homelab: stop sops-policy scan resetting state on the next rule
Critical bug — the loop reset age_block_last_idx unconditionally on every '- path_regex:' line. So after finding the target rule's age block, encountering the NEXT rule wiped the result and the function returned False. _grant_shared_secrets / _revoke_shared_secrets both silently no-op'd because of this. Fix: break out of the scan once we've collected the target rule's data. Refactored the remove helper to share a find_target_age_lines inner so the dangling-trailing-comma fixup uses the same logic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
95
bin/homelab
95
bin/homelab
@@ -141,6 +141,10 @@ def _add_recipient_to_sops_policy(sops_path: Path, path_regex_pattern: str, pubk
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("- path_regex:"):
|
||||
# If we've already collected what we need from the target rule,
|
||||
# stop — don't let the next rule wipe age_block_last_idx.
|
||||
if in_target_rule and age_block_last_idx is not None:
|
||||
break
|
||||
in_target_rule = path_regex_pattern in line
|
||||
age_block_start = None
|
||||
age_block_last_idx = None
|
||||
@@ -152,13 +156,12 @@ def _add_recipient_to_sops_policy(sops_path: Path, path_regex_pattern: str, pubk
|
||||
continue
|
||||
if age_block_start is None:
|
||||
continue
|
||||
# Inside the age block; track the last age1... line.
|
||||
if "age1" in stripped:
|
||||
if pubkey in line:
|
||||
return True # already a recipient
|
||||
age_block_last_idx = i
|
||||
elif stripped == "" or stripped.startswith("#"):
|
||||
continue # blank / comment inside the block
|
||||
continue
|
||||
else:
|
||||
break # next key, age block ended
|
||||
if age_block_last_idx is None:
|
||||
@@ -204,59 +207,47 @@ def _remove_recipient_from_sops_policy(sops_path: Path, path_regex_pattern: str,
|
||||
if not sops_path.exists():
|
||||
return False
|
||||
lines = sops_path.read_text().splitlines(keepends=True)
|
||||
in_target_rule = False
|
||||
age_block_start = None
|
||||
target_idx = None
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("- path_regex:"):
|
||||
in_target_rule = path_regex_pattern in line
|
||||
age_block_start = None
|
||||
target_idx = None
|
||||
continue
|
||||
if not in_target_rule:
|
||||
continue
|
||||
if "age: >-" in line:
|
||||
age_block_start = i
|
||||
continue
|
||||
if age_block_start is None:
|
||||
continue
|
||||
if "age1" in stripped:
|
||||
if pubkey in line:
|
||||
target_idx = i
|
||||
|
||||
def find_target_age_lines() -> tuple[list[int], bool]:
|
||||
"""Scan and return (indices_of_age1_lines_in_target_rule, found_rule)."""
|
||||
in_target = False
|
||||
age_block_start = None
|
||||
age_idxs: list[int] = []
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("- path_regex:"):
|
||||
if in_target and age_idxs:
|
||||
return age_idxs, True
|
||||
in_target = path_regex_pattern in line
|
||||
age_block_start = None
|
||||
age_idxs = []
|
||||
continue
|
||||
if not in_target:
|
||||
continue
|
||||
if "age: >-" in line:
|
||||
age_block_start = i
|
||||
continue
|
||||
if age_block_start is None:
|
||||
continue
|
||||
if "age1" in stripped:
|
||||
age_idxs.append(i)
|
||||
elif stripped == "" or stripped.startswith("#"):
|
||||
continue
|
||||
else:
|
||||
break
|
||||
elif stripped == "" or stripped.startswith("#"):
|
||||
continue
|
||||
else:
|
||||
break # next key, age block ended
|
||||
return age_idxs, in_target
|
||||
|
||||
age_idxs, found = find_target_age_lines()
|
||||
if not found:
|
||||
return False
|
||||
target_idx = next((i for i in age_idxs if pubkey in lines[i]), None)
|
||||
if target_idx is None:
|
||||
return True # nothing to remove — already absent
|
||||
return True # already absent
|
||||
del lines[target_idx]
|
||||
# Fix a now-dangling trailing comma on the new last age line if any.
|
||||
# Find the new last age line in this rule's age block.
|
||||
in_target_rule = False
|
||||
age_block_start = None
|
||||
last_age_idx = None
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("- path_regex:"):
|
||||
in_target_rule = path_regex_pattern in line
|
||||
age_block_start = None
|
||||
continue
|
||||
if not in_target_rule:
|
||||
continue
|
||||
if "age: >-" in line:
|
||||
age_block_start = i
|
||||
continue
|
||||
if age_block_start is None:
|
||||
continue
|
||||
if "age1" in stripped:
|
||||
last_age_idx = i
|
||||
elif stripped == "" or stripped.startswith("#"):
|
||||
continue
|
||||
else:
|
||||
break
|
||||
if last_age_idx is not None:
|
||||
# After deletion, fix trailing comma on the new last age line.
|
||||
new_age_idxs, _ = find_target_age_lines()
|
||||
if new_age_idxs:
|
||||
last_age_idx = new_age_idxs[-1]
|
||||
last_line = lines[last_age_idx]
|
||||
if last_line.rstrip().endswith(","):
|
||||
lines[last_age_idx] = last_line.rstrip().rstrip(",") + "\n"
|
||||
|
||||
Reference in New Issue
Block a user