railiance-platform/tests/test_rpf_wp_0015_e2_receipt.py
codex dad91e8c44 Route the sender lane's cluster writes through AUDIT_KUBECONFIG too.
Round-10 review (railiance-platform) found that ContainedOperator inherited
an ssh-only kubectl, so an E2 would write OpenBao and then fail its sync,
restart and rollback. Also: a bad AUDIT_KUBECONFIG now leaves window-error
evidence, and the receipt script validates bodies and lets a later
request-changes withdraw an approval.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 236506@bnt-lap001
Assistant-Session: 09087018-91e1-48c5-ab2f-acfbb62c92e4
2026-11-03 15:09:59 +01:00

92 lines
3.7 KiB
Python

"""The E2 receipt generator emits a receipt the sender lane accepts as T03."""
import importlib.util
import json
import subprocess
import sys
from datetime import UTC, datetime
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def lane():
sys.path.insert(0, str(ROOT / "scripts"))
spec = importlib.util.spec_from_file_location("lane_e2", ROOT / "scripts/audit_core_synthetic_sender_lane.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def generator():
spec = importlib.util.spec_from_file_location("e2_receipt", ROOT / "scripts/rpf-wp-0015-e2-receipt.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def test_receipt_is_accepted_by_the_lane_as_t03(tmp_path, monkeypatch, capsys):
gen = generator()
owners = {o: {"acknowledged": True, "message_id": f"{o}-msg"} for o in gen.OWNERS}
monkeypatch.setattr(gen, "approvals", lambda review, contract, base: ("d" * 64, owners))
review = gen.review_module()
pins = review.load_contract()["artifact_sha256"]
monkeypatch.setattr(review, "file_sha256", lambda path: pins[str(path.relative_to(ROOT))])
monkeypatch.setattr(gen, "review_module", lambda: review)
out = tmp_path / "approval.json"
gen.main(["x", str(out)])
printed = json.loads(capsys.readouterr().out)
m = lane()
approval, spec = m.load_receipt(out, datetime.now(UTC), require_open_window=True)
assert approval["task_id"] == "RAILIANCE-WP-0024-T03"
assert printed["confirm"] == m.confirm_token(approval)
def test_refuses_to_overwrite(tmp_path):
out = tmp_path / "approval.json"
out.write_text("{}")
result = subprocess.run([sys.executable, str(ROOT / "scripts/rpf-wp-0015-e2-receipt.py"), str(out)],
capture_output=True, text=True)
assert result.returncode != 0 and out.read_text() == "{}"
def test_later_request_changes_withdraws_an_approval():
gen = generator()
review = gen.review_module()
contract = review.load_contract()
digest = review.contract_digest(contract)
def message(decision, created, mid, sender="audit-core", owner="audit-core"):
body = review.build_receipt(contract, owner, decision, "claude/x",
verification={"passed": True, "checks": []},
note="needs a fix in file.py:1" if decision == "request-changes" else None)
body["created_at"] = created
return {"id": mid, "from_agent": sender, "subject": review.receipt_subject(body), "body": json.dumps(body)}
class Resp:
def __init__(self, data): self.data = data
def __enter__(self): return self
def __exit__(self, *a): return False
def read(self): return json.dumps(self.data).encode()
def fetch(msgs):
import unittest.mock as um
with um.patch.object(gen.urllib.request, "urlopen", return_value=Resp(msgs)):
with um.patch.object(gen.json, "load", lambda r: msgs):
return gen.approvals(review, contract, "http://hub")
ok = [message("approve", "2026-11-03T10:00:00Z", f"{o}-1", o, o) for o in gen.OWNERS]
assert fetch(ok)[0] == digest
withdrawn = ok + [message("request-changes", "2026-11-03T11:00:00Z", "ac-2")]
try:
fetch(withdrawn)
except SystemExit as exc:
assert "audit-core" in str(exc)
else:
raise AssertionError("withdrawn approval was accepted")
forged = [message("approve", "2026-11-03T10:00:00Z", "f", "someone-else", "audit-core")] + ok[1:]
try:
fetch(forged)
except SystemExit:
pass
else:
raise AssertionError("approval from the wrong sender was accepted")