Files
rune/tests/test_audit_ledger_switch.py
T
Nick 70e9a8849a
local-review.yml (push) Invalid workflow file
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 17s
CI Pipeline / rust-surface (push) Successful in 4m10s
CI Pipeline / canary (push) Failing after 1m0s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 6s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / type-check (push) Failing after 34s
CI Pipeline / unit-tests (push) Failing after 8m19s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 10s
feat(phase-g): audit_ledger switched to the Rust chain — #2449 batch A (contract BUILDER-2026-10-08T14:06:45Z-f1eada)
- The defect: SECRET_KEY defaulted to rune-governed-adaptation-2024 while the
  LIVE 62-entry chain verifies under the DEPLOYED vintage
  rune-drift-integrity-2024 (proved live: deployed verifies 62/valid, the old
  default saw 0 entries) — a src/rune append would have corrupted the chain
  under the authority key. Key ADOPTS the authority (RECONCILE-DON'T-CLOBBER).
- verify_chain + _compute_hash delegate to the ep seam (no silent fallback —
  a missing cdylib fails loudly). Rust verify on the live ledger: 62/valid.
- tests/test_audit_ledger_switch.py 5/5: key adoption, Rust-vs-Python HMAC
  parity, append→verify round-trip, tamper detection through Rust, live
  ledger under the authority key.
- Test-isolation law: the new file lazy-imports audit_ledger (top-level
  import at collection cached LEDGER_FILE under the wrong env and broke the
  shims battery's env pinning). Both orders green; family 12/12; ratchet PASS.
2026-10-08 15:18:34 +01:00

120 lines
4.6 KiB
Python

"""test_audit_ledger_switch.py — #2449 batch A: the audit_ledger switch.
Pins: the key adopts the live-chain authority (rune-drift-integrity-2024);
the hash chain is RUST (ep seam) with exact parity against the Python HMAC
vintage; append→verify round-trips through the switched module; the live
ledger verifies 62/valid under the authority key.
"""
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(ROOT / "src/rust/evidence_provenance"))
import ep_loader # noqa: E402
def _al():
"""Lazy import (NEVER top-level): the shims battery pins env in its
fixture — a top-level `from rune import audit_ledger` at COLLECTION
caches LEDGER_FILE under the wrong env and breaks it (order-fragility).
Import inside each test so resolution happens under the live env."""
sys.modules.pop("rune.audit_ledger", None)
from rune import audit_ledger as al # noqa: E402
return al
AUTHORITY_KEY = "rune-drift-integrity-2024"
class TestAuditLedgerSwitch(unittest.TestCase):
@classmethod
def tearDownClass(cls):
# Test-isolation law: the shims battery imports audit_ledger under
# ITS pinned env — purge the cache (sys.modules AND the package
# attribute, which `from rune import X` prefers) so it re-resolves
# LEDGER_FILE under that env.
import rune
for name in ("rune.audit_ledger", "memory_env"):
sys.modules.pop(name, None)
if hasattr(rune, "audit_ledger"):
delattr(rune, "audit_ledger")
if hasattr(rune, "memory_env"):
delattr(rune, "memory_env")
def test_key_adopts_live_chain_authority(self):
al = _al()
self.assertEqual(al.SECRET_KEY, AUTHORITY_KEY, "the governed-adaptation default was the vintage-split defect")
def test_rust_hash_parity_with_python_vintage(self):
"""The ep seam's compute_hash must equal the Python HMAC vintage
(prev_hash + json.dumps(entry, sort_keys=True) under the key)."""
import hashlib
import hmac
import json
al = _al()
entry = {"type": "promotion", "id": 7, "details": {"from": "a", "to": "b"}}
payload = json.dumps(entry, sort_keys=True).encode()
expected = hmac.new(AUTHORITY_KEY.encode(), ("genesis" + payload.decode()).encode(), hashlib.sha256).hexdigest()
self.assertEqual(al._compute_hash("genesis", entry), expected)
self.assertEqual(ep_loader.compute_hash("genesis", payload.decode(), AUTHORITY_KEY), expected)
def test_append_verify_round_trip(self):
import json
import tempfile
al = _al()
with tempfile.TemporaryDirectory() as td:
ledger = str(Path(td) / "ledger.jsonl")
orig = al.LEDGER_FILE
al.LEDGER_FILE = ledger
try:
r1 = al.append_entry("promotion", 1, {"from": "PROVISIONAL", "to": "VALIDATED"})
self.assertTrue(r1.get("ok", True) or "hash" in json.dumps(r1))
r2 = al.append_entry("promotion", 2, {"from": "VALIDATED", "to": "LOCKED"})
self.assertIsNotNone(r2)
v = al.verify_chain()
self.assertTrue(v["valid"], v)
self.assertEqual(v["entries"], 2)
self.assertEqual(v.get("reason"), "chain intact")
finally:
al.LEDGER_FILE = orig
def test_tamper_detection_through_rust(self):
import json
import tempfile
al = _al()
with tempfile.TemporaryDirectory() as td:
ledger = Path(td) / "ledger.jsonl"
orig = al.LEDGER_FILE
al.LEDGER_FILE = str(ledger)
try:
al.append_entry("promotion", 1, {"x": 1})
lines = ledger.read_text().splitlines()
entry = json.loads(lines[0])
entry["details"] = {"x": 999} # tamper
ledger.write_text(json.dumps(entry) + "\n")
v = al.verify_chain()
self.assertFalse(v["valid"], "a tampered entry must fail verification")
finally:
al.LEDGER_FILE = orig
def test_live_ledger_verifies_under_authority_key(self):
live = Path.home() / ".config/opencode/memory/promotion_ledger.jsonl"
if not live.exists():
self.skipTest("no live ledger on this host")
r = ep_loader.verify_chain(str(live), AUTHORITY_KEY)
self.assertTrue(r["valid"])
self.assertGreaterEqual(r["entries"], 20)
if __name__ == "__main__":
unittest.main()