KB-27A2

FIX7 P0 Hardening Packet — hardened_bad_input_probes.py

7 min read Revision 1

#!/usr/bin/env python3 """Adversarial probes for the HARDENED rollback gate (T2-REC-ROLLBACK-HARDENING-1).

Base data = the real, frozen T1 staging rollback evidence in valid_evidence_recheck.json (copied byte-for-byte from fix7-p0-dryrun-and-execution-readiness-packet-2026-06-11/rollback-recovery-proof.json).

Each probe injects exactly one defect into a deepcopy of that evidence and asserts the hardened gate (hardened_dryrun_validator.check_rollback_proof) FAILS CLOSED with the expected code prefix, emitting no PASS/digest/cert/seal. A positive control asserts the unmodified evidence PASSES.

Required probe classes (Workstream B): 1 after_apply_hash == before_hash while claiming mutation 2 missing after_apply_hash 3 missing before_hash 4 missing after_rollback_hash 5 production rollback claimed despite no production mutation 6 rollback proof claimed but no rollback step 7 valid existing T1 rollback evidence still passes (control)

Exit 0 => control passes AND every probe fails closed (any_fail_open == False). Exit 1 => any probe failed open, or the control broke. Writes hardening_probe_results.json (deterministic). """ import copy import json import os import sys

import hardened_dryrun_validator as V

HERE = os.path.dirname(os.path.abspath(file))

def load_rb(): with open(os.path.join(HERE, "valid_evidence_recheck.json"), "r", encoding="utf-8") as fh: return json.load(fh)["rollback_evidence"]

def entry_by_id(rb, eid): for e in rb["entries"]: if e.get("id") == eid: return e raise KeyError(eid)

forbidden leak tokens: a fail-closed probe must NOT emit any of these

LEAK_TOKENS = ("PASS", "DIGEST", "CERT", "SEAL", "AUTHORIZED", "PROVEN_OK")

def expect_fail(name, rb, expected_prefixes): fails = V.check_rollback_proof(rb) closed = bool(fails) and any( any(f.startswith(p) for p in expected_prefixes) for f in fails ) # fail-closed output must carry no PASS/cert/seal-like official token leaked = [f for f in fails if any(t in f.upper() for t in LEAK_TOKENS)] ok = closed and not leaked print("[%s] %s -> %s%s" % ( "FAIL-CLOSED" if ok else "FAIL-OPEN", name, "; ".join(fails) if fails else "(no fail codes!)", "" if not leaked else " LEAK:" + ";".join(leaked))) return {"probe": name, "fail_closed": ok, "codes": fails, "expected_prefix": list(expected_prefixes), "leak": leaked}

def main(): base = load_rb() results = []

# ---- positive control: unmodified real evidence passes ----
control_fails = V.check_rollback_proof(copy.deepcopy(base))
controls_pass = not control_fails
print("[CONTROL] real T1 rollback evidence passes hardened gate: %s%s"
      % ("YES" if controls_pass else "NO",
         "" if controls_pass else " -> " + "; ".join(control_fails)))

# 1 after_apply_hash == before_hash while claiming mutation
d = copy.deepcopy(base)
e = entry_by_id(d, "RB-3")
e["after_apply_hash"] = e["before_hash"]      # apply changed nothing
results.append(expect_fail("P1 apply==before (fabricated, no real mutation)",
                           d, ["ROLLBACK_APPLY_DID_NOT_MUTATE"]))

# 2 missing after_apply_hash
d = copy.deepcopy(base)
entry_by_id(d, "RB-3")["after_apply_hash"] = ""
results.append(expect_fail("P2 missing after_apply_hash", d,
                           ["ROLLBACK_ENTRY_MISSING_HASH:RB-3:after_apply_hash"]))

# 3 missing before_hash
d = copy.deepcopy(base)
entry_by_id(d, "RB-3")["before_hash"] = ""
results.append(expect_fail("P3 missing before_hash", d,
                           ["ROLLBACK_ENTRY_MISSING_HASH:RB-3:before_hash"]))

# 4 missing after_rollback_hash
d = copy.deepcopy(base)
entry_by_id(d, "RB-3")["after_rollback_hash"] = ""
results.append(expect_fail("P4 missing after_rollback_hash", d,
                           ["ROLLBACK_ENTRY_MISSING_HASH:RB-3:after_rollback_hash"]))

# 5 production rollback claimed despite no production mutation
d = copy.deepcopy(base)
d["production_rollback_status"] = "PROVEN"
results.append(expect_fail("P5 production rollback claimed", d,
                           ["PRODUCTION_ROLLBACK_CLAIMED"]))

# 6 rollback proof claimed but no rollback step
d = copy.deepcopy(base)
d["staging_mutation_occurred"] = False
d["entries"] = []
results.append(expect_fail("P6 PROVEN claimed but no rollback step/mutation", d,
                           ["ROLLBACK_PROVEN_BUT_NO_MUTATION", "ROLLBACK_PROVEN_NO_ENTRIES"]))

# 7 valid existing T1 rollback evidence still passes (control re-asserted as a probe)
d = copy.deepcopy(base)
p7_fails = V.check_rollback_proof(d)
p7_ok = not p7_fails
print("[%s] P7 valid T1 evidence still passes -> %s"
      % ("FAIL-CLOSED" if p7_ok else "FAIL-OPEN",
         "(clean PASS)" if p7_ok else "; ".join(p7_fails)))
results.append({"probe": "P7 valid T1 evidence still passes",
                "fail_closed": p7_ok, "codes": p7_fails,
                "expected_prefix": ["(none: must pass)"], "leak": []})

total = len(results)
passed = sum(1 for r in results if r["fail_closed"])
any_fail_open = (passed != total) or (not controls_pass)

out = {
    "doc": "fix7-p0-rollback-validator-hardening-probe-results",
    "date": "2026-06-11",
    "hardened_rule": "T2-REC-ROLLBACK-HARDENING-1: after_apply_hash != before_hash required on every claimed staging mutation",
    "base_evidence": "valid_evidence_recheck.json (real frozen T1 staging rollback evidence)",
    "control_pass": controls_pass,
    "total": total,
    "fail_closed": passed,
    "any_fail_open": any_fail_open,
    "results": results,
    "new_guard_codes": ["ROLLBACK_APPLY_DID_NOT_MUTATE", "ROLLBACK_NOT_RESTORED_TO_PIN"],
    "superset_note": "hardened validator removes no original gate; it only adds the rollback-mutation guard, so all original defect classes remain caught.",
}
with open(os.path.join(HERE, "hardening_probe_results.json"), "w", encoding="utf-8") as fh:
    json.dump(out, fh, indent=2, sort_keys=True)
    fh.write("\n")

print("HARDENING_PROBES: %d/%d fail-closed; control_pass=%s; any_fail_open=%s"
      % (passed, total, controls_pass, any_fail_open))
sys.exit(1 if any_fail_open else 0)

if name == "main": main()

Back to Knowledge Hub knowledge/dev/reports/architecture/fix7-p0-rollback-validator-hardening-packet-2026-06-11/hardened_bad_input_probes.py