Evidence export of closed runs and rtut seal (RBT-WP-0009-T04)

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

Assistant: claude-code
Assistant-Model: sonnet
Assistant-Process: 295952@bnt-lap001
Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
This commit is contained in:
tegwick 2026-09-29 21:35:03 +02:00
parent e021fd979f
commit 6d70f4d97d
12 changed files with 149 additions and 19 deletions

View file

@ -157,3 +157,48 @@ def test_the_record_file_is_read_only_after_closing_and_tampering_is_called_out(
data = json.loads(r.path.read_text()); data["operator"] = "forged"; r.path.write_text(json.dumps(data))
body = req(srv, "GET", base)[2]
assert "changed outside the app after it was sealed" in body and "no longer counts towards maturity" in body
# ---- evidence export ------------------------------------------------------------------------------------------------------
def raw(s, path):
c = http.client.HTTPConnection("127.0.0.1", s.server_address[1])
c.request("GET", path, None, {"Host": "127.0.0.1"})
r = c.getresponse()
return r.status, {k.lower(): v for k, v in r.getheaders()}, r.read()
@pytest.mark.parametrize("pack", ["rtut.showcase-lighthouse", "rtut.showcase-lighthouse-v2"])
def test_a_closed_run_record_can_be_downloaded_and_its_seal_checked_elsewhere(srv, pack, tmp_path, capsys):
from rtut.__main__ import main
base, _ = start(srv, pack)
st, _, body = raw(srv, f"{base}/record.json")
assert st == 409 and b"once the run is closed" in body # an open run has no final record
assert "Download the run record" not in req(srv, "GET", base)[2]
post(srv, f"{base}/finalize", outcome="abandoned", note="for the record")
st, hdr, body = raw(srv, f"{base}/record.json")
rid = base.rsplit("/", 1)[1]
assert st == 200 and hdr["content-type"] == "application/json" and hdr["x-rtut-seal"] == "sealed"
assert hdr["content-disposition"] == f'attachment; filename="run-{rid}.json"' and hdr["x-content-type-options"] == "nosniff"
assert "sandbox" in hdr["content-security-policy"]
assert body == run_of(srv, base).path.read_bytes() # exactly as stored
record = json.loads(body)
assert record["run_id"] == rid and record["outcome"] == "abandoned" and R1.record_seal_state(record) == "sealed"
assert f"<a href='{base}/record.json'>Download the run record (JSON)</a>" in req(srv, "GET", base)[2]
f = tmp_path / "exported.json"; f.write_bytes(body)
assert main(["seal", str(f)]) == 0 and capsys.readouterr().out.strip() == "sealed" # anyone can verify it
record["operator"] = "forged"; f.write_text(json.dumps(record))
assert main(["seal", str(f)]) == 1 and capsys.readouterr().out.strip() == "broken"
def test_a_tampered_record_is_still_downloadable_but_flagged_in_the_header(srv):
base, _ = start(srv, "rtut.showcase-lighthouse-v2")
post(srv, f"{base}/finalize", outcome="abandoned")
r = run_of(srv, base); r.path.chmod(0o644)
data = json.loads(r.path.read_text()); data["operator"] = "forged"; r.path.write_text(json.dumps(data))
st, hdr, _ = raw(srv, f"{base}/record.json")
assert st == 200 and hdr["x-rtut-seal"] == "broken" # evidence, with the warning attached
def test_unknown_run_record_is_not_found(srv):
assert raw(srv, "/run/0/nope/record.json")[0] == 404