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):
|
for i, line in enumerate(lines):
|
||||||
stripped = line.strip()
|
stripped = line.strip()
|
||||||
if stripped.startswith("- path_regex:"):
|
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
|
in_target_rule = path_regex_pattern in line
|
||||||
age_block_start = None
|
age_block_start = None
|
||||||
age_block_last_idx = 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
|
continue
|
||||||
if age_block_start is None:
|
if age_block_start is None:
|
||||||
continue
|
continue
|
||||||
# Inside the age block; track the last age1... line.
|
|
||||||
if "age1" in stripped:
|
if "age1" in stripped:
|
||||||
if pubkey in line:
|
if pubkey in line:
|
||||||
return True # already a recipient
|
return True # already a recipient
|
||||||
age_block_last_idx = i
|
age_block_last_idx = i
|
||||||
elif stripped == "" or stripped.startswith("#"):
|
elif stripped == "" or stripped.startswith("#"):
|
||||||
continue # blank / comment inside the block
|
continue
|
||||||
else:
|
else:
|
||||||
break # next key, age block ended
|
break # next key, age block ended
|
||||||
if age_block_last_idx is None:
|
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():
|
if not sops_path.exists():
|
||||||
return False
|
return False
|
||||||
lines = sops_path.read_text().splitlines(keepends=True)
|
lines = sops_path.read_text().splitlines(keepends=True)
|
||||||
in_target_rule = False
|
|
||||||
age_block_start = None
|
def find_target_age_lines() -> tuple[list[int], bool]:
|
||||||
target_idx = None
|
"""Scan and return (indices_of_age1_lines_in_target_rule, found_rule)."""
|
||||||
for i, line in enumerate(lines):
|
in_target = False
|
||||||
stripped = line.strip()
|
age_block_start = None
|
||||||
if stripped.startswith("- path_regex:"):
|
age_idxs: list[int] = []
|
||||||
in_target_rule = path_regex_pattern in line
|
for i, line in enumerate(lines):
|
||||||
age_block_start = None
|
stripped = line.strip()
|
||||||
target_idx = None
|
if stripped.startswith("- path_regex:"):
|
||||||
continue
|
if in_target and age_idxs:
|
||||||
if not in_target_rule:
|
return age_idxs, True
|
||||||
continue
|
in_target = path_regex_pattern in line
|
||||||
if "age: >-" in line:
|
age_block_start = None
|
||||||
age_block_start = i
|
age_idxs = []
|
||||||
continue
|
continue
|
||||||
if age_block_start is None:
|
if not in_target:
|
||||||
continue
|
continue
|
||||||
if "age1" in stripped:
|
if "age: >-" in line:
|
||||||
if pubkey in line:
|
age_block_start = i
|
||||||
target_idx = 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
|
break
|
||||||
elif stripped == "" or stripped.startswith("#"):
|
return age_idxs, in_target
|
||||||
continue
|
|
||||||
else:
|
age_idxs, found = find_target_age_lines()
|
||||||
break # next key, age block ended
|
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:
|
if target_idx is None:
|
||||||
return True # nothing to remove — already absent
|
return True # already absent
|
||||||
del lines[target_idx]
|
del lines[target_idx]
|
||||||
# Fix a now-dangling trailing comma on the new last age line if any.
|
# After deletion, fix trailing comma on the new last age line.
|
||||||
# Find the new last age line in this rule's age block.
|
new_age_idxs, _ = find_target_age_lines()
|
||||||
in_target_rule = False
|
if new_age_idxs:
|
||||||
age_block_start = None
|
last_age_idx = new_age_idxs[-1]
|
||||||
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:
|
|
||||||
last_line = lines[last_age_idx]
|
last_line = lines[last_age_idx]
|
||||||
if last_line.rstrip().endswith(","):
|
if last_line.rstrip().endswith(","):
|
||||||
lines[last_age_idx] = last_line.rstrip().rstrip(",") + "\n"
|
lines[last_age_idx] = last_line.rstrip().rstrip(",") + "\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user