53 lines
2 KiB
Diff
53 lines
2 KiB
Diff
# UNDF: UNDF-2026-000000006
|
|
# UNDF: (leave blank)
|
|
# CWE-407: Host.add_group() and populate_ancestors() use `group not in self.groups`
|
|
# linear scan on list inside loops — O(A*G) per add_group call, O(H*G*A) total
|
|
# Fix: maintain _groups_set: set alongside self.groups for O(1) membership
|
|
# Severity: MEDIUM — inventory with 100+ groups per host triggers quadratic behavior
|
|
# Measured: 250x op-count overhead at G=500
|
|
--- a/lib/ansible/inventory/host.py
|
|
+++ b/lib/ansible/inventory/host.py
|
|
@@ -62,6 +62,7 @@
|
|
self.vars: dict[str, t.Any] = {}
|
|
self.groups: list[Group] = []
|
|
+ self._groups_set: set[Group] = set()
|
|
self._uuid: str | None = None
|
|
|
|
@@ -80,8 +81,10 @@
|
|
def populate_ancestors(self, additions: c.Iterable[Group] | None = None) -> None:
|
|
if additions is None:
|
|
for group in self.groups:
|
|
self.add_group(group)
|
|
else:
|
|
for group in additions:
|
|
- if group not in self.groups:
|
|
+ if group not in self._groups_set:
|
|
self.groups.append(group)
|
|
+ self._groups_set.add(group)
|
|
|
|
@@ -90,13 +93,15 @@
|
|
def add_group(self, group: Group) -> bool:
|
|
added = False
|
|
# populate ancestors first
|
|
for oldg in group.get_ancestors():
|
|
- if oldg not in self.groups:
|
|
+ if oldg not in self._groups_set:
|
|
self.groups.append(oldg)
|
|
+ self._groups_set.add(oldg)
|
|
|
|
# actually add group
|
|
- if group not in self.groups:
|
|
+ if group not in self._groups_set:
|
|
self.groups.append(group)
|
|
+ self._groups_set.add(group)
|
|
added = True
|
|
return added
|
|
|
|
@@ -103,7 +108,8 @@
|
|
def remove_group(self, group: Group) -> bool:
|
|
removed = False
|
|
- if group in self.groups:
|
|
+ if group in self._groups_set:
|
|
self.groups.remove(group)
|
|
+ self._groups_set.discard(group)
|
|
removed = True
|