custody-describe apply: silent, results to a 0600 receipt
The warden admin wrapper refuses any output; the first founder run was refused (nothing written, all entries still drafts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 327203@bnt-lap001 Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
This commit is contained in:
parent
6f529413c8
commit
7d54d049c1
3 changed files with 33 additions and 13 deletions
|
|
@ -12,7 +12,7 @@ because a confidently wrong `used_by` is worse than an empty one.
|
|||
|
||||
`apply` writes custom_metadata only (`bao kv metadata patch`), for entries
|
||||
marked `review: accepted` with all five fields filled. It never reads or writes
|
||||
a value, prints nothing but paths and booleans, and runs under the founder's
|
||||
a value, prints nothing (results go to a 0600 receipt), and runs under the founder's
|
||||
admin session (warden access openbao-platform-admin-login --exec), since
|
||||
ops-mason-survey cannot write metadata.
|
||||
"""
|
||||
|
|
@ -121,20 +121,31 @@ def check(doc: dict) -> int:
|
|||
return 0 if bad == 0 else 1
|
||||
|
||||
|
||||
def apply(doc: dict) -> int:
|
||||
failed = 0
|
||||
RECEIPT = os.path.join(HOME, ".local/state/railiance/receipts/custody-describe.json")
|
||||
|
||||
|
||||
def apply(doc: dict, receipt: str = RECEIPT) -> int:
|
||||
"""Silent: the warden wrapper refuses any output, so results go to a 0600 receipt."""
|
||||
import json
|
||||
results = {}
|
||||
for path, e in doc.items():
|
||||
if e.get("review") != "accepted" or any(not e.get(k) for k in REQUIRED):
|
||||
print(f"skip {path}")
|
||||
results[path] = "skipped"
|
||||
continue
|
||||
mount, rest = path.split("/", 1)
|
||||
args = ["bao", "kv", "metadata", "patch", f"-mount={mount}"]
|
||||
args += [f"-custom-metadata={k}={_clip(e[k])}" for k in REQUIRED]
|
||||
args.append(rest)
|
||||
ok = subprocess.run(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
|
||||
failed += not ok
|
||||
print(f"{'patched' if ok else 'FAILED '} {path}")
|
||||
return 1 if failed else 0
|
||||
results[path] = "patched" if ok else "failed"
|
||||
os.makedirs(os.path.dirname(receipt), mode=0o700, exist_ok=True)
|
||||
old_umask = os.umask(0o077)
|
||||
try:
|
||||
with open(receipt, "w") as f:
|
||||
json.dump(results, f, indent=1, sort_keys=True)
|
||||
finally:
|
||||
os.umask(old_umask)
|
||||
return 1 if "failed" in results.values() else 0
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
|
|
|
|||
|
|
@ -9,14 +9,19 @@ _spec.loader.exec_module(cd)
|
|||
FULL = dict(description="d", owner="o", used_by="u", rotation="r", on_loss="l")
|
||||
|
||||
|
||||
def test_apply_patches_only_accepted_complete_entries_and_only_metadata():
|
||||
def test_apply_patches_only_accepted_complete_entries_and_only_metadata(tmp_path, capsys):
|
||||
doc = {
|
||||
"platform/workloads/a/b": {"review": "accepted", **FULL},
|
||||
"platform/workloads/c/d": {"review": "draft", **FULL},
|
||||
"operators/e": {"review": "accepted", **dict(FULL, used_by="")},
|
||||
}
|
||||
with patch.object(cd.subprocess, "run", return_value=MagicMock(returncode=0)) as run:
|
||||
assert cd.apply(doc) == 0
|
||||
assert cd.apply(doc, receipt=str(tmp_path / 'r.json')) == 0
|
||||
assert capsys.readouterr() == ('', '')
|
||||
import json, os, stat
|
||||
r = tmp_path / 'r.json'
|
||||
assert json.load(open(r)) == {'platform/workloads/a/b': 'patched', 'platform/workloads/c/d': 'skipped', 'operators/e': 'skipped'}
|
||||
assert stat.S_IMODE(os.stat(r).st_mode) == 0o600
|
||||
assert run.call_count == 1
|
||||
args = run.call_args.args[0]
|
||||
assert args[:5] == ["bao", "kv", "metadata", "patch", "-mount=platform"]
|
||||
|
|
@ -25,10 +30,11 @@ def test_apply_patches_only_accepted_complete_entries_and_only_metadata():
|
|||
assert run.call_args.kwargs["stdout"] is cd.subprocess.DEVNULL and run.call_args.kwargs["stderr"] is cd.subprocess.DEVNULL
|
||||
|
||||
|
||||
def test_apply_reports_failure_without_output():
|
||||
def test_apply_reports_failure_without_output(tmp_path, capsys):
|
||||
doc = {"platform/workloads/a/b": {"review": "accepted", **FULL}}
|
||||
with patch.object(cd.subprocess, "run", return_value=MagicMock(returncode=2)):
|
||||
assert cd.apply(doc) == 1
|
||||
assert cd.apply(doc, receipt=str(tmp_path / 'r.json')) == 1
|
||||
assert capsys.readouterr() == ('', '')
|
||||
|
||||
|
||||
def test_check_refuses_drafts_missing_and_overlong_fields():
|
||||
|
|
|
|||
|
|
@ -115,9 +115,12 @@ have gaps left empty on purpose (nextcloud x2, keycape-factor-issuer,
|
|||
grafana-admin, smtp, and four `used_by`). Every entry is `review: draft`.
|
||||
`apply` writes custom_metadata only, for `review: accepted` entries, silently
|
||||
(`tests/test_custody_describe.py`, suite 157 passed). Founder run, after
|
||||
review: `warden access openbao-platform-admin-login --exec -- python3
|
||||
review: `warden access openbao-platform-admin-login --exec -- sh -c 'python3
|
||||
/home/worsch/ops-mason/scripts/custody-describe.py apply
|
||||
/home/worsch/ops-mason/manifests/custody-descriptions.yaml`.
|
||||
/home/worsch/ops-mason/manifests/custody-descriptions.yaml >/dev/null 2>&1'`,
|
||||
then read `~/.local/state/railiance/receipts/custody-describe.json`.
|
||||
(First attempt 2026-10-09 refused by the wrapper because apply printed status
|
||||
lines; nothing written, all entries were still drafts. apply is now silent.)
|
||||
|
||||
## Resolve the rest with their owners
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue