Files
rustfs/scripts/run_scanner_heal_scoped_ack_evidence.py
T
houseme 3afb389247 test(scanner): harden scoped ack evidence proof (#7602)
Require Scanner/Heal G03 scoped ACK evidence fields to carry their own measured provenance and concrete ACK, capability, and mixed-peer observations before release-bundle gate verification.

Co-authored-by: zhi22915 <qiuzgang@gmail.com>
2026-09-10 01:05:00 +08:00

324 lines
13 KiB
Python
Executable File

#!/usr/bin/env python3
"""Assemble measured Scanner/Heal G03 scoped ACK release evidence.
This producer consumes one operator-collected measured JSON proof. It packages
durable root publication, exact scoped ACK identity, peer capability, and
mixed-peer fallback evidence into the common release-bundle descriptor shape.
"""
from __future__ import annotations
import argparse
from datetime import datetime, timezone
import json
import re
import subprocess
import sys
from pathlib import Path
from typing import Any
import check_test_wiring as wiring
ROOT = Path(__file__).resolve().parents[1]
G03_FIELDS = (
"durable_root_publication_proof",
"scoped_ack_request_identity",
"participating_peer_capability_snapshot",
"mixed_peer_ack_fallback_oracle",
)
def git_head() -> str:
return subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=ROOT, text=True).strip()
def timestamp(value: Any, name: str) -> str:
wiring.require(isinstance(value, str) and value.strip(), f"missing {name}")
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
wiring.require(parsed.tzinfo is not None, f"{name} must include timezone")
return parsed.isoformat().replace("+00:00", "Z")
def measured_proof(path: Path, source_revision: str) -> dict[str, Any]:
proof = wiring.read_json(path)
wiring.require(proof.get("schema") == 1, "proof schema must be 1")
wiring.require(proof.get("evidence_type") == "measured", "proof must be measured")
for marker in ("fixture", "fixture_only", "dry_run", "synthetic"):
wiring.require(proof.get(marker) is not True, f"proof is {marker}")
wiring.require(proof.get("source_revision") == source_revision, "proof source revision mismatch")
started_at = timestamp(proof.get("started_at"), "proof.started_at")
finished_at = timestamp(proof.get("finished_at"), "proof.finished_at")
wiring.require(
datetime.fromisoformat(finished_at.replace("Z", "+00:00"))
>= datetime.fromisoformat(started_at.replace("Z", "+00:00")),
"proof timestamps are inverted",
)
wiring.evidence_string(proof.get("run_id"), "proof.run_id", r"[A-Za-z0-9][A-Za-z0-9._:-]{7,127}")
wiring.evidence_string(
proof.get("measurement_window_id"),
"proof.measurement_window_id",
r"[A-Za-z0-9][A-Za-z0-9._:-]{7,127}",
)
wiring.require(proof["measurement_window_id"] != proof["run_id"], "proof must separate run/window identities")
versions = proof.get("versions")
wiring.require(
isinstance(versions, list)
and len(set(versions)) >= 2
and all(isinstance(version, str) and re.fullmatch(r"[0-9a-f]{40}", version) for version in versions),
"proof requires two source revisions",
)
wiring.require(source_revision in versions, "proof versions omit tested source revision")
return proof
def field_from_proof(proof: dict[str, Any], field: str) -> dict[str, Any]:
value = proof.get(field)
wiring.require(isinstance(value, dict), f"proof missing {field}")
for marker in ("fixture", "fixture_only", "dry_run", "synthetic"):
wiring.require(value.get(marker) is not True, f"{field} is {marker}")
wiring.require(value.get("evidence_type") == "measured", f"{field} must be measured")
wiring.require(value.get("source_revision") == proof["source_revision"], f"{field} source revision mismatch")
wiring.require(value.get("run_id") == proof["run_id"], f"{field} run_id mismatch")
wiring.require(
value.get("measurement_window_id") == proof["measurement_window_id"],
f"{field} measurement window mismatch",
)
evidence = {
**value,
"versions": proof["versions"],
"mixed_version_role": wiring.SCANNER_HEAL_RELEASE_MIXED_VERSION_ROLES[("G03", field)],
}
wiring.validate_release_bundle_domain_evidence("G03", field, evidence)
return evidence
def write_field(out_dir: Path, common: dict[str, Any], field: str, field_evidence: dict[str, Any]) -> dict[str, Any]:
evidence = {
**field_evidence,
**common,
"evidence_type": "measured",
"summary": field_evidence.get("summary") or f"Measured Scanner/Heal G03 {field} evidence.",
}
artifact = out_dir / "artifacts" / f"G03-{field}.json"
artifact.parent.mkdir(parents=True, exist_ok=True)
payload = {
"schema": 1,
"evidence_type": "measured",
"source_revision": evidence["source_revision"],
"run_id": evidence["run_id"],
"measurement_window_id": evidence["measurement_window_id"],
"gate": "G03",
"field": field,
}
for key, value in evidence.items():
if key not in {"artifact", "sha256", "artifact_format", "summary", "started_at", "finished_at", "command"}:
payload[key] = value
wiring.write_json(artifact, payload)
evidence["artifact"] = artifact.relative_to(out_dir).as_posix()
evidence["sha256"] = wiring.digest(artifact)
evidence["artifact_format"] = "json"
return evidence
def build_descriptor(args: argparse.Namespace) -> Path:
out_dir = args.out_dir.resolve()
wiring.require(not out_dir.exists(), "output directory must be new")
source_revision = args.source_revision or git_head()
proof = measured_proof(args.proof_json.resolve(), source_revision)
out_dir.mkdir(parents=True)
common = {
"evidence_type": "measured",
"source_revision": source_revision,
"run_id": proof["run_id"],
"measurement_window_id": proof["measurement_window_id"],
"started_at": timestamp(proof["started_at"], "proof.started_at"),
"finished_at": timestamp(proof["finished_at"], "proof.finished_at"),
"command": [
"scripts/run_scanner_heal_scoped_ack_evidence.py",
"--proof-json",
"<proof-json>",
],
}
descriptor = out_dir / "release-bundle-scoped-ack.json"
gates = {
"G03": {
"status": "pass",
"lane": "mixed-version-rollback",
"evidence_type": "measured",
"evidence_fields": {
field: write_field(out_dir, common, field, field_from_proof(proof, field))
for field in G03_FIELDS
},
},
}
wiring.write_json(descriptor, {
"schema": 1,
"evidence": "measured",
"source_revision": source_revision,
"gates": gates,
})
subprocess.check_call([
sys.executable,
str(ROOT / "scripts/check_test_wiring.py"),
"--check-scanner-heal-release-bundle-gate",
str(descriptor),
"G03",
], cwd=ROOT)
return descriptor
def write_self_test_proof(path: Path, source_revision: str) -> None:
now = datetime.now(timezone.utc).replace(microsecond=0)
run_id = f"scoped-ack-{source_revision[:12]}"
measurement_window_id = f"scoped-ack-window-{source_revision[:12]}"
def field_payload(field: str, values: dict[str, Any]) -> dict[str, Any]:
return {
"evidence_type": "measured",
"source_revision": source_revision,
"run_id": run_id,
"measurement_window_id": measurement_window_id,
"scoped_ack_cases": list(wiring.SCANNER_HEAL_RELEASE_SCOPED_ACK_CASES[field]),
**{required: True for required in wiring.SCANNER_HEAL_RELEASE_G03_REQUIRED_TRUE_FIELDS[field]},
**values,
}
proof = {
"schema": 1,
"evidence_type": "measured",
"source_revision": source_revision,
"run_id": run_id,
"measurement_window_id": measurement_window_id,
"started_at": now.isoformat().replace("+00:00", "Z"),
"finished_at": now.isoformat().replace("+00:00", "Z"),
"versions": ["a" * 40, source_revision],
"durable_root_publication_proof": field_payload("durable_root_publication_proof", {}),
"scoped_ack_request_identity": field_payload("scoped_ack_request_identity", {}),
"participating_peer_capability_snapshot": field_payload("participating_peer_capability_snapshot", {}),
"mixed_peer_ack_fallback_oracle": field_payload("mixed_peer_ack_fallback_oracle", {}),
}
wiring.write_json(path, proof)
def run_self_test() -> None:
import tempfile
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source_revision = git_head()
proof = root / "scoped-ack-proof.json"
write_self_test_proof(proof, source_revision)
descriptor = build_descriptor(parse_args([
"--proof-json", str(proof),
"--out-dir", str(root / "out"),
]))
wiring.require(descriptor.is_file(), "self-test descriptor missing")
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source_revision = git_head()
proof = root / "scoped-ack-proof.json"
write_self_test_proof(proof, source_revision)
payload = wiring.read_json(proof)
payload["scoped_ack_request_identity"]["scoped_ack_cases"].remove("exact-generation")
wiring.write_json(proof, payload)
try:
build_descriptor(parse_args(["--proof-json", str(proof), "--out-dir", str(root / "out")]))
except ValueError as err:
wiring.require("missing cases" in str(err), "wrong self-test failure for scoped ACK cases")
else:
raise ValueError("self-test accepted incomplete scoped ACK proof")
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source_revision = git_head()
proof = root / "scoped-ack-proof.json"
write_self_test_proof(proof, source_revision)
payload = wiring.read_json(proof)
payload["durable_root_publication_proof"]["root_readback_observed"] = False
wiring.write_json(proof, payload)
try:
build_descriptor(parse_args(["--proof-json", str(proof), "--out-dir", str(root / "out")]))
except ValueError as err:
wiring.require("root_readback_observed" in str(err), "wrong self-test failure for root readback")
else:
raise ValueError("self-test accepted incomplete root publication proof")
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source_revision = git_head()
proof = root / "scoped-ack-proof.json"
write_self_test_proof(proof, source_revision)
payload = wiring.read_json(proof)
payload["participating_peer_capability_snapshot"]["source_revision"] = "b" * 40
wiring.write_json(proof, payload)
try:
build_descriptor(parse_args(["--proof-json", str(proof), "--out-dir", str(root / "out")]))
except ValueError as err:
wiring.require("source revision mismatch" in str(err), "wrong self-test failure for field source")
else:
raise ValueError("self-test accepted stale scoped ACK field source")
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source_revision = git_head()
proof = root / "scoped-ack-proof.json"
write_self_test_proof(proof, source_revision)
payload = wiring.read_json(proof)
payload["participating_peer_capability_snapshot"].pop("capability_probe_observed")
wiring.write_json(proof, payload)
try:
build_descriptor(parse_args(["--proof-json", str(proof), "--out-dir", str(root / "out")]))
except ValueError as err:
wiring.require("capability_probe_observed" in str(err), "wrong self-test failure for capability proof")
else:
raise ValueError("self-test accepted incomplete capability snapshot proof")
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source_revision = git_head()
proof = root / "scoped-ack-proof.json"
write_self_test_proof(proof, source_revision)
payload = wiring.read_json(proof)
payload["evidence_type"] = "synthetic"
wiring.write_json(proof, payload)
try:
build_descriptor(parse_args(["--proof-json", str(proof), "--out-dir", str(root / "out")]))
except ValueError as err:
wiring.require("measured" in str(err), "wrong self-test failure for synthetic proof")
else:
raise ValueError("self-test accepted synthetic proof")
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--proof-json", type=Path)
parser.add_argument("--out-dir", type=Path)
parser.add_argument("--source-revision")
parser.add_argument("--self-test", action="store_true")
args = parser.parse_args(argv)
if not args.self_test:
if args.proof_json is None:
parser.error("--proof-json is required unless --self-test is used")
if args.out_dir is None:
parser.error("--out-dir is required unless --self-test is used")
return args
def main() -> int:
try:
args = parse_args()
if args.self_test:
run_self_test()
return 0
descriptor = build_descriptor(args)
print(f"Scoped ACK release descriptor verified: {descriptor}")
return 0
except (ValueError, OSError, json.JSONDecodeError, subprocess.SubprocessError) as err:
print(f"ERROR: {err}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())