java-topology/defects/pyramid/patch/pyramid-0003-actions-remaining-set.patch

31 lines
1.5 KiB
Diff

# UNDF: UNDF-2026-000000233
Fixes pyramid-0003: config/actions.py resolveConflicts() — list.remove() inside sorted output loop.
--- a/src/pyramid/config/actions.py
+++ b/src/pyramid/config/actions.py
@@ DEFECT pyramid-0003: resolveConflicts() line 490
# In class _ConflictState.__init__():
- self.remaining_actions = [] # list — O(n) remove — CWE-407
+ self.remaining_actions = [] # kept as list for extend/iteration
+ self.remaining_actions_set = set() # FIX pyramid-0003: O(1) removal
# In normalize_actions / state initialization:
state.remaining_actions.extend(normalize_actions(actions))
+ state.remaining_actions_set.update(id(a) for a in state.remaining_actions)
# In resolveConflicts() yield loop:
for i, action in sorted(output, key=operator.itemgetter(0)):
state.min_order = action['order']
state.start = i + 1
- state.remaining_actions.remove(action) # O(n) linear scan — CWE-407
+ state.remaining_actions_set.discard(id(action)) # O(1) — fixed
+ # remaining_actions list lazily filtered when iterated (or rebuild on demand)
state.resolved_ainfos[action['discriminator']] = (i, action)
yield action
# NOTE: actions are dicts (unhashable), so we track by id(). The list is
# kept for ordered iteration in subsequent passes; rebuild by filtering with
# the set when needed: [a for a in state.remaining_actions if id(a) in set].
# This converts the O(N²) startup cost to O(N).