From 578561c74f807ce50aa398a6cbafd684a96a4c40 Mon Sep 17 00:00:00 2001 From: ECHO OMEGA PRIME Date: Sat, 3 Oct 2026 13:59:09 -0500 Subject: [PATCH 1/5] Add reviewed ACB collector with production signing boundaries --- docs/ACCOUNT_CONTINUITY_COLLECTOR.md | 158 +++++ scripts/hammer_account_bridge_attestor.py | 684 +++++++++++++++++++ tests/test_hammer_account_bridge_attestor.py | 309 +++++++++ 3 files changed, 1151 insertions(+) create mode 100644 docs/ACCOUNT_CONTINUITY_COLLECTOR.md create mode 100644 scripts/hammer_account_bridge_attestor.py create mode 100644 tests/test_hammer_account_bridge_attestor.py diff --git a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md new file mode 100644 index 0000000..cb26729 --- /dev/null +++ b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md @@ -0,0 +1,158 @@ +# Account Continuity Bridge production acceptance collector + +`scripts/hammer_account_bridge_attestor.py` is an operator collector for the reviewed +ACB candidate `def1828001c354bcf89f7d32bc987d6eba520cb6`, PR 4, branch +`agent/grok47-provider-recovery-20261003`, plugin version +`1.1.0+codex.20261003120504`. It is not a subscriber endpoint or a generic signer. +Changing the candidate requires source review and new evidence. Policy, trust +roots and target source are not changed by this collector. + +This is held diagnostic source. The pinned candidate subsequently failed a real +installed Windows router-state rename stability pass. It is not eligible for +production signing; a repaired candidate requires a separately reviewed pin +update and fresh measured acceptance. The hosted App receipt was also unavailable +during preparation because its owner service was stopped. No signing or deployment +was performed by this source-publication task. + +## Source provenance + +Recovered through scoped SDK reads from HAMMER's historical operator workspace: +`C:/Users/bobmc/tmp/echo-account-continuity-attest-20260902T173258Z-33cd2522/hammer_account_bridge_attestor.py`. +Its exact recovered SHA256 was +`9451710e9ec0323b7784411720fd76214268a2a7fa64da28d97a80fcae922ef4`. +The SDK's text scrubber replaced the harmless Python keyword `password=None)`; +restoring that literal reproduced the independently measured complete source hash. +No key bytes were retrieved. The old temporary workspace had no Git provenance; +this repository establishes reviewed source ownership from this import onward. + +The first review used deployed CertForge base +`d8ad9fd881365801354b78a758632d2a31ab6828` and source commits +`8eb9cc5e346dc31342eadf2d8fbb00e2e0717666` and +`591d1ba6524c4858f63dfab21fe690e4d5a10521`. Publication transfers only this collector, +its tests and this document onto canonical `main` base +`4f7d99e2dd4422f3d81cf5b709581be963f5818a`, preserving unrelated main and deployed +history. The Python collector and test bytes remain identical to the independently +reviewed source; only this provenance/hold documentation is extended. The collector +is standalone and uses the existing `cryptography` dependency. It does not import +or install the deployed consumer changes absent from that main base. Operational +use still requires a separately verified strict production-E2E consumer and trust +admission; this source-only PR does not establish either. + +The historical owner was `HAMMER\bobmc`; its existing collector identity is +`ed25519:59de9be507b39b291ee13c4a57378ec6`. The collector requires that identity; +it does not generate keys or enroll public keys. Current trust admission must be +verified independently by the operator before use. + +## Execution and custody + +Run only as the existing HAMMER collector owner. Inputs must come from the +authorized QUENCH acceptance and hosted-app readback, outside the candidate +repository. Required `--quench-evidence-sha256` and `--revision-receipt-sha256` +bind the actual owner-retrieved JSON bytes; these hashes are custody checks, +not proof that an arbitrary caller's JSON is authentic. Never populate successful +fields by assertion or copy the synthetic test fixtures into operational evidence. + +The collector verifies a transferred Git bundle, exact head, branch, ancestry and +clean checkout. It runs three independent passes of 91 HAMMER-safe assertions, +three router concurrency/lock negative controls, and three critical journeys. +DPAPI-dependent core/bridge assertions must pass on QUENCH's real native install; +they are explicitly not represented as executed on HAMMER. The complete QUENCH +suite has 119 named assertions. Secret scanning must pass on both hosts. + +This operator path is only for the reviewed first-party ECHO candidate. It must +not be repurposed to execute arbitrary customer code under the key-owning user. +Customer targets continue to require dedicated isolated runners and separate +signing authority. Key material is never sent to target commands. Source children +and the temporary checkout finish before the operator loads the existing key. +The key must be outside the collector workspace, bundle and evidence inputs. +Outputs are three distinct new paths; existing files are never replaced. + +## QUENCH evidence v2 + +The JSON object schema is `echo.account-continuity.quench-evidence.v2`: + +| Field | Required evidence | +|---|---| +| `host`, `observed_at` | QUENCH; actual zoned observation time, no more than one hour old | +| `source_commit`, `installed_cache_commit`, `remote_branch_commit`, `pull_request_head_commit` | Each independently read back as the exact candidate SHA | +| `branch`, `pull_request`, `installed_version` | Exact branch above, integer 4, exact plugin version above | +| `installation_scope` | Explicit `isolated_canary` or `production`; production signing requires `production` | +| `installed_manifest_sha256` | Hash of the measured installed file manifest whose files were compared to the candidate | +| `native_plugin_enabled`, `fresh_native_session` | Both verified true through actual native plugin/session readback | +| `iterations`, `assertions_passed_per_iteration`, `critical_journeys` | 3, `[119,119,119]`, three actual `PASS` results | +| `test_runs` | Three rows: numbered `iteration`, actual `observed_at`, exact `source_commit`, `total=119`, complete suite counts, `critical_journey=PASS`, and real `router_concurrency` output | +| `live_runs` | Three distinct nonce/session rows from actual installed bridge execution, as described below | +| `status_runs` | Three actual non-spending installed MCP observations with time/source binding | +| `gitleaks_exact_tree`, `codex_mcp_config` | Actual `PASS` exact-tree scan and `ok` native MCP config readback | +| `private_key_exported`, `credentials_in_evidence` | False, supported by the execution boundary and sanitized artifact inspection | + +The suite count mapping is `repository_policy:8`, `account_continuity_core:6`, +`provider_auth_monitor:18`, `provider_content_import:9`, `multiprovider_mcp:35`, +`account_continuity_bridge:22`, `provider_registry:21`. + +Every router row must be the real `Test-RouterConcurrency.mjs` result: +`ok=true`, `concurrent_requests=12`, `concurrent_processes=8`, and +`contended_lock_preserved=true`. This is additional acceptance, not included in +the 119 named assertions. + +Every live row requires `exact_canary_match=true`, `selected_provider=forge-qwen`, +`selected_outcome=success`, `provenance=LIVE_PROVIDER_BRIDGE`, +`credential_copied_or_exposed=false`, equal valid `canary_sha256` and +`response_sha256`, actual `model` and `session_id`, exact `source_commit`, +`governance=PASS`, and actual `observed_at`. Nonces and session IDs must be distinct. +The inherited Qwen route is preserved. A canary is one bounded no-tools/no-files +turn through the installed MCP route with a fresh unique expected token, followed +by exact response readback. Use the existing governed prompt builder; no bypass +or direct substitute API establishes installed bridge acceptance. + +Every status row requires `status_nonspending=true`, +`server_name=account_continuity_multiprovider_mcp`, `server_version=0.5.0`, +`provider_count=7`, `tool_count=17`, exact source SHA and actual observation time. +The 26 critical-journey surfaces include nine PowerShell actions; they are not +the native MCP tool count. The actual source/native inventory has 17 MCP tools. +Every nested observation must be current and timezone-aware. + +`isolated_canary` means a real official native installation in a new task-owned +Codex home with the same tests, live calls, negative controls and installed-byte +readback. It is not a workspace test. The evidence validator preserves that scope, +but the production collector rejects it before hosted collection, source execution, +private-key access or signing. Its input remains unsigned canary evidence and the +release remains NOT_READY. The generic production policy does not inspect this +scope itself, so a documentation disclaimer cannot enforce the boundary. Only +measured `production` installation evidence may enter production signing. Scope, +custody hashes and every source timestamp are revalidated immediately before key +access so long HAMMER test runs cannot refresh expired QUENCH observations. + +## Hosted receipt and invocation + +`--revision-receipt` is an actual Certification Forge GitHub App revision receipt +readback, not a GitHub Actions CI document. It must have app identity +`certification-forge`, exact repository/SHA, a valid observed receipt chain and +one succeeded receipt matching `--hosted-delivery-id`. Its result must bind the +exact acquired target/environment, initial `COMPLETE`/`NOT_READY` certification, +`production_e2e_valid=false`, positive check-run identity and custody hash. +The standalone strict run alone does not supply this hosted-app receipt. + +```powershell +& '' scripts/hammer_account_bridge_attestor.py ` + --bundle '' --base-commit '' ` + --source-commit def1828001c354bcf89f7d32bc987d6eba520cb6 ` + --target-identity-digest '' ` + --environment-identity-digest '' ` + --revision-receipt '' --revision-receipt-sha256 '' ` + --hosted-delivery-id '' ` + --quench-evidence '' --quench-evidence-sha256 '' ` + --private-key '' ` + --python '' --pwsh '' --node '' ` + --gitleaks '' --workspace-root '' ` + --quench-address '' --quench-management-port '' ` + --output '' --public-key-output '' ` + --report-output '' +``` + +This command signs only after every real acceptance gate completes. Source tests +do not execute it against production or existing keys. The operator separately +verifies the returned signature and exact binding, then admits the envelope via +the root-owned atomic transfer described in `OPERATIONS.md`. The collector has +no remote admission/deployment code. A new idempotent strict run consumes fresh +evidence; existing terminal runs and their signed verdicts remain unchanged. diff --git a/scripts/hammer_account_bridge_attestor.py b/scripts/hammer_account_bridge_attestor.py new file mode 100644 index 0000000..faac463 --- /dev/null +++ b/scripts/hammer_account_bridge_attestor.py @@ -0,0 +1,684 @@ +from __future__ import annotations + +# Recovered from the HAMMER owner workspace; see docs/ACCOUNT_CONTINUITY_COLLECTOR.md. +# Historical source SHA256: 9451710e9ec0323b7784411720fd76214268a2a7fa64da28d97a80fcae922ef4 + +import argparse +import base64 +import hashlib +import json +import os +import re +import socket +import subprocess +import tempfile +from datetime import UTC, datetime, timedelta +from pathlib import Path +from typing import Any + +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey + + +SCHEMA_VERSION = "certforge.production-e2e.v1" +REPORT_SCHEMA = "echo.account-continuity.hammer-attestor-report.v1" +PROFILE = "generic-production-v1" +REPOSITORY = "echoomegaprime/account-continuity-bridge" +BRANCH = "agent/grok47-provider-recovery-20261003" +SOURCE_COMMIT = "def1828001c354bcf89f7d32bc987d6eba520cb6" +PLUGIN_VERSION = "1.1.0+codex.20261003120504" +PULL_REQUEST = 4 +COLLECTOR_KEY_ID = "ed25519:59de9be507b39b291ee13c4a57378ec6" +BASE_CHECKS = frozenset( + { + "runtime_or_artifact_executed", + "exact_identity_readback", + "critical_journeys_complete", + "negative_controls_pass", + "stability_verified", + "external_acceptance_verified", + } +) +EXPECTED_ASSERTIONS = { + "repository_policy": 8, + "account_continuity_core": 6, + "provider_auth_monitor": 18, + "provider_content_import": 9, + "multiprovider_mcp": 35, + "account_continuity_bridge": 22, + "provider_registry": 21, +} +POWERSHELL_TESTS = { + "repository_policy": "tests/Test-RepositoryPolicy.ps1", + "provider_auth_monitor": "tests/Test-ProviderAuthMonitor.ps1", + "provider_content_import": "tests/Test-ProviderContentImport.ps1", + "multiprovider_mcp": "tests/Test-MultiproviderMcp.ps1", +} +HAMMER_EXPECTED_ASSERTIONS = { + name: EXPECTED_ASSERTIONS[name] + for name in (*POWERSHELL_TESTS, "provider_registry") +} +HAMMER_DPAPI_BOUNDARY = { + "account_continuity_core": EXPECTED_ASSERTIONS["account_continuity_core"], + "account_continuity_bridge": EXPECTED_ASSERTIONS["account_continuity_bridge"], +} +SHA40 = re.compile(r"^[0-9a-f]{40}$") +SHA256 = re.compile(r"^[0-9a-f]{64}$") + + +class AttestationError(RuntimeError): + """A fail-closed rejection with no secret-bearing detail.""" + + +def canonical_json(value: Any) -> bytes: + return json.dumps( + value, + sort_keys=True, + separators=(",", ":"), + ensure_ascii=False, + ).encode("utf-8") + + +def sha256_bytes(value: bytes) -> str: + return hashlib.sha256(value).hexdigest() + + +def read_json(path: Path, *, expected_sha256: str | None = None) -> tuple[dict[str, Any], str]: + try: + content = path.read_bytes() + digest = sha256_bytes(content) + if expected_sha256 is not None and (not SHA256.fullmatch(expected_sha256) or digest != expected_sha256): + raise AttestationError("owner-collected evidence custody digest mismatch") + value = json.loads(content.decode("utf-8-sig")) + except (OSError, UnicodeError, json.JSONDecodeError) as exc: + raise AttestationError(f"invalid JSON evidence: {path.name}") from exc + if not isinstance(value, dict): + raise AttestationError(f"JSON evidence must be an object: {path.name}") + return value, digest + + +def run( + command: list[str], + *, + cwd: Path | None = None, + env: dict[str, str] | None = None, + timeout: int = 300, +) -> subprocess.CompletedProcess[str]: + completed = subprocess.run( + command, + cwd=str(cwd) if cwd else None, + env=env, + text=True, + capture_output=True, + timeout=timeout, + check=False, + ) + if completed.returncode != 0: + raise AttestationError( + f"verification command failed ({completed.returncode}): {Path(command[0]).name}" + ) + return completed + + +def verify_hosted_receipt( + path: Path, + *, + source_commit: str, + target_digest: str, + environment_digest: str, + delivery_id: str, + expected_sha256: str | None = None, +) -> dict[str, Any]: + document, document_sha256 = read_json(path, expected_sha256=expected_sha256) + if document.get("app_key") != "certification-forge": + raise AttestationError("hosted receipt has the wrong app identity") + if document.get("repository") != REPOSITORY: + raise AttestationError("hosted receipt has the wrong repository") + if document.get("target_sha") != source_commit: + raise AttestationError("hosted receipt is not bound to the exact source") + chain = document.get("receipt_chain") + if not isinstance(chain, dict) or chain.get("ok") is not True: + raise AttestationError("hosted receipt chain is invalid") + receipts = document.get("receipts") + if not isinstance(receipts, list): + raise AttestationError("hosted receipt list is invalid") + matches = [ + row + for row in receipts + if isinstance(row, dict) + and row.get("target_sha") == source_commit + and row.get("repository") == REPOSITORY + and row.get("delivery_id") == delivery_id + and row.get("state") == "succeeded" + ] + if len(matches) != 1: + raise AttestationError("exact-source hosted delivery is missing or ambiguous") + receipt = matches[0] + result = receipt.get("result") + if not isinstance(result, dict) or result.get("effect") != "certification": + raise AttestationError("hosted receipt is not a certification receipt") + if result.get("target_identity_digest") != target_digest: + raise AttestationError("hosted receipt target identity mismatch") + if result.get("environment_identity_digest") != environment_digest: + raise AttestationError("hosted receipt environment identity mismatch") + if result.get("run_outcome") != "COMPLETE" or result.get("release_verdict") != "NOT_READY": + raise AttestationError("hosted initial certification state is unexpected") + if result.get("production_e2e_valid") is not False: + raise AttestationError("hosted initial certification did not fail closed") + if not isinstance(result.get("check_run"), int) or result["check_run"] <= 0: + raise AttestationError("hosted receipt check-run identity is invalid") + receipt_hash = str(receipt.get("receipt_hash") or "") + if not SHA256.fullmatch(receipt_hash): + raise AttestationError("hosted receipt custody hash is invalid") + return { + "receipt_hash": receipt_hash, + "delivery_id": str(receipt.get("delivery_id") or ""), + "check_run": result["check_run"], + "initial_certification_id": str(result.get("run_id") or ""), + "initial_release_verdict": str(result.get("release_verdict") or ""), + "chain_receipts": int(chain.get("receipts") or 0), + "document_sha256": document_sha256, + } + + +def verify_quench_evidence(path: Path, source_commit: str, *, expected_sha256: str | None = None) -> dict[str, Any]: + document, document_sha256 = read_json(path, expected_sha256=expected_sha256) + if source_commit != SOURCE_COMMIT: + raise AttestationError("collector requires its reviewed exact-source candidate") + if document.get("schema_version") != "echo.account-continuity.quench-evidence.v2": + raise AttestationError("QUENCH evidence schema is invalid") + verify_current_time(document.get("observed_at")) + if str(document.get("host", "")).casefold() != "quench": + raise AttestationError("runtime evidence was not produced on QUENCH") + for field in ( + "source_commit", + "installed_cache_commit", + "remote_branch_commit", + "pull_request_head_commit", + ): + if document.get(field) != source_commit: + raise AttestationError(f"QUENCH evidence {field} is not exact-source") + if type(document.get("pull_request")) is not int or document["pull_request"] != PULL_REQUEST: + raise AttestationError("QUENCH evidence has the wrong pull request") + if document.get("branch") != BRANCH: + raise AttestationError("QUENCH evidence has the wrong branch") + if document.get("installed_version") != PLUGIN_VERSION: + raise AttestationError("QUENCH installed plugin version is unexpected") + if document.get("installation_scope") not in {"production", "isolated_canary"}: + raise AttestationError("QUENCH installation scope is unsupported") + if document.get("native_plugin_enabled") is not True or document.get("fresh_native_session") is not True: + raise AttestationError("QUENCH native installed plugin acceptance is incomplete") + if not SHA256.fullmatch(str(document.get("installed_manifest_sha256") or "")): + raise AttestationError("QUENCH installed manifest identity is missing") + if document.get("iterations") != 3: + raise AttestationError("QUENCH stability iteration count is invalid") + if document.get("assertions_passed_per_iteration") != [119, 119, 119]: + raise AttestationError("QUENCH test stability evidence is invalid") + if document.get("critical_journeys") != ["PASS", "PASS", "PASS"]: + raise AttestationError("QUENCH journey stability evidence is invalid") + test_runs = document.get("test_runs") + if not isinstance(test_runs, list) or len(test_runs) != 3: + raise AttestationError("QUENCH detailed test evidence is invalid") + for iteration, row in enumerate(test_runs, start=1): + if not isinstance(row, dict) or row.get("iteration") != iteration: + raise AttestationError("QUENCH test iteration identity is invalid") + verify_current_time(row.get("observed_at")) + if row.get("source_commit") != source_commit or row.get("total") != 119: + raise AttestationError("QUENCH test iteration is not exact-source") + if row.get("critical_journey") != "PASS" or row.get("assertions") != EXPECTED_ASSERTIONS: + raise AttestationError("QUENCH detailed assertions are invalid") + verify_router_result(row.get("router_concurrency")) + live_runs = document.get("live_runs") + if not isinstance(live_runs, list) or len(live_runs) != 3: + raise AttestationError("QUENCH live canary evidence is invalid") + seen_nonces: set[str] = set() + seen_sessions: set[str] = set() + for row in live_runs: + if not isinstance(row, dict): + raise AttestationError("QUENCH live canary record is invalid") + verify_current_time(row.get("observed_at")) + if row.get("source_commit") != source_commit or row.get("governance") != "PASS": + raise AttestationError("QUENCH canary is not governed exact-source execution") + session = row.get("session_id") + if not isinstance(session, str) or not session or not isinstance(row.get("model"), str) or not row["model"]: + raise AttestationError("QUENCH canary model/session identity is missing") + if row.get("exact_canary_match") is not True: + raise AttestationError("QUENCH live canary did not match") + if row.get("selected_provider") != "forge-qwen" or row.get("selected_outcome") != "success": + raise AttestationError("QUENCH live canary used the wrong route") + if row.get("provenance") != "LIVE_PROVIDER_BRIDGE": + raise AttestationError("QUENCH live canary provenance is invalid") + if row.get("credential_copied_or_exposed") is not False: + raise AttestationError("QUENCH live canary reports credential exposure") + if row.get("canary_sha256") != row.get("response_sha256"): + raise AttestationError("QUENCH live canary digest does not match") + if not SHA256.fullmatch(str(row.get("canary_sha256", ""))): + raise AttestationError("QUENCH live canary digest is invalid") + if row["canary_sha256"] in seen_nonces or session in seen_sessions: + raise AttestationError("QUENCH requires three distinct live nonce sessions") + seen_nonces.add(row["canary_sha256"]) + seen_sessions.add(session) + status_runs = document.get("status_runs") + if not isinstance(status_runs, list) or len(status_runs) != 3: + raise AttestationError("QUENCH status stability evidence is invalid") + for row in status_runs: + if not isinstance(row, dict) or row.get("status_nonspending") is not True: + raise AttestationError("QUENCH status probe was not non-spending") + verify_current_time(row.get("observed_at")) + if row.get("source_commit") != source_commit: + raise AttestationError("QUENCH status probe is not exact-source") + if row.get("server_name") != "account_continuity_multiprovider_mcp": + raise AttestationError("QUENCH status probe has the wrong server") + if row.get("server_version") != "0.5.0" or row.get("provider_count") != 7 or row.get("tool_count") != 17: + raise AttestationError("QUENCH status probe surface is incomplete") + if document.get("gitleaks_exact_tree") != "PASS": + raise AttestationError("QUENCH secret scan is not passing") + if document.get("codex_mcp_config") != "ok": + raise AttestationError("QUENCH MCP configuration is not healthy") + if document.get("private_key_exported") is not False: + raise AttestationError("QUENCH evidence reports private-key export") + if document.get("credentials_in_evidence") is not False: + raise AttestationError("QUENCH evidence reports credential material") + return { + "document_sha256": document_sha256, + "installed_version": document["installed_version"], + "installation_scope": document["installation_scope"], + "installed_manifest_sha256": document["installed_manifest_sha256"], + "assertions_passed_per_iteration": document["assertions_passed_per_iteration"], + "critical_journeys": document["critical_journeys"], + "live_canaries": len(live_runs), + "status_probes": len(status_runs), + "tool_count": status_runs[0]["tool_count"], + "provider_count": status_runs[0]["provider_count"], + "selected_provider": "forge-qwen", + "provenance": "LIVE_PROVIDER_BRIDGE", + "gitleaks_exact_tree": "PASS", + "codex_mcp_config": "ok", + "private_key_exported": False, + } + + +def verify_current_time(value: Any) -> None: + try: + observed = datetime.fromisoformat(value) + if observed.tzinfo is None or not -5 <= (datetime.now(UTC) - observed).total_seconds() <= 3600: + raise ValueError("outside acceptance window") + except (TypeError, ValueError) as exc: + raise AttestationError("QUENCH evidence time is not current and timezone-aware") from exc + + +def verify_production_quench_evidence(path: Path, source_commit: str, *, expected_sha256: str) -> dict[str, Any]: + evidence = verify_quench_evidence(path, source_commit, expected_sha256=expected_sha256) + if evidence["installation_scope"] != "production": + raise AttestationError("production installation is required; isolated_canary evidence remains unsigned and NOT_READY") + return evidence + + +def verify_router_result(value: Any) -> None: + if (not isinstance(value, dict) or value.get("ok") is not True + or type(value.get("concurrent_requests")) is not int or value["concurrent_requests"] != 12 + or type(value.get("concurrent_processes")) is not int or value["concurrent_processes"] != 8 + or value.get("contended_lock_preserved") is not True): + raise AttestationError("router concurrency/negative-control acceptance is incomplete") + + +def read_router_command(completed: subprocess.CompletedProcess[str]) -> dict[str, Any]: + try: + value = json.loads(completed.stdout) + except json.JSONDecodeError as exc: + raise AttestationError("router command did not return JSON") from exc + verify_router_result(value) + return value + + +def verify_private_key( + path: Path, + repository: Path, + bundle: Path, + quench_evidence: Path, +) -> tuple[Ed25519PrivateKey, str, str]: + resolved = path.resolve(strict=True) + if resolved.is_relative_to(repository) or resolved in {bundle, quench_evidence}: + raise AttestationError("collector private key is inside source or transfer state") + try: + key = serialization.load_pem_private_key(resolved.read_bytes(), password=None) + except (OSError, TypeError, ValueError) as exc: + raise AttestationError("collector private key is unavailable") from exc + if not isinstance(key, Ed25519PrivateKey): + raise AttestationError("collector private key is not Ed25519") + public_key = key.public_key() + raw = public_key.public_bytes( + serialization.Encoding.Raw, + serialization.PublicFormat.Raw, + ) + key_id = "ed25519:" + sha256_bytes(raw)[:32] + if key_id != COLLECTOR_KEY_ID: + raise AttestationError("collector key does not match the existing admitted identity") + public_pem = public_key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.SubjectPublicKeyInfo, + ).decode("ascii") + return key, key_id, public_pem + + +def verify_quench_reachability(address: str, port: int) -> None: + try: + with socket.create_connection((address, port), timeout=5.0): + return + except OSError as exc: + raise AttestationError("HAMMER cannot reach the QUENCH management listener") from exc + + +def parse_test_json(completed: subprocess.CompletedProcess[str], label: str) -> int: + lines = [line for line in completed.stdout.splitlines() if line.strip()] + if not lines: + raise AttestationError(f"{label} returned no evidence") + try: + value = json.loads("\n".join(lines)) + except json.JSONDecodeError as exc: + raise AttestationError(f"{label} did not return JSON") from exc + if not isinstance(value, dict) or value.get("ok") is not True: + raise AttestationError(f"{label} did not pass") + assertions = value.get("assertions") + if isinstance(assertions, dict): + if not assertions or any(passed is not True for passed in assertions.values()): + raise AttestationError(f"{label} named assertion failed or is missing") + return len(assertions) + if type(assertions) is int and assertions > 0: + return assertions + raise AttestationError(f"{label} assertion count is unavailable") + + +def parse_node_check(completed: subprocess.CompletedProcess[str]) -> int: + for line in reversed(completed.stdout.splitlines()): + if not line.strip().startswith("{"): + continue + try: + value = json.loads(line) + except json.JSONDecodeError: + continue + if isinstance(value, dict) and value.get("ok") is True and type(value.get("assertions")) is int and value["assertions"] > 0: + return value["assertions"] + raise AttestationError("Node registry assertion count is unavailable") + + +def atomic_write(path: Path, data: bytes) -> None: + """Publish complete new evidence without replacing any existing owner file.""" + path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile("wb", dir=path.parent, delete=False) as stream: + stream.write(data) + temporary = Path(stream.name) + try: + os.link(temporary, path) + finally: + temporary.unlink(missing_ok=True) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Attest Account Continuity Bridge from HAMMER") + parser.add_argument("--bundle", type=Path, required=True) + parser.add_argument("--base-commit", required=True) + parser.add_argument("--source-commit", required=True) + parser.add_argument("--target-identity-digest", required=True) + parser.add_argument("--environment-identity-digest", required=True) + parser.add_argument("--revision-receipt", type=Path, required=True) + parser.add_argument("--revision-receipt-sha256", required=True) + parser.add_argument("--hosted-delivery-id", required=True) + parser.add_argument("--quench-evidence", type=Path, required=True) + parser.add_argument("--quench-evidence-sha256", required=True) + parser.add_argument("--private-key", type=Path, required=True) + parser.add_argument("--python", type=Path, required=True) + parser.add_argument("--pwsh", type=Path, required=True) + parser.add_argument("--node", type=Path, required=True) + parser.add_argument("--gitleaks", type=Path, required=True) + parser.add_argument("--workspace-root", type=Path, required=True) + parser.add_argument("--quench-address", required=True) + parser.add_argument("--quench-management-port", type=int, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--public-key-output", type=Path, required=True) + parser.add_argument("--report-output", type=Path, required=True) + return parser.parse_args() + + +def main() -> int: + args = parse_args() + if socket.gethostname().casefold() != "hammer": + raise AttestationError("collector must run on HAMMER") + source_commit = args.source_commit.casefold() + base_commit = args.base_commit.casefold() + target_digest = args.target_identity_digest.casefold() + environment_digest = args.environment_identity_digest.casefold() + if not SHA40.fullmatch(source_commit) or not SHA40.fullmatch(base_commit): + raise AttestationError("source and base commits must be exact") + if source_commit != SOURCE_COMMIT: + raise AttestationError("collector requires its reviewed exact-source candidate") + if not SHA256.fullmatch(target_digest) or not SHA256.fullmatch(environment_digest): + raise AttestationError("run identity digests must be exact") + + bundle = args.bundle.resolve(strict=True) + python = args.python.resolve(strict=True) + pwsh = args.pwsh.resolve(strict=True) + node = args.node.resolve(strict=True) + gitleaks = args.gitleaks.resolve(strict=True) + workspace_root = args.workspace_root.resolve(strict=True) + quench_evidence_path = args.quench_evidence.resolve(strict=True) + if not workspace_root.is_dir(): + raise AttestationError("collector workspace root is not a directory") + output_paths = [path.resolve() for path in (args.output, args.public_key_output, args.report_output)] + protected_paths = {args.private_key.resolve(), bundle, quench_evidence_path, + args.revision_receipt.resolve(), Path(__file__).resolve()} + if (len(set(output_paths)) != 3 or any(path in protected_paths or path.exists() for path in output_paths) + or args.private_key.resolve().is_relative_to(workspace_root)): + raise AttestationError("collector output/key paths violate ownership separation") + quench = verify_production_quench_evidence(quench_evidence_path, source_commit, + expected_sha256=args.quench_evidence_sha256) + hosted = verify_hosted_receipt( + args.revision_receipt.resolve(strict=True), + source_commit=source_commit, + target_digest=target_digest, + environment_digest=environment_digest, + delivery_id=args.hosted_delivery_id, + expected_sha256=args.revision_receipt_sha256, + ) + verify_quench_reachability(args.quench_address, args.quench_management_port) + + test_runs: list[dict[str, int]] = [] + journey_runs: list[str] = [] + router_runs: list[dict[str, Any]] = [] + with tempfile.TemporaryDirectory(prefix="acb-attest-", dir=workspace_root) as temporary: + root = Path(temporary) + repository = root / "repo" + run(["git", "clone", "--quiet", str(bundle), str(repository)], timeout=600) + run(["git", "-C", str(repository), "checkout", "--detach", "--quiet", source_commit]) + head = run(["git", "-C", str(repository), "rev-parse", "HEAD"]).stdout.strip() + if head != source_commit: + raise AttestationError("bundle checkout is not the exact source") + bundle_refs = run(["git", "-C", str(repository), "bundle", "list-heads", str(bundle)]).stdout + if f"{source_commit} refs/heads/{BRANCH}" not in bundle_refs: + raise AttestationError("bundle branch does not resolve to the exact source") + run(["git", "-C", str(repository), "fsck", "--full"], timeout=600) + run(["git", "-C", str(repository), "merge-base", "--is-ancestor", base_commit, source_commit]) + run(["git", "-C", str(repository), "diff", "--check", base_commit, source_commit]) + + environment = os.environ.copy() + environment["PYTHONDONTWRITEBYTECODE"] = "1" + for _ in range(3): + counts: dict[str, int] = {} + for label, relative in POWERSHELL_TESTS.items(): + completed = run( + [str(pwsh), "-NoLogo", "-NoProfile", "-File", str(repository / relative)], + cwd=repository, + env=environment, + timeout=300, + ) + counts[label] = parse_test_json(completed, label) + for relative in ( + "mcp/server.mjs", + "mcp/commands.mjs", + "mcp/provider-registry.mjs", + "mcp/router.mjs", + "mcp/governance.mjs", + "mcp/status.mjs", + "mcp/tools.mjs", + "mcp/forge-plugins.mjs", + ): + run([str(node), "--check", str(repository / relative)], cwd=repository, env=environment) + counts["provider_registry"] = parse_node_check( + run([str(node), str(repository / "tests/Test-ProviderRegistry.mjs")], cwd=repository, env=environment) + ) + if counts != HAMMER_EXPECTED_ASSERTIONS or sum(counts.values()) != 91: + raise AttestationError("HAMMER assertion totals are invalid") + router_result = read_router_command(run( + [str(node), str(repository / "tests/Test-RouterConcurrency.mjs")], + cwd=repository, env=environment)) + router_runs.append(router_result) + test_runs.append(counts) + journey = run( + [str(python), "-B", str(repository / "scripts/certforge_journey.py")], + cwd=repository, + env=environment, + ).stdout.strip() + if journey != "ACCOUNT_CONTINUITY_CRITICAL_JOURNEY_OK surfaces=26 apps=8 providers=7 secret_fields=0": + raise AttestationError("HAMMER critical journey output is invalid") + journey_runs.append("PASS") + + run([str(gitleaks), "dir", "--no-banner", "--redact", str(repository)], timeout=300) + status = run(["git", "-C", str(repository), "status", "--porcelain"]).stdout.strip() + if status: + raise AttestationError("exact-source checkout became dirty during verification") + + observed_at = datetime.now(UTC) + canonical_target = f"https://github.com/{REPOSITORY}.git@{source_commit}" + evidence_summary = { + "bundle_sha256": sha256_bytes(bundle.read_bytes()), + "hosted_receipt_document_sha256": hosted["document_sha256"], + "hosted_receipt_hash": hosted["receipt_hash"], + "hosted_delivery_id": hosted["delivery_id"], + "hosted_check_run": hosted["check_run"], + "quench_evidence_sha256": quench["document_sha256"], + "installed_version": quench["installed_version"], + "installation_scope": quench["installation_scope"], + "installed_manifest_sha256": quench["installed_manifest_sha256"], + "hammer_router_concurrency": router_runs, + "hammer_test_iterations": len(test_runs), + "hammer_assertions_passed_per_iteration": [sum(row.values()) for row in test_runs], + "hammer_assertion_detail": test_runs, + "hammer_dpapi_remote_session_boundary": HAMMER_DPAPI_BOUNDARY, + "hammer_dpapi_remote_session_result": "NOT_EXECUTED_ON_HAMMER_REQUIRES_QUENCH_ACCEPTANCE", + "hammer_critical_journeys": journey_runs, + "quench_assertions_passed_per_iteration": quench["assertions_passed_per_iteration"], + "quench_critical_journeys": quench["critical_journeys"], + "quench_live_canaries": quench["live_canaries"], + "quench_status_probes": quench["status_probes"], + "tool_count": quench["tool_count"], + "provider_count": quench["provider_count"], + "selected_provider": quench["selected_provider"], + "provenance": quench["provenance"], + "gitleaks_exact_tree_quench": quench["gitleaks_exact_tree"], + "gitleaks_exact_tree_hammer": "PASS", + "codex_mcp_config": quench["codex_mcp_config"], + "private_key_exported": False, + } + checks = { + "runtime_or_artifact_executed": len(test_runs) == 3, + "exact_identity_readback": head == source_commit == SOURCE_COMMIT, + "critical_journeys_complete": journey_runs == ["PASS"] * 3, + "negative_controls_pass": len(router_runs) == 3 and all(row["contended_lock_preserved"] is True for row in router_runs), + "stability_verified": test_runs == [HAMMER_EXPECTED_ASSERTIONS] * 3, + "external_acceptance_verified": quench["live_canaries"] == 3 and quench["status_probes"] == 3, + } + if not all(checks.values()): + raise AttestationError("production acceptance did not complete") + payload = { + "schema_version": SCHEMA_VERSION, + "attestation_id": ( + f"hammer-account-continuity-{observed_at.strftime('%Y%m%dT%H%M%SZ')}-{source_commit[:12]}" + ), + "profile": PROFILE, + "target_identity_digest": target_digest, + "environment_identity_digest": environment_digest, + "source_commit": source_commit, + "deployment_sha": source_commit, + "canonical_target": canonical_target, + "required_checks": sorted(BASE_CHECKS), + "checks": checks, + "stability_probe_count": len(test_runs), + "evidence_summary": evidence_summary, + "observed_at": observed_at.isoformat(), + "expires_at": (observed_at + timedelta(minutes=45)).isoformat(), + "signing_key_id": COLLECTOR_KEY_ID, + } + # Source subprocesses and their temporary checkout have finished before key access. + # This is the existing native owner signing operation, never worker-side key injection. + # Long test runs cannot refresh expired upstream evidence by issuing a new envelope. + verify_production_quench_evidence(quench_evidence_path, source_commit, + expected_sha256=args.quench_evidence_sha256) + key, key_id, public_pem = verify_private_key(args.private_key, repository, bundle, quench_evidence_path) + signature = key.sign(canonical_json(payload)) + envelope = { + "payload": payload, + "signature_b64": base64.b64encode(signature).decode("ascii"), + "key_id": key_id, + "public_key_pem": public_pem, + } + signed_digest = sha256_bytes( + canonical_json( + { + "payload": payload, + "signature_b64": envelope["signature_b64"], + "key_id": key_id, + } + ) + ) + report = { + "schema_version": REPORT_SCHEMA, + "collector_host": "HAMMER", + "target_host": "QUENCH", + "repository": REPOSITORY, + "branch": BRANCH, + "base_commit": base_commit, + "source_commit": source_commit, + "target_identity_digest": target_digest, + "environment_identity_digest": environment_digest, + "collector_key_id": key_id, + "attestation_envelope_sha256": signed_digest, + "bundle_sha256": evidence_summary["bundle_sha256"], + "hosted_receipt": hosted, + "quench_evidence": quench, + "hammer_test_iterations": len(test_runs), + "hammer_assertions_passed_per_iteration": evidence_summary["hammer_assertions_passed_per_iteration"], + "hammer_critical_journeys": journey_runs, + "gitleaks_exact_tree_hammer": "PASS", + "private_key_exported": False, + "signed_evidence_summary_sha256": sha256_bytes(canonical_json(evidence_summary)), + "checks": {name: "PASS" if passed else "FAIL" for name, passed in checks.items()}, + "installation_scope": quench["installation_scope"], + "completed_at": datetime.now(UTC).isoformat(), + } + + atomic_write(args.output, json.dumps(envelope, indent=2, sort_keys=True).encode() + b"\n") + atomic_write(args.public_key_output, public_pem.encode("ascii")) + atomic_write(args.report_output, json.dumps(report, indent=2, sort_keys=True).encode() + b"\n") + print( + json.dumps( + { + "result": "ATTESTATION_READY", + "collector_key_id": key_id, + "source_commit": source_commit, + "tests_per_iteration": 91, + "stability_probe_count": len(test_runs), + "live_canaries_bound": quench["live_canaries"], + "attestation_envelope_sha256": signed_digest, + }, + sort_keys=True, + ) + ) + return 0 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except (AttestationError, OSError, subprocess.SubprocessError, ValueError) as exc: + print(json.dumps({"result": "NOT_READY", "error": str(exc)}, sort_keys=True)) + raise SystemExit(1) diff --git a/tests/test_hammer_account_bridge_attestor.py b/tests/test_hammer_account_bridge_attestor.py new file mode 100644 index 0000000..edfc49c --- /dev/null +++ b/tests/test_hammer_account_bridge_attestor.py @@ -0,0 +1,309 @@ +"""Acceptance regressions use synthetic evidence; no production key or target runs.""" +import copy +import hashlib +import importlib.util +import json +import subprocess +from datetime import UTC, datetime, timedelta +from pathlib import Path +from types import SimpleNamespace + +import pytest + +SPEC = importlib.util.spec_from_file_location( + "acb_attestor", Path(__file__).resolve().parents[1] / "scripts/hammer_account_bridge_attestor.py") +collector = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(collector) +SOURCE = "def1828001c354bcf89f7d32bc987d6eba520cb6" +ASSERTIONS = { + "repository_policy": 8, "account_continuity_core": 6, + "provider_auth_monitor": 18, "provider_content_import": 9, + "multiprovider_mcp": 35, "account_continuity_bridge": 22, "provider_registry": 21, +} + + +def current_evidence(): + observed = datetime.now(UTC).isoformat() + concurrency = {"ok": True, "concurrent_requests": 12, "concurrent_processes": 8, + "contended_lock_preserved": True} + return { + "schema_version": "echo.account-continuity.quench-evidence.v2", + "host": "QUENCH", "observed_at": observed, + "source_commit": SOURCE, "installed_cache_commit": SOURCE, + "remote_branch_commit": SOURCE, "pull_request_head_commit": SOURCE, + "pull_request": 4, "branch": "agent/grok47-provider-recovery-20261003", + "installed_version": "1.1.0+codex.20261003120504", + "installation_scope": "production", "installed_manifest_sha256": "a" * 64, + "native_plugin_enabled": True, "fresh_native_session": True, + "iterations": 3, "assertions_passed_per_iteration": [119, 119, 119], + "critical_journeys": ["PASS", "PASS", "PASS"], + "test_runs": [{"iteration": n, "source_commit": SOURCE, "total": 119, + "assertions": dict(ASSERTIONS), "critical_journey": "PASS", + "router_concurrency": dict(concurrency), "observed_at": observed} + for n in range(1, 4)], + "live_runs": [{"exact_canary_match": True, "selected_provider": "forge-qwen", + "selected_outcome": "success", "provenance": "LIVE_PROVIDER_BRIDGE", + "credential_copied_or_exposed": False, "canary_sha256": str(n) * 64, + "response_sha256": str(n) * 64, "observed_at": observed, + "session_id": f"synthetic-native-session-{n}", "model": "fixture-model", + "source_commit": SOURCE, "governance": "PASS"} + for n in range(1, 4)], + "status_runs": [{"status_nonspending": True, + "server_name": "account_continuity_multiprovider_mcp", + "server_version": "0.5.0", "provider_count": 7, "tool_count": 17, + "observed_at": observed, "source_commit": SOURCE} for _ in range(3)], + "gitleaks_exact_tree": "PASS", "codex_mcp_config": "ok", + "private_key_exported": False, "credentials_in_evidence": False, + } + + +def verify(tmp_path, document): + path = tmp_path / "synthetic-evidence.json" + path.write_text(json.dumps(document), encoding="utf-8") + return collector.verify_quench_evidence(path, SOURCE) + + +def test_current_exact_installed_release_acceptance_is_supported(tmp_path): + result = verify(tmp_path, current_evidence()) + assert result["assertions_passed_per_iteration"] == [119, 119, 119] + assert result["live_canaries"] == 3 + assert result["installation_scope"] == "production" + + +def test_isolated_native_install_scope_is_preserved_not_promoted(tmp_path): + document = current_evidence() + document["installation_scope"] = "isolated_canary" + assert verify(tmp_path, document)["installation_scope"] == "isolated_canary" + + +def prepare_main_fixture(tmp_path, monkeypatch, *, scope): + document = current_evidence() + document["installation_scope"] = scope + evidence = tmp_path / "quench.json" + evidence.write_text(json.dumps(document), encoding="utf-8") + evidence_bytes = evidence.read_bytes() + workspace = tmp_path / "workspace" + workspace.mkdir() + placeholder = tmp_path / "placeholder" + placeholder.write_text("synthetic path only", encoding="utf-8") + outputs = [tmp_path / name for name in ("envelope.json", "public.pem", "report.json")] + args = SimpleNamespace( + source_commit=SOURCE, base_commit="1" * 40, + target_identity_digest="2" * 64, environment_identity_digest="3" * 64, + bundle=placeholder, python=placeholder, pwsh=placeholder, node=placeholder, + gitleaks=placeholder, workspace_root=workspace, quench_evidence=evidence, + quench_evidence_sha256=hashlib.sha256(evidence_bytes).hexdigest(), + private_key=tmp_path / "unavailable-owner-key.pem", revision_receipt=placeholder, + revision_receipt_sha256="4" * 64, hosted_delivery_id="synthetic-delivery", + quench_address="127.0.0.1", quench_management_port=1, + output=outputs[0], public_key_output=outputs[1], report_output=outputs[2]) + monkeypatch.setattr(collector, "parse_args", lambda: args) + monkeypatch.setattr(collector.socket, "gethostname", lambda: "HAMMER") + return args, evidence_bytes + + +def test_isolated_canary_cannot_reach_production_collection_or_signing(tmp_path, monkeypatch): + args, evidence_bytes = prepare_main_fixture(tmp_path, monkeypatch, scope="isolated_canary") + + def forbidden(*args, **kwargs): + pytest.fail("isolated canary reached a production collection/signing side effect") + + for name in ("verify_hosted_receipt", "verify_quench_reachability", "run", + "verify_private_key", "atomic_write"): + monkeypatch.setattr(collector, name, forbidden) + with pytest.raises(collector.AttestationError, match="production installation.*isolated_canary"): + collector.main() + assert args.quench_evidence.read_bytes() == evidence_bytes + assert all(not path.exists() for path in (args.output, args.public_key_output, args.report_output)) + assert not list(args.workspace_root.iterdir()) + + +def test_long_source_validation_cannot_refresh_expired_acceptance_before_signing(tmp_path, monkeypatch): + args, evidence_bytes = prepare_main_fixture(tmp_path, monkeypatch, scope="production") + elapsed = timedelta() + + class SimulatedClock(datetime): + @classmethod + def now(cls, tz=None): + return datetime.now(tz) + elapsed + + monkeypatch.setattr(collector, "datetime", SimulatedClock) + monkeypatch.setattr(collector, "verify_quench_reachability", lambda *args: None) + monkeypatch.setattr(collector, "verify_hosted_receipt", lambda *args, **kwargs: { + "document_sha256": "4" * 64, "receipt_hash": "5" * 64, + "delivery_id": "synthetic-delivery", "check_run": 1}) + journeys = [] + + def synthetic_run(command, **kwargs): + nonlocal elapsed + stdout = "" + if "rev-parse" in command: + stdout = SOURCE + elif "list-heads" in command: + stdout = f"{SOURCE} refs/heads/{collector.BRANCH}" + elif "-File" in command: + label = next(label for label, relative in collector.POWERSHELL_TESTS.items() + if command[-1].replace("\\", "/").endswith(relative)) + stdout = json.dumps({"ok": True, "assertions": ASSERTIONS[label]}) + elif command[-1].endswith("Test-ProviderRegistry.mjs"): + stdout = json.dumps({"ok": True, "assertions": ASSERTIONS["provider_registry"]}) + elif command[-1].endswith("Test-RouterConcurrency.mjs"): + stdout = json.dumps({"ok": True, "concurrent_requests": 12, + "concurrent_processes": 8, "contended_lock_preserved": True}) + elif command[-1].endswith("certforge_journey.py"): + journeys.append("PASS") + stdout = "ACCOUNT_CONTINUITY_CRITICAL_JOURNEY_OK surfaces=26 apps=8 providers=7 secret_fields=0" + elif "dir" in command: + elapsed = timedelta(hours=2) + return subprocess.CompletedProcess(command, 0, stdout, "") + + monkeypatch.setattr(collector, "run", synthetic_run) + + def forbidden(*args, **kwargs): + pytest.fail("expired upstream evidence reached key access or signed output") + + monkeypatch.setattr(collector, "verify_private_key", forbidden) + monkeypatch.setattr(collector, "atomic_write", forbidden) + with pytest.raises(collector.AttestationError, match="current and timezone-aware"): + collector.main() + assert journeys == ["PASS"] * 3 + assert args.quench_evidence.read_bytes() == evidence_bytes + assert all(not path.exists() for path in (args.output, args.public_key_output, args.report_output)) + assert not list(args.workspace_root.iterdir()) + + +def test_workspace_without_native_installation_is_not_acceptance(tmp_path): + document = current_evidence() + document["installation_scope"] = "workspace" + with pytest.raises(collector.AttestationError, match="scope"): + verify(tmp_path, document) + + +def test_journey_surface_count_cannot_substitute_for_native_tool_inventory(tmp_path): + document = current_evidence() + document["status_runs"][0]["tool_count"] = 26 + with pytest.raises(collector.AttestationError, match="surface"): + verify(tmp_path, document) + + +@pytest.mark.parametrize("field", ["source_commit", "installed_cache_commit", + "remote_branch_commit", "pull_request_head_commit"]) +def test_each_identity_substitution_fails_closed(tmp_path, field): + document = current_evidence() + document[field] = "0" * 40 + with pytest.raises(collector.AttestationError, match="exact-source"): + verify(tmp_path, document) + + +@pytest.mark.parametrize("field,value", [("installed_version", "old"), ("pull_request", 2), + ("branch", "agent/old"), ("native_plugin_enabled", False), + ("fresh_native_session", False)]) +def test_uninstalled_or_wrong_native_release_is_rejected(tmp_path, field, value): + document = current_evidence() + document[field] = value + with pytest.raises(collector.AttestationError): + verify(tmp_path, document) + + +def test_duplicate_canary_cannot_count_as_three_runs(tmp_path): + document = current_evidence() + document["live_runs"] = [copy.deepcopy(document["live_runs"][0]) for _ in range(3)] + with pytest.raises(collector.AttestationError, match="distinct"): + verify(tmp_path, document) + + +@pytest.mark.parametrize("field,value", [("exact_canary_match", False), + ("selected_provider", "fixture"), ("provenance", "MIRRORED"), + ("governance", "UNKNOWN"), ("source_commit", "0" * 40), + ("credential_copied_or_exposed", True), ("response_sha256", "f" * 64)]) +def test_missing_real_canary_acceptance_cannot_pass(tmp_path, field, value): + document = current_evidence() + document["live_runs"][1][field] = value + with pytest.raises(collector.AttestationError): + verify(tmp_path, document) + + +def test_stale_and_naive_evidence_time_rejected(tmp_path): + for observed in ((datetime.now(UTC) - timedelta(hours=2)).isoformat(), "2026-10-03T10:00:00"): + document = current_evidence() + document["observed_at"] = observed + with pytest.raises(collector.AttestationError, match="current"): + verify(tmp_path, document) + + +def test_failed_router_negative_control_rejected(tmp_path): + document = current_evidence() + document["test_runs"][1]["router_concurrency"]["contended_lock_preserved"] = False + with pytest.raises(collector.AttestationError, match="router"): + verify(tmp_path, document) + + +def test_one_missing_assertion_is_not_relabelled_pass(tmp_path): + document = current_evidence() + document["test_runs"][2]["assertions"]["provider_auth_monitor"] = 17 + with pytest.raises(collector.AttestationError, match="assertions"): + verify(tmp_path, document) + + +def test_ok_flag_cannot_hide_failed_named_assertion(): + result = subprocess.CompletedProcess(["fixture"], 0, + json.dumps({"ok": True, "assertions": {"negative_control": False}}), "") + with pytest.raises(collector.AttestationError, match="assertion"): + collector.parse_test_json(result, "fixture") + + +def test_zero_or_boolean_count_is_not_execution_evidence(): + for assertions in (0, -1, True, {}): + result = subprocess.CompletedProcess(["fixture"], 0, + json.dumps({"ok": True, "assertions": assertions}), "") + with pytest.raises(collector.AttestationError, match="assertion"): + collector.parse_test_json(result, "fixture") + + +@pytest.mark.parametrize("stdout", ["not json", "[]", "{}", + '{"ok":true,"concurrent_requests":12,"concurrent_processes":8,"contended_lock_preserved":false}']) +def test_router_command_requires_real_success_and_negative_control(stdout): + with pytest.raises(collector.AttestationError, match="router"): + collector.read_router_command(subprocess.CompletedProcess(["fixture"], 0, stdout, "")) + + +def test_evidence_write_does_not_replace_an_existing_owner_file(tmp_path): + destination = tmp_path / "receipt.json" + destination.write_bytes(b"existing owner evidence") + with pytest.raises(FileExistsError): + collector.atomic_write(destination, b"replacement") + assert destination.read_bytes() == b"existing owner evidence" + assert sorted(p.name for p in tmp_path.iterdir()) == ["receipt.json"] + + +def test_evidence_write_is_complete_and_removes_temporary_file(tmp_path): + destination = tmp_path / "receipt.json" + collector.atomic_write(destination, b"complete evidence") + assert destination.read_bytes() == b"complete evidence" + assert sorted(p.name for p in tmp_path.iterdir()) == ["receipt.json"] + + +def test_owner_evidence_pin_rejects_changed_bytes(tmp_path): + path = tmp_path / "evidence.json" + path.write_text('{"host":"QUENCH"}') + with pytest.raises(collector.AttestationError, match="custody"): + collector.read_json(path, expected_sha256="0" * 64) + + +def test_parse_and_custody_hash_use_one_byte_snapshot(tmp_path, monkeypatch): + path = tmp_path / "evidence.json" + original = b'{"host":"QUENCH"}' + path.write_bytes(original) + expected = hashlib.sha256(original).hexdigest() + real_read = Path.read_bytes + + def replace_after_read(selected): + data = real_read(selected) + if selected == path: + path.write_bytes(b'{"host":"changed-after-read"}') + return data + + monkeypatch.setattr(Path, "read_bytes", replace_after_read) + document, digest = collector.read_json(path, expected_sha256=expected) + assert document == {"host": "QUENCH"} + assert digest == expected From bf02be6624f99704a4f17e626f721201f7567ed1 Mon Sep 17 00:00:00 2001 From: ECHO OMEGA PRIME Date: Sat, 3 Oct 2026 14:21:43 -0500 Subject: [PATCH 2/5] Bind repaired ACB candidate and six Windows rename controls --- docs/ACCOUNT_CONTINUITY_COLLECTOR.md | 44 +++++++++++---- scripts/hammer_account_bridge_attestor.py | 45 ++++++++++++++-- tests/test_hammer_account_bridge_attestor.py | 57 +++++++++++++++++++- 3 files changed, 130 insertions(+), 16 deletions(-) diff --git a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md index cb26729..cda376d 100644 --- a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md +++ b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md @@ -1,16 +1,20 @@ # Account Continuity Bridge production acceptance collector `scripts/hammer_account_bridge_attestor.py` is an operator collector for the reviewed -ACB candidate `def1828001c354bcf89f7d32bc987d6eba520cb6`, PR 4, branch +ACB candidate `d410c61f11b5e15b30c9e2629f75838e38b5dc1c`, PR 4, branch `agent/grok47-provider-recovery-20261003`, plugin version -`1.1.0+codex.20261003120504`. It is not a subscriber endpoint or a generic signer. +`1.1.0+codex.20261003191426`. It is not a subscriber endpoint or a generic signer. Changing the candidate requires source review and new evidence. Policy, trust roots and target source are not changed by this collector. -This is held diagnostic source. The pinned candidate subsequently failed a real -installed Windows router-state rename stability pass. It is not eligible for -production signing; a repaired candidate requires a separately reviewed pin -update and fresh measured acceptance. The hosted App receipt was also unavailable +This is held diagnostic source. Previous candidate `def1828` failed a real +installed Windows router-state rename stability pass; `9f6e1b4` then exposed an +overlong Windows reader test fixture, and `6e92def` exposed loss of timestamp +text fidelity in provider-auth state. The current reviewed successor retains +the bounded product retry, synchronizes that fixture and preserves state values. +Its exact identity pin +is not proof of passing installation or production acceptance: all current +measured evidence remains mandatory. The hosted App receipt was unavailable during preparation because its owner service was stopped. No signing or deployment was performed by this source-publication task. @@ -31,9 +35,10 @@ The first review used deployed CertForge base `591d1ba6524c4858f63dfab21fe690e4d5a10521`. Publication transfers only this collector, its tests and this document onto canonical `main` base `4f7d99e2dd4422f3d81cf5b709581be963f5818a`, preserving unrelated main and deployed -history. The Python collector and test bytes remain identical to the independently -reviewed source; only this provenance/hold documentation is extended. The collector -is standalone and uses the existing `cryptography` dependency. It does not import +history. The initial transfer preserved the independently reviewed Python and test +bytes; a separate follow-up binds the repaired ACB candidate and requires all six +Windows atomic-rename controls on both hosts. The collector is standalone and uses +the existing `cryptography` dependency. It does not import or install the deployed consumer changes absent from that main base. Operational use still requires a separately verified strict production-E2E consumer and trust admission; this source-only PR does not establish either. @@ -54,7 +59,8 @@ fields by assertion or copy the synthetic test fixtures into operational evidenc The collector verifies a transferred Git bundle, exact head, branch, ancestry and clean checkout. It runs three independent passes of 91 HAMMER-safe assertions, -three router concurrency/lock negative controls, and three critical journeys. +three router concurrency/lock negative controls, three Windows atomic-rename +control passes, and three critical journeys. DPAPI-dependent core/bridge assertions must pass on QUENCH's real native install; they are explicitly not represented as executed on HAMMER. The complete QUENCH suite has 119 named assertions. Secret scanning must pass on both hosts. @@ -80,7 +86,7 @@ The JSON object schema is `echo.account-continuity.quench-evidence.v2`: | `installed_manifest_sha256` | Hash of the measured installed file manifest whose files were compared to the candidate | | `native_plugin_enabled`, `fresh_native_session` | Both verified true through actual native plugin/session readback | | `iterations`, `assertions_passed_per_iteration`, `critical_journeys` | 3, `[119,119,119]`, three actual `PASS` results | -| `test_runs` | Three rows: numbered `iteration`, actual `observed_at`, exact `source_commit`, `total=119`, complete suite counts, `critical_journey=PASS`, and real `router_concurrency` output | +| `test_runs` | Three rows: numbered `iteration`, actual `observed_at`, exact `source_commit`, `total=119`, complete suite counts, `critical_journey=PASS`, and real `router_concurrency` plus `atomic_rename` outputs | | `live_runs` | Three distinct nonce/session rows from actual installed bridge execution, as described below | | `status_runs` | Three actual non-spending installed MCP observations with time/source binding | | `gitleaks_exact_tree`, `codex_mcp_config` | Actual `PASS` exact-tree scan and `ok` native MCP config readback | @@ -95,6 +101,22 @@ Every router row must be the real `Test-RouterConcurrency.mjs` result: `contended_lock_preserved=true`. This is additional acceptance, not included in the 119 named assertions. +Each `atomic_rename` row must be the actual JSON from +`node tests/Test-RouterAtomicRename.mjs`: `ok=true`, `platform=win32`, and exactly +these six named `assertions`, each strictly true: + +- `actual_windows_reader_recovers_without_target_delete` +- `EPERM_has_expected_platform_retry_boundary` +- `EACCES_has_expected_platform_retry_boundary` +- `EBUSY_has_expected_platform_retry_boundary` +- `EIO_has_expected_platform_retry_boundary` +- `persistent_failure_is_bounded_and_preserves_previous_state` + +These are six additional controls per pass, separate from the 119 base assertions. +The actual Windows file-handle case is required on both QUENCH and HAMMER; a +non-Windows result containing only five controls cannot substitute. The collector +runs this command on HAMMER and includes each complete result in its evidence. + Every live row requires `exact_canary_match=true`, `selected_provider=forge-qwen`, `selected_outcome=success`, `provenance=LIVE_PROVIDER_BRIDGE`, `credential_copied_or_exposed=false`, equal valid `canary_sha256` and diff --git a/scripts/hammer_account_bridge_attestor.py b/scripts/hammer_account_bridge_attestor.py index faac463..aa837ee 100644 --- a/scripts/hammer_account_bridge_attestor.py +++ b/scripts/hammer_account_bridge_attestor.py @@ -25,8 +25,8 @@ PROFILE = "generic-production-v1" REPOSITORY = "echoomegaprime/account-continuity-bridge" BRANCH = "agent/grok47-provider-recovery-20261003" -SOURCE_COMMIT = "def1828001c354bcf89f7d32bc987d6eba520cb6" -PLUGIN_VERSION = "1.1.0+codex.20261003120504" +SOURCE_COMMIT = "d410c61f11b5e15b30c9e2629f75838e38b5dc1c" +PLUGIN_VERSION = "1.1.0+codex.20261003191426" PULL_REQUEST = 4 COLLECTOR_KEY_ID = "ed25519:59de9be507b39b291ee13c4a57378ec6" BASE_CHECKS = frozenset( @@ -62,6 +62,14 @@ "account_continuity_core": EXPECTED_ASSERTIONS["account_continuity_core"], "account_continuity_bridge": EXPECTED_ASSERTIONS["account_continuity_bridge"], } +ATOMIC_RENAME_CONTROLS = frozenset({ + "actual_windows_reader_recovers_without_target_delete", + "EPERM_has_expected_platform_retry_boundary", + "EACCES_has_expected_platform_retry_boundary", + "EBUSY_has_expected_platform_retry_boundary", + "EIO_has_expected_platform_retry_boundary", + "persistent_failure_is_bounded_and_preserves_previous_state", +}) SHA40 = re.compile(r"^[0-9a-f]{40}$") SHA256 = re.compile(r"^[0-9a-f]{64}$") @@ -228,6 +236,7 @@ def verify_quench_evidence(path: Path, source_commit: str, *, expected_sha256: s if row.get("critical_journey") != "PASS" or row.get("assertions") != EXPECTED_ASSERTIONS: raise AttestationError("QUENCH detailed assertions are invalid") verify_router_result(row.get("router_concurrency")) + verify_atomic_rename_result(row.get("atomic_rename")) live_runs = document.get("live_runs") if not isinstance(live_runs, list) or len(live_runs) != 3: raise AttestationError("QUENCH live canary evidence is invalid") @@ -288,6 +297,7 @@ def verify_quench_evidence(path: Path, source_commit: str, *, expected_sha256: s "critical_journeys": document["critical_journeys"], "live_canaries": len(live_runs), "status_probes": len(status_runs), + "atomic_rename_controls_per_iteration": len(ATOMIC_RENAME_CONTROLS), "tool_count": status_runs[0]["tool_count"], "provider_count": status_runs[0]["provider_count"], "selected_provider": "forge-qwen", @@ -331,6 +341,24 @@ def read_router_command(completed: subprocess.CompletedProcess[str]) -> dict[str return value +def verify_atomic_rename_result(value: Any) -> None: + if not isinstance(value, dict) or value.get("ok") is not True or value.get("platform") != "win32": + raise AttestationError("Windows atomic rename acceptance is incomplete") + assertions = value.get("assertions") + if (not isinstance(assertions, dict) or set(assertions) != ATOMIC_RENAME_CONTROLS + or any(passed is not True for passed in assertions.values())): + raise AttestationError("Windows atomic rename controls are incomplete or failed") + + +def read_atomic_rename_command(completed: subprocess.CompletedProcess[str]) -> dict[str, Any]: + try: + value = json.loads(completed.stdout) + except json.JSONDecodeError as exc: + raise AttestationError("atomic rename command did not return JSON") from exc + verify_atomic_rename_result(value) + return value + + def verify_private_key( path: Path, repository: Path, @@ -485,6 +513,7 @@ def main() -> int: test_runs: list[dict[str, int]] = [] journey_runs: list[str] = [] router_runs: list[dict[str, Any]] = [] + atomic_rename_runs: list[dict[str, Any]] = [] with tempfile.TemporaryDirectory(prefix="acb-attest-", dir=workspace_root) as temporary: root = Path(temporary) repository = root / "repo" @@ -532,6 +561,9 @@ def main() -> int: [str(node), str(repository / "tests/Test-RouterConcurrency.mjs")], cwd=repository, env=environment)) router_runs.append(router_result) + atomic_rename_runs.append(read_atomic_rename_command(run( + [str(node), str(repository / "tests/Test-RouterAtomicRename.mjs")], + cwd=repository, env=environment))) test_runs.append(counts) journey = run( [str(python), "-B", str(repository / "scripts/certforge_journey.py")], @@ -560,6 +592,8 @@ def main() -> int: "installation_scope": quench["installation_scope"], "installed_manifest_sha256": quench["installed_manifest_sha256"], "hammer_router_concurrency": router_runs, + "hammer_atomic_rename": atomic_rename_runs, + "quench_atomic_rename_controls_per_iteration": quench["atomic_rename_controls_per_iteration"], "hammer_test_iterations": len(test_runs), "hammer_assertions_passed_per_iteration": [sum(row.values()) for row in test_runs], "hammer_assertion_detail": test_runs, @@ -583,7 +617,12 @@ def main() -> int: "runtime_or_artifact_executed": len(test_runs) == 3, "exact_identity_readback": head == source_commit == SOURCE_COMMIT, "critical_journeys_complete": journey_runs == ["PASS"] * 3, - "negative_controls_pass": len(router_runs) == 3 and all(row["contended_lock_preserved"] is True for row in router_runs), + "negative_controls_pass": (len(router_runs) == 3 + and all(row["contended_lock_preserved"] is True for row in router_runs) + and len(atomic_rename_runs) == 3 + and all(set(row["assertions"]) == ATOMIC_RENAME_CONTROLS + and all(passed is True for passed in row["assertions"].values()) + for row in atomic_rename_runs)), "stability_verified": test_runs == [HAMMER_EXPECTED_ASSERTIONS] * 3, "external_acceptance_verified": quench["live_canaries"] == 3 and quench["status_probes"] == 3, } diff --git a/tests/test_hammer_account_bridge_attestor.py b/tests/test_hammer_account_bridge_attestor.py index edfc49c..b230e08 100644 --- a/tests/test_hammer_account_bridge_attestor.py +++ b/tests/test_hammer_account_bridge_attestor.py @@ -14,12 +14,25 @@ "acb_attestor", Path(__file__).resolve().parents[1] / "scripts/hammer_account_bridge_attestor.py") collector = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(collector) -SOURCE = "def1828001c354bcf89f7d32bc987d6eba520cb6" +SOURCE = "d410c61f11b5e15b30c9e2629f75838e38b5dc1c" ASSERTIONS = { "repository_policy": 8, "account_continuity_core": 6, "provider_auth_monitor": 18, "provider_content_import": 9, "multiprovider_mcp": 35, "account_continuity_bridge": 22, "provider_registry": 21, } +ATOMIC_CONTROLS = { + "actual_windows_reader_recovers_without_target_delete", + "EPERM_has_expected_platform_retry_boundary", + "EACCES_has_expected_platform_retry_boundary", + "EBUSY_has_expected_platform_retry_boundary", + "EIO_has_expected_platform_retry_boundary", + "persistent_failure_is_bounded_and_preserves_previous_state", +} + + +def atomic_rename_evidence(): + return {"ok": True, "platform": "win32", + "assertions": {name: True for name in sorted(ATOMIC_CONTROLS)}} def current_evidence(): @@ -32,13 +45,14 @@ def current_evidence(): "source_commit": SOURCE, "installed_cache_commit": SOURCE, "remote_branch_commit": SOURCE, "pull_request_head_commit": SOURCE, "pull_request": 4, "branch": "agent/grok47-provider-recovery-20261003", - "installed_version": "1.1.0+codex.20261003120504", + "installed_version": "1.1.0+codex.20261003191426", "installation_scope": "production", "installed_manifest_sha256": "a" * 64, "native_plugin_enabled": True, "fresh_native_session": True, "iterations": 3, "assertions_passed_per_iteration": [119, 119, 119], "critical_journeys": ["PASS", "PASS", "PASS"], "test_runs": [{"iteration": n, "source_commit": SOURCE, "total": 119, "assertions": dict(ASSERTIONS), "critical_journey": "PASS", + "atomic_rename": atomic_rename_evidence(), "router_concurrency": dict(concurrency), "observed_at": observed} for n in range(1, 4)], "live_runs": [{"exact_canary_match": True, "selected_provider": "forge-qwen", @@ -150,6 +164,8 @@ def synthetic_run(command, **kwargs): elif command[-1].endswith("Test-RouterConcurrency.mjs"): stdout = json.dumps({"ok": True, "concurrent_requests": 12, "concurrent_processes": 8, "contended_lock_preserved": True}) + elif command[-1].endswith("Test-RouterAtomicRename.mjs"): + stdout = json.dumps(atomic_rename_evidence()) elif command[-1].endswith("certforge_journey.py"): journeys.append("PASS") stdout = "ACCOUNT_CONTINUITY_CRITICAL_JOURNEY_OK surfaces=26 apps=8 providers=7 secret_fields=0" @@ -195,6 +211,17 @@ def test_each_identity_substitution_fails_closed(tmp_path, field): verify(tmp_path, document) +@pytest.mark.parametrize("old_sha", ["def1828001c354bcf89f7d32bc987d6eba520cb6", + "9f6e1b41cf548e62523baa020e3e1584610b704c", + "6e92def9758eaea61c145d4b5e2465ec08eee30d"]) +def test_superseded_installed_candidates_cannot_reuse_collector(tmp_path, old_sha): + evidence = current_evidence() + for field in ("source_commit", "installed_cache_commit", "remote_branch_commit", "pull_request_head_commit"): + evidence[field] = old_sha + with pytest.raises(collector.AttestationError, match="exact-source"): + verify(tmp_path, evidence) + + @pytest.mark.parametrize("field,value", [("installed_version", "old"), ("pull_request", 2), ("branch", "agent/old"), ("native_plugin_enabled", False), ("fresh_native_session", False)]) @@ -238,6 +265,24 @@ def test_failed_router_negative_control_rejected(tmp_path): verify(tmp_path, document) +@pytest.mark.parametrize("mutation", ["missing", "failed", "non_windows", "partial", "false_ok"]) +def test_atomic_rename_controls_require_real_complete_windows_acceptance(tmp_path, mutation): + document = current_evidence() + row = document["test_runs"][1] + if mutation == "missing": + row.pop("atomic_rename") + elif mutation == "failed": + row["atomic_rename"]["assertions"]["actual_windows_reader_recovers_without_target_delete"] = False + elif mutation == "non_windows": + row["atomic_rename"]["platform"] = "linux" + elif mutation == "partial": + row["atomic_rename"]["assertions"].pop("EIO_has_expected_platform_retry_boundary") + else: + row["atomic_rename"]["ok"] = False + with pytest.raises(collector.AttestationError, match="atomic rename"): + verify(tmp_path, document) + + def test_one_missing_assertion_is_not_relabelled_pass(tmp_path): document = current_evidence() document["test_runs"][2]["assertions"]["provider_auth_monitor"] = 17 @@ -267,6 +312,14 @@ def test_router_command_requires_real_success_and_negative_control(stdout): collector.read_router_command(subprocess.CompletedProcess(["fixture"], 0, stdout, "")) +@pytest.mark.parametrize("stdout", ["not json", "[]", "{}", + '{"ok":true,"platform":"win32","assertions":6}', + '{"ok":true,"platform":"linux","assertions":{}}']) +def test_atomic_rename_command_requires_all_real_windows_controls(stdout): + with pytest.raises(collector.AttestationError, match="atomic rename"): + collector.read_atomic_rename_command(subprocess.CompletedProcess(["fixture"], 0, stdout, "")) + + def test_evidence_write_does_not_replace_an_existing_owner_file(tmp_path): destination = tmp_path / "receipt.json" destination.write_bytes(b"existing owner evidence") From 25b9da443eb8fdd4744f48f8e2274ca29adffde8 Mon Sep 17 00:00:00 2001 From: ECHO OMEGA PRIME Date: Sat, 3 Oct 2026 14:54:42 -0500 Subject: [PATCH 3/5] Require measured Windows lock acquisition acceptance for ACB V6 --- docs/ACCOUNT_CONTINUITY_COLLECTOR.md | 43 ++++++++++++---- scripts/hammer_account_bridge_attestor.py | 43 ++++++++++++++-- tests/test_hammer_account_bridge_attestor.py | 53 ++++++++++++++++++-- 3 files changed, 122 insertions(+), 17 deletions(-) diff --git a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md index cda376d..34bac15 100644 --- a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md +++ b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md @@ -1,22 +1,26 @@ # Account Continuity Bridge production acceptance collector `scripts/hammer_account_bridge_attestor.py` is an operator collector for the reviewed -ACB candidate `d410c61f11b5e15b30c9e2629f75838e38b5dc1c`, PR 4, branch +ACB candidate `d9ffe76ad63b71545d5378f154e15af10e4f7a9e`, PR 4, branch `agent/grok47-provider-recovery-20261003`, plugin version -`1.1.0+codex.20261003191426`. It is not a subscriber endpoint or a generic signer. +`1.1.0+codex.20261003194149`. It is not a subscriber endpoint or a generic signer. Changing the candidate requires source review and new evidence. Policy, trust roots and target source are not changed by this collector. This is held diagnostic source. Previous candidate `def1828` failed a real installed Windows router-state rename stability pass; `9f6e1b4` then exposed an overlong Windows reader test fixture, and `6e92def` exposed loss of timestamp -text fidelity in provider-auth state. The current reviewed successor retains -the bounded product retry, synchronizes that fixture and preserves state values. +text fidelity in provider-auth state. Candidate `d410c61` then lost case-distinct +JSON keys, and `85e6885` exposed a separate Windows sharing error during router +lock acquisition. The current reviewed successor preserves case-sensitive state +keys and retries lock acquisition within its existing bounded deadline, while +retaining the prior atomic-rename bound and synchronized reader fixture. Its exact identity pin is not proof of passing installation or production acceptance: all current -measured evidence remains mandatory. The hosted App receipt was unavailable -during preparation because its owner service was stopped. No signing or deployment -was performed by this source-publication task. +measured evidence remains mandatory. The hosted App service was initially stopped; +its separately recovered loopback service still does not establish an authentic +exact-candidate webhook receipt. No signing or deployment was performed by this +source-publication task. ## Source provenance @@ -37,7 +41,8 @@ its tests and this document onto canonical `main` base `4f7d99e2dd4422f3d81cf5b709581be963f5818a`, preserving unrelated main and deployed history. The initial transfer preserved the independently reviewed Python and test bytes; a separate follow-up binds the repaired ACB candidate and requires all six -Windows atomic-rename controls on both hosts. The collector is standalone and uses +Windows atomic-rename controls and five lock-acquisition controls on both hosts. +The collector is standalone and uses the existing `cryptography` dependency. It does not import or install the deployed consumer changes absent from that main base. Operational use still requires a separately verified strict production-E2E consumer and trust @@ -60,7 +65,7 @@ fields by assertion or copy the synthetic test fixtures into operational evidenc The collector verifies a transferred Git bundle, exact head, branch, ancestry and clean checkout. It runs three independent passes of 91 HAMMER-safe assertions, three router concurrency/lock negative controls, three Windows atomic-rename -control passes, and three critical journeys. +control passes, three Windows lock-acquisition control passes, and three critical journeys. DPAPI-dependent core/bridge assertions must pass on QUENCH's real native install; they are explicitly not represented as executed on HAMMER. The complete QUENCH suite has 119 named assertions. Secret scanning must pass on both hosts. @@ -86,7 +91,7 @@ The JSON object schema is `echo.account-continuity.quench-evidence.v2`: | `installed_manifest_sha256` | Hash of the measured installed file manifest whose files were compared to the candidate | | `native_plugin_enabled`, `fresh_native_session` | Both verified true through actual native plugin/session readback | | `iterations`, `assertions_passed_per_iteration`, `critical_journeys` | 3, `[119,119,119]`, three actual `PASS` results | -| `test_runs` | Three rows: numbered `iteration`, actual `observed_at`, exact `source_commit`, `total=119`, complete suite counts, `critical_journey=PASS`, and real `router_concurrency` plus `atomic_rename` outputs | +| `test_runs` | Three rows: numbered `iteration`, actual `observed_at`, exact `source_commit`, `total=119`, complete suite counts, `critical_journey=PASS`, and real `router_concurrency`, `atomic_rename`, and `router_lock_acquisition` outputs | | `live_runs` | Three distinct nonce/session rows from actual installed bridge execution, as described below | | `status_runs` | Three actual non-spending installed MCP observations with time/source binding | | `gitleaks_exact_tree`, `codex_mcp_config` | Actual `PASS` exact-tree scan and `ok` native MCP config readback | @@ -117,6 +122,22 @@ The actual Windows file-handle case is required on both QUENCH and HAMMER; a non-Windows result containing only five controls cannot substitute. The collector runs this command on HAMMER and includes each complete result in its evidence. +Each `router_lock_acquisition` row must be the actual JSON from +`node tests/Test-RouterLockAcquisition.mjs`: `ok=true`, `platform=win32`, and +exactly these five named `assertions`, each strictly true: + +- `EPERM_acquisition_has_expected_platform_retry_boundary` +- `EACCES_acquisition_has_expected_platform_retry_boundary` +- `EBUSY_acquisition_has_expected_platform_retry_boundary` +- `EIO_acquisition_has_expected_platform_retry_boundary` +- `persistent_acquisition_failure_preserves_unowned_lock_and_state` + +These five controls are separate from the 119 base assertions and six rename +controls. The collector executes the command during each of its three HAMMER +passes, validates every result, and retains those complete outputs in the signed +evidence summary. No skipped or non-Windows control result substitutes for real +Windows execution on either host. + Every live row requires `exact_canary_match=true`, `selected_provider=forge-qwen`, `selected_outcome=success`, `provenance=LIVE_PROVIDER_BRIDGE`, `credential_copied_or_exposed=false`, equal valid `canary_sha256` and @@ -158,7 +179,7 @@ The standalone strict run alone does not supply this hosted-app receipt. ```powershell & '' scripts/hammer_account_bridge_attestor.py ` --bundle '' --base-commit '' ` - --source-commit def1828001c354bcf89f7d32bc987d6eba520cb6 ` + --source-commit d9ffe76ad63b71545d5378f154e15af10e4f7a9e ` --target-identity-digest '' ` --environment-identity-digest '' ` --revision-receipt '' --revision-receipt-sha256 '' ` diff --git a/scripts/hammer_account_bridge_attestor.py b/scripts/hammer_account_bridge_attestor.py index aa837ee..9747fef 100644 --- a/scripts/hammer_account_bridge_attestor.py +++ b/scripts/hammer_account_bridge_attestor.py @@ -25,8 +25,8 @@ PROFILE = "generic-production-v1" REPOSITORY = "echoomegaprime/account-continuity-bridge" BRANCH = "agent/grok47-provider-recovery-20261003" -SOURCE_COMMIT = "d410c61f11b5e15b30c9e2629f75838e38b5dc1c" -PLUGIN_VERSION = "1.1.0+codex.20261003191426" +SOURCE_COMMIT = "d9ffe76ad63b71545d5378f154e15af10e4f7a9e" +PLUGIN_VERSION = "1.1.0+codex.20261003194149" PULL_REQUEST = 4 COLLECTOR_KEY_ID = "ed25519:59de9be507b39b291ee13c4a57378ec6" BASE_CHECKS = frozenset( @@ -71,6 +71,13 @@ "persistent_failure_is_bounded_and_preserves_previous_state", }) SHA40 = re.compile(r"^[0-9a-f]{40}$") +LOCK_ACQUISITION_CONTROLS = frozenset({ + "EPERM_acquisition_has_expected_platform_retry_boundary", + "EACCES_acquisition_has_expected_platform_retry_boundary", + "EBUSY_acquisition_has_expected_platform_retry_boundary", + "EIO_acquisition_has_expected_platform_retry_boundary", + "persistent_acquisition_failure_preserves_unowned_lock_and_state", +}) SHA256 = re.compile(r"^[0-9a-f]{64}$") @@ -237,6 +244,7 @@ def verify_quench_evidence(path: Path, source_commit: str, *, expected_sha256: s raise AttestationError("QUENCH detailed assertions are invalid") verify_router_result(row.get("router_concurrency")) verify_atomic_rename_result(row.get("atomic_rename")) + verify_lock_acquisition_result(row.get("router_lock_acquisition")) live_runs = document.get("live_runs") if not isinstance(live_runs, list) or len(live_runs) != 3: raise AttestationError("QUENCH live canary evidence is invalid") @@ -298,6 +306,7 @@ def verify_quench_evidence(path: Path, source_commit: str, *, expected_sha256: s "live_canaries": len(live_runs), "status_probes": len(status_runs), "atomic_rename_controls_per_iteration": len(ATOMIC_RENAME_CONTROLS), + "router_lock_acquisition_controls_per_iteration": len(LOCK_ACQUISITION_CONTROLS), "tool_count": status_runs[0]["tool_count"], "provider_count": status_runs[0]["provider_count"], "selected_provider": "forge-qwen", @@ -359,6 +368,24 @@ def read_atomic_rename_command(completed: subprocess.CompletedProcess[str]) -> d return value +def verify_lock_acquisition_result(value: Any) -> None: + if not isinstance(value, dict) or value.get("ok") is not True or value.get("platform") != "win32": + raise AttestationError("Windows lock acquisition acceptance is incomplete") + assertions = value.get("assertions") + if (not isinstance(assertions, dict) or set(assertions) != LOCK_ACQUISITION_CONTROLS + or any(passed is not True for passed in assertions.values())): + raise AttestationError("Windows lock acquisition controls are incomplete or failed") + + +def read_lock_acquisition_command(completed: subprocess.CompletedProcess[str]) -> dict[str, Any]: + try: + value = json.loads(completed.stdout) + except json.JSONDecodeError as exc: + raise AttestationError("lock acquisition command did not return JSON") from exc + verify_lock_acquisition_result(value) + return value + + def verify_private_key( path: Path, repository: Path, @@ -514,6 +541,7 @@ def main() -> int: journey_runs: list[str] = [] router_runs: list[dict[str, Any]] = [] atomic_rename_runs: list[dict[str, Any]] = [] + lock_acquisition_runs: list[dict[str, Any]] = [] with tempfile.TemporaryDirectory(prefix="acb-attest-", dir=workspace_root) as temporary: root = Path(temporary) repository = root / "repo" @@ -564,6 +592,9 @@ def main() -> int: atomic_rename_runs.append(read_atomic_rename_command(run( [str(node), str(repository / "tests/Test-RouterAtomicRename.mjs")], cwd=repository, env=environment))) + lock_acquisition_runs.append(read_lock_acquisition_command(run( + [str(node), str(repository / "tests/Test-RouterLockAcquisition.mjs")], + cwd=repository, env=environment))) test_runs.append(counts) journey = run( [str(python), "-B", str(repository / "scripts/certforge_journey.py")], @@ -593,7 +624,9 @@ def main() -> int: "installed_manifest_sha256": quench["installed_manifest_sha256"], "hammer_router_concurrency": router_runs, "hammer_atomic_rename": atomic_rename_runs, + "hammer_router_lock_acquisition": lock_acquisition_runs, "quench_atomic_rename_controls_per_iteration": quench["atomic_rename_controls_per_iteration"], + "quench_router_lock_acquisition_controls_per_iteration": quench["router_lock_acquisition_controls_per_iteration"], "hammer_test_iterations": len(test_runs), "hammer_assertions_passed_per_iteration": [sum(row.values()) for row in test_runs], "hammer_assertion_detail": test_runs, @@ -622,7 +655,11 @@ def main() -> int: and len(atomic_rename_runs) == 3 and all(set(row["assertions"]) == ATOMIC_RENAME_CONTROLS and all(passed is True for passed in row["assertions"].values()) - for row in atomic_rename_runs)), + for row in atomic_rename_runs) + and len(lock_acquisition_runs) == 3 + and all(set(row["assertions"]) == LOCK_ACQUISITION_CONTROLS + and all(passed is True for passed in row["assertions"].values()) + for row in lock_acquisition_runs)), "stability_verified": test_runs == [HAMMER_EXPECTED_ASSERTIONS] * 3, "external_acceptance_verified": quench["live_canaries"] == 3 and quench["status_probes"] == 3, } diff --git a/tests/test_hammer_account_bridge_attestor.py b/tests/test_hammer_account_bridge_attestor.py index b230e08..b28bd05 100644 --- a/tests/test_hammer_account_bridge_attestor.py +++ b/tests/test_hammer_account_bridge_attestor.py @@ -14,7 +14,7 @@ "acb_attestor", Path(__file__).resolve().parents[1] / "scripts/hammer_account_bridge_attestor.py") collector = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(collector) -SOURCE = "d410c61f11b5e15b30c9e2629f75838e38b5dc1c" +SOURCE = "d9ffe76ad63b71545d5378f154e15af10e4f7a9e" ASSERTIONS = { "repository_policy": 8, "account_continuity_core": 6, "provider_auth_monitor": 18, "provider_content_import": 9, @@ -35,6 +35,16 @@ def atomic_rename_evidence(): "assertions": {name: True for name in sorted(ATOMIC_CONTROLS)}} +def lock_acquisition_evidence(): + return {"ok": True, "platform": "win32", "assertions": { + "EPERM_acquisition_has_expected_platform_retry_boundary": True, + "EACCES_acquisition_has_expected_platform_retry_boundary": True, + "EBUSY_acquisition_has_expected_platform_retry_boundary": True, + "EIO_acquisition_has_expected_platform_retry_boundary": True, + "persistent_acquisition_failure_preserves_unowned_lock_and_state": True, + }} + + def current_evidence(): observed = datetime.now(UTC).isoformat() concurrency = {"ok": True, "concurrent_requests": 12, "concurrent_processes": 8, @@ -45,7 +55,7 @@ def current_evidence(): "source_commit": SOURCE, "installed_cache_commit": SOURCE, "remote_branch_commit": SOURCE, "pull_request_head_commit": SOURCE, "pull_request": 4, "branch": "agent/grok47-provider-recovery-20261003", - "installed_version": "1.1.0+codex.20261003191426", + "installed_version": "1.1.0+codex.20261003194149", "installation_scope": "production", "installed_manifest_sha256": "a" * 64, "native_plugin_enabled": True, "fresh_native_session": True, "iterations": 3, "assertions_passed_per_iteration": [119, 119, 119], @@ -53,6 +63,7 @@ def current_evidence(): "test_runs": [{"iteration": n, "source_commit": SOURCE, "total": 119, "assertions": dict(ASSERTIONS), "critical_journey": "PASS", "atomic_rename": atomic_rename_evidence(), + "router_lock_acquisition": lock_acquisition_evidence(), "router_concurrency": dict(concurrency), "observed_at": observed} for n in range(1, 4)], "live_runs": [{"exact_canary_match": True, "selected_provider": "forge-qwen", @@ -147,6 +158,7 @@ def now(cls, tz=None): "document_sha256": "4" * 64, "receipt_hash": "5" * 64, "delivery_id": "synthetic-delivery", "check_run": 1}) journeys = [] + lock_commands = [] def synthetic_run(command, **kwargs): nonlocal elapsed @@ -166,6 +178,9 @@ def synthetic_run(command, **kwargs): "concurrent_processes": 8, "contended_lock_preserved": True}) elif command[-1].endswith("Test-RouterAtomicRename.mjs"): stdout = json.dumps(atomic_rename_evidence()) + elif command[-1].endswith("Test-RouterLockAcquisition.mjs"): + lock_commands.append(command) + stdout = json.dumps(lock_acquisition_evidence()) elif command[-1].endswith("certforge_journey.py"): journeys.append("PASS") stdout = "ACCOUNT_CONTINUITY_CRITICAL_JOURNEY_OK surfaces=26 apps=8 providers=7 secret_fields=0" @@ -183,6 +198,7 @@ def forbidden(*args, **kwargs): with pytest.raises(collector.AttestationError, match="current and timezone-aware"): collector.main() assert journeys == ["PASS"] * 3 + assert len(lock_commands) == 3 assert args.quench_evidence.read_bytes() == evidence_bytes assert all(not path.exists() for path in (args.output, args.public_key_output, args.report_output)) assert not list(args.workspace_root.iterdir()) @@ -213,7 +229,9 @@ def test_each_identity_substitution_fails_closed(tmp_path, field): @pytest.mark.parametrize("old_sha", ["def1828001c354bcf89f7d32bc987d6eba520cb6", "9f6e1b41cf548e62523baa020e3e1584610b704c", - "6e92def9758eaea61c145d4b5e2465ec08eee30d"]) + "6e92def9758eaea61c145d4b5e2465ec08eee30d", + "d410c61f11b5e15b30c9e2629f75838e38b5dc1c", + "85e6885a1dae1d663b1a7d6fc6ac8d3f53247f2d"]) def test_superseded_installed_candidates_cannot_reuse_collector(tmp_path, old_sha): evidence = current_evidence() for field in ("source_commit", "installed_cache_commit", "remote_branch_commit", "pull_request_head_commit"): @@ -290,6 +308,27 @@ def test_one_missing_assertion_is_not_relabelled_pass(tmp_path): verify(tmp_path, document) +@pytest.mark.parametrize("mutation", ["missing", "failed", "non_windows", "partial", "false_ok", "coerced"]) +def test_lock_acquisition_controls_require_complete_windows_acceptance(tmp_path, mutation): + document = current_evidence() + row = document["test_runs"][1] + control = "persistent_acquisition_failure_preserves_unowned_lock_and_state" + if mutation == "missing": + row.pop("router_lock_acquisition") + elif mutation == "failed": + row["router_lock_acquisition"]["assertions"][control] = False + elif mutation == "non_windows": + row["router_lock_acquisition"]["platform"] = "linux" + elif mutation == "partial": + row["router_lock_acquisition"]["assertions"].pop(control) + elif mutation == "false_ok": + row["router_lock_acquisition"]["ok"] = False + else: + row["router_lock_acquisition"]["assertions"][control] = 1 + with pytest.raises(collector.AttestationError, match="lock acquisition"): + verify(tmp_path, document) + + def test_ok_flag_cannot_hide_failed_named_assertion(): result = subprocess.CompletedProcess(["fixture"], 0, json.dumps({"ok": True, "assertions": {"negative_control": False}}), "") @@ -320,6 +359,14 @@ def test_atomic_rename_command_requires_all_real_windows_controls(stdout): collector.read_atomic_rename_command(subprocess.CompletedProcess(["fixture"], 0, stdout, "")) +@pytest.mark.parametrize("stdout", ["not json", "[]", "{}", + '{"ok":true,"platform":"win32","assertions":5}', + '{"ok":true,"platform":"linux","assertions":{}}']) +def test_lock_acquisition_command_requires_all_windows_controls(stdout): + with pytest.raises(collector.AttestationError, match="lock acquisition"): + collector.read_lock_acquisition_command(subprocess.CompletedProcess(["fixture"], 0, stdout, "")) + + def test_evidence_write_does_not_replace_an_existing_owner_file(tmp_path): destination = tmp_path / "receipt.json" destination.write_bytes(b"existing owner evidence") From 0f3c580771cfe370419306afb7f1cd0674113582 Mon Sep 17 00:00:00 2001 From: ECHO OMEGA PRIME Date: Sat, 3 Oct 2026 15:17:35 -0500 Subject: [PATCH 4/5] Link collector admission contract to exact deployed consumer --- docs/ACCOUNT_CONTINUITY_COLLECTOR.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md index 34bac15..3616e4c 100644 --- a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md +++ b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md @@ -196,6 +196,11 @@ The standalone strict run alone does not supply this hosted-app receipt. This command signs only after every real acceptance gate completes. Source tests do not execute it against production or existing keys. The operator separately verifies the returned signature and exact binding, then admits the envelope via -the root-owned atomic transfer described in `OPERATIONS.md`. The collector has -no remote admission/deployment code. A new idempotent strict run consumes fresh +the root-owned atomic transfer described in the separately deployed consumer's +[exact Operations contract](https://github.com/echoomegaprime/echo-certification-forge/blob/d8ad9fd881365801354b78a758632d2a31ab6828/docs/OPERATIONS.md#verification-sequence). +That reference specifies required custody semantics; it does not establish that +the current deployment satisfies them or grant a production-canary bootstrap +exception. This branch's own `OPERATIONS.md` does not contain that deployed +consumer section. The collector has no remote admission/deployment code. +A new idempotent strict run consumes fresh evidence; existing terminal runs and their signed verdicts remain unchanged. From 9160bcc04a33daf10839ae153a2ffe11fc5d7b81 Mon Sep 17 00:00:00 2001 From: Echo Omega Prime Date: Sun, 1 Nov 2026 21:51:07 -0600 Subject: [PATCH 5/5] Add exact E5 unsigned account bridge measurement recipe --- docs/ACCOUNT_CONTINUITY_COLLECTOR.md | 79 ++++++ scripts/hammer_account_bridge_attestor.py | 269 +++++++++++++++++++ tests/test_hammer_account_bridge_attestor.py | 200 ++++++++++++++ 3 files changed, 548 insertions(+) diff --git a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md index 3616e4c..83ea7f1 100644 --- a/docs/ACCOUNT_CONTINUITY_COLLECTOR.md +++ b/docs/ACCOUNT_CONTINUITY_COLLECTOR.md @@ -1,5 +1,84 @@ # Account Continuity Bridge production acceptance collector +## E5 unsigned measurement recipe (PR 7) + +The separate `measure-e5` subcommand measures exact candidate +`e5b8c7b7f3fd59c79cd9c436ef14ec40216da119`, branch +`agent/innovator-provider-readiness-20261030`, plugin +`1.1.0+codex.20261030230943`. The legacy production signer below remains pinned +to its previously reviewed candidate and rejects E5 before key access. +The new subcommand has no private-key argument, signing operation, installation, +trust enrollment, live inference or remote admission operation. + +The recipe verifies the Git root, official origin, clean exact HEAD and branch, +then hashes every tracked regular file before starting source tests. It runs +six fixed PowerShell suites, registry assertions and all six Node test files. +Default execution repeats them three times and rechecks the complete source +and installed manifests afterward. A source or installed-byte race aborts output. +Children receive an explicit Windows environment list including PATHEXT, with +SDK/provider credentials excluded. Child windows are hidden. Diagnostics contain +event, suite, iteration, count and failure category; captured output is represented +by SHA256. Raw child output is not copied into ordinary diagnostic logs. + +E5's suite contract differs from the legacy 119-assertion contract: + +| Suite | Assertions | +|---|---:| +| Repository policy | 8 | +| Account continuity core | 6 | +| Provider auth monitor | 5 | +| Provider content import | 9 | +| Multiprovider MCP fixtures | 35 | +| Account continuity bridge | 22 | +| Provider registry | 16 | +| Node regressions | 94 | +| Total per source iteration | 195 | + +These are source/fixture assertions, not current provider health or native-client +production acceptance. The Node suite includes current concurrency, process, +receipt, safety and boundary regressions; all 94 must pass with zero failures, +skips, cancellations or todos. Old standalone Windows control outputs cannot +substitute for this changed suite. Legacy signed collection retains its existing +Windows rename and acquisition controls. + +```powershell +python scripts/hammer_account_bridge_attestor.py measure-e5 ` + --source '' ` + --installed-root '' ` + --node '' --pwsh '' ` + --output '' +``` + +`--iterations 1` explicitly records the missing three-pass stability prerequisite. +Omitting the installed root records MISSING. Actual absent or different files +record MISMATCH with at most 32 names. Source and installed roots must be separate. +Outputs cannot overwrite source, installed files or previous evidence. + +Optional `--owner-evidence` plus `--owner-evidence-sha256` validates bounded schema +`echo.account-continuity.quench-evidence.e5.v1`: exact four source identities, +branch/PR/version, independently compared installed-manifest digest, production +scope, native enabled/fresh-session flags, three current 195-assertion rows with +critical journeys, three distinct governed Qwen nonce/session rows and three +non-spending 17-tool/7-provider status rows. The source-pinned route is +`forge-qwen-worker` and model `huihui_ai/Qwen3.8-abliterated:27b`. Identifying +required evidence does not authorize inference or override fleet compute limits. +A changed model route requires new review and evidence. Input files stay outside +target and installed trees. Missing/expired/mixed identities, canary scope, +route/model mismatch, replayed nonce/session, wrong counts and custody mismatch +are rejected. + +Owner JSON is not authenticated by field validation. Its result is explicitly +STRUCTURE_VALIDATED_ONLY and cannot clear native, live, hosted-receipt or signer +admission. Report schema `echo.account-continuity.e5-measurement.v1` differs from +a signed production envelope. Synthetic fixtures and successful real measurements +always emit NOT_READY, unsigned=true, signing_available=false and outstanding +prerequisites. Do not ingest these reports as production attestations. Trusted +independent E5 collector admission, authentic hosted App revision receipt/custody, +actual native/live production readback and genuine Commander acceptance remain +separate gates. Source passes and metadata booleans cannot replace them. + +## Legacy admitted recipe and provenance + `scripts/hammer_account_bridge_attestor.py` is an operator collector for the reviewed ACB candidate `d9ffe76ad63b71545d5378f154e15af10e4f7a9e`, PR 4, branch `agent/grok47-provider-recovery-20261003`, plugin version diff --git a/scripts/hammer_account_bridge_attestor.py b/scripts/hammer_account_bridge_attestor.py index 9747fef..f8330a9 100644 --- a/scripts/hammer_account_bridge_attestor.py +++ b/scripts/hammer_account_bridge_attestor.py @@ -11,6 +11,7 @@ import re import socket import subprocess +import sys import tempfile from datetime import UTC, datetime, timedelta from pathlib import Path @@ -80,6 +81,28 @@ }) SHA256 = re.compile(r"^[0-9a-f]{64}$") +# E5 is a separate unsigned recipe, never admitted to the legacy key path. +E5_SOURCE = "e5b8c7b7f3fd59c79cd9c436ef14ec40216da119" +E5_BRANCH = "agent/innovator-provider-readiness-20261030" +E5_VERSION = "1.1.0+codex.20261030230943" +E5_MODEL = "huihui_ai/Qwen3.8-abliterated:27b" +E5_ASSERTIONS = { + "repository_policy": 8, "account_continuity_core": 6, + "provider_auth_monitor": 5, "provider_content_import": 9, + "multiprovider_mcp": 35, "account_continuity_bridge": 22, + "provider_registry": 16, "node_regressions": 94, +} +E5_PS_TESTS = { + **POWERSHELL_TESTS, + "account_continuity_core": "tests/Test-AccountContinuityCore.ps1", + "account_continuity_bridge": "scripts/Test-AccountContinuityBridge.ps1", +} +E5_NODE_TESTS = ( + "tests/Test-ProviderStatus.mjs", "tests/Test-RouterConcurrency.mjs", + "tests/Test-ProviderProcess.mjs", "tests/Test-ReceiptProvenance.mjs", + "tests/Test-RouterSafety.mjs", "tests/Test-Boundaries.mjs", +) + class AttestationError(RuntimeError): """A fail-closed rejection with no secret-bearing detail.""" @@ -127,6 +150,7 @@ def run( capture_output=True, timeout=timeout, check=False, + creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), ) if completed.returncode != 0: raise AttestationError( @@ -469,6 +493,249 @@ def atomic_write(path: Path, data: bytes) -> None: temporary.unlink(missing_ok=True) +def e5_snapshot(repository: Path) -> dict[str, str]: + """Measure the reviewed first-party tree before executing any child.""" + repository = repository.resolve(strict=True) + git_environment = os.environ.copy() + git_environment.update(GIT_NO_REPLACE_OBJECTS="1", GIT_OPTIONAL_LOCKS="0") + + def git(*arguments: str) -> str: + return run(["git", "-c", "core.fsmonitor=false", "-C", str(repository), *arguments], + env=git_environment).stdout.strip() + + root = git("rev-parse", "--show-toplevel").replace("\\", "/") + if root.casefold() != repository.as_posix().casefold(): + raise AttestationError("E5 source must be the repository root") + if git("rev-parse", "HEAD") != E5_SOURCE or git("branch", "--show-current") != E5_BRANCH: + raise AttestationError("E5 source or branch is not the reviewed candidate") + if git("remote", "get-url", "origin") not in { + "https://github.com/echoomegaprime/account-continuity-bridge.git", + "git@github.com:echoomegaprime/account-continuity-bridge.git", + } or git("status", "--porcelain"): + raise AttestationError("E5 source origin or clean-tree binding failed") + entries = [entry for entry in git("ls-tree", "-rz", "--full-tree", E5_SOURCE).split("\0") if entry] + if not entries or len(entries) > 10000: + raise AttestationError("E5 source inventory is invalid") + manifest = {} + for entry in sorted(entries): + header, relative = entry.split("\t", 1) + mode, kind, blob = header.split() + path = repository / relative + if (mode not in {"100644", "100755"} or kind != "blob" or not SHA40.fullmatch(blob) + or path.is_symlink() or not path.resolve().is_relative_to(repository)): + raise AttestationError("E5 inventory contains an unsafe path") + if not path.is_file() or path.stat().st_size > 16 * 1024 * 1024: + raise AttestationError("E5 inventory file is missing or oversized") + content = path.read_bytes() + # A clean index alone can conceal assume-unchanged/stat-cache edits. + # Bind actual bytes to the immutable tree, allowing only Windows CRLF + # checkout conversion for these reviewed text source types. + candidates = [content] + if path.suffix.lower() in {".md", ".ps1", ".psm1", ".mjs", ".json", ".yml", ".yaml"}: + candidates.append(content.replace(b"\r\n", b"\n")) + identities = {hashlib.sha1(b"blob " + str(len(value)).encode() + b"\0" + value, + usedforsecurity=False).hexdigest() for value in candidates} + if blob not in identities: + raise AttestationError("E5 working bytes differ from the immutable source blob") + manifest[relative] = sha256_bytes(content) + plugin, _ = read_json(repository / ".codex-plugin/plugin.json") + if plugin.get("version") != E5_VERSION: + raise AttestationError("E5 source plugin version is unexpected") + return manifest + + +def e5_installed_snapshot(installed: Path | None, manifest: dict[str, str]) -> dict[str, Any]: + if installed is None: + return {"state": "MISSING", "reason": "installed_root_not_supplied"} + installed = installed.resolve(strict=True) + mismatches, actual = [], {} + for relative, expected in sorted(manifest.items()): + path = installed / relative + if (path.is_symlink() or not path.resolve().is_relative_to(installed) + or not path.is_file() or path.stat().st_size > 16 * 1024 * 1024): + mismatches.append(relative) + continue + actual[relative] = sha256_bytes(path.read_bytes()) + if actual[relative] != expected: + mismatches.append(relative) + return {"state": "MATCH" if not mismatches else "MISMATCH", + "manifest_sha256": sha256_bytes(canonical_json(actual)), + "mismatch_count": len(mismatches), "mismatches": mismatches[:32], + "tracked_files": len(manifest), "scope": "tracked_bytes_only; native enablement unverified"} + + +def e5_node_counts(completed: subprocess.CompletedProcess[str]) -> int: + metrics = {} + for line in completed.stdout.splitlines(): + match = re.fullmatch(r"# (tests|pass|fail|cancelled|skipped|todo) (\d+)", line.strip()) + if match: + if match[1] in metrics: + raise AttestationError("E5 Node summary is ambiguous") + metrics[match[1]] = int(match[2]) + if (completed.returncode or set(metrics) != {"tests", "pass", "fail", "cancelled", "skipped", "todo"} + or metrics["tests"] != 94 or metrics["pass"] != 94 + or any(metrics[key] for key in ("fail", "cancelled", "skipped", "todo"))): + raise AttestationError("E5 Node suite is incomplete or failing") + return metrics["pass"] + + +def verify_e5_owner_evidence(path: Path, *, expected_sha256: str, + installed: dict[str, Any]) -> dict[str, Any]: + """Validate custody and structure only; owner assertions never admit signing.""" + if installed.get("state") != "MATCH": + raise AttestationError("E5 installed bytes were not independently matched") + if path.stat().st_size > 1024 * 1024: + raise AttestationError("E5 owner evidence exceeds the bounded input size") + document, digest = read_json(path, expected_sha256=expected_sha256) + if document.get("schema_version") != "echo.account-continuity.quench-evidence.e5.v1": + raise AttestationError("E5 owner evidence schema is invalid") + verify_current_time(document.get("observed_at")) + expected = { + "host": "QUENCH", "branch": E5_BRANCH, "pull_request": 7, + "installed_version": E5_VERSION, "installation_scope": "production", + "native_plugin_enabled": True, "fresh_native_session": True, + "installed_manifest_sha256": installed["manifest_sha256"], + "iterations": 3, "credentials_in_evidence": False, "private_key_exported": False, + } + for key in ("source_commit", "installed_cache_commit", "remote_branch_commit", "pull_request_head_commit"): + expected[key] = E5_SOURCE + for key, value in expected.items(): + if type(document.get(key)) is not type(value) or document[key] != value: + raise AttestationError("E5 owner evidence identity or production boundary failed") + rows = document.get("test_runs") + if not isinstance(rows, list) or len(rows) != 3: + raise AttestationError("E5 requires three measured test passes") + for iteration, row in enumerate(rows, 1): + if (not isinstance(row, dict) or type(row.get("iteration")) is not int + or row["iteration"] != iteration or row.get("source_commit") != E5_SOURCE + or row.get("assertions") != E5_ASSERTIONS or row.get("total") != 195 + or row.get("critical_journey") != "PASS"): + raise AttestationError("E5 detailed test evidence is incomplete") + verify_current_time(row.get("observed_at")) + seen, sessions = set(), set() + rows = document.get("live_runs") + if not isinstance(rows, list) or len(rows) != 3: + raise AttestationError("E5 requires three distinct governed live runs") + for row in rows: + if not isinstance(row, dict): + raise AttestationError("E5 live record is invalid") + verify_current_time(row.get("observed_at")) + nonce, session = row.get("canary_sha256"), row.get("session_id") + if (row.get("source_commit") != E5_SOURCE or row.get("governance") != "PASS" + or row.get("selected_provider") != "forge-qwen" + or row.get("selected_route") != "forge-qwen-worker" or row.get("model") != E5_MODEL + or row.get("selected_outcome") != "success" or row.get("exact_canary_match") is not True + or row.get("provenance") != "LIVE_PROVIDER_BRIDGE" + or row.get("credential_copied_or_exposed") is not False + or not isinstance(nonce, str) or not SHA256.fullmatch(nonce) + or nonce != row.get("response_sha256") or nonce in seen + or not isinstance(session, str) or not session or session in sessions): + raise AttestationError("E5 live route, nonce or session binding failed") + seen.add(nonce) + sessions.add(session) + rows = document.get("status_runs") + if not isinstance(rows, list) or len(rows) != 3: + raise AttestationError("E5 requires three non-spending installed status readbacks") + for row in rows: + if (not isinstance(row, dict) or row.get("source_commit") != E5_SOURCE + or row.get("status_nonspending") is not True + or row.get("server_name") != "account_continuity_multiprovider_mcp" + or row.get("server_version") != "0.5.0" + or row.get("provider_count") != 7 or row.get("tool_count") != 17): + raise AttestationError("E5 installed status identity is invalid") + verify_current_time(row.get("observed_at")) + return {"state": "STRUCTURE_VALIDATED_ONLY", "document_sha256": digest, + "authority": "owner_readback_not_independently_authenticated"} + + +def measure_e5(argv: list[str]) -> int: + parser = argparse.ArgumentParser(description="Unsigned exact-E5 measurement; no signing capability") + parser.add_argument("--source", type=Path, required=True) + parser.add_argument("--installed-root", type=Path) + parser.add_argument("--node", required=True) + parser.add_argument("--pwsh", required=True) + parser.add_argument("--iterations", type=int, choices=(1, 3), default=3) + parser.add_argument("--owner-evidence", type=Path) + parser.add_argument("--owner-evidence-sha256") + parser.add_argument("--output", type=Path, required=True) + args = parser.parse_args(argv) + source, output = args.source.resolve(strict=True), args.output.resolve() + installed_root = args.installed_root.resolve(strict=True) if args.installed_root else None + if (output.exists() or output.is_relative_to(source) + or (installed_root and (output.is_relative_to(installed_root) + or installed_root.is_relative_to(source) + or source.is_relative_to(installed_root)))): + raise AttestationError("E5 source, install and new output paths must be separate") + if bool(args.owner_evidence) != bool(args.owner_evidence_sha256): + raise AttestationError("E5 owner evidence requires its independently retrieved custody hash") + if args.owner_evidence and (args.owner_evidence.resolve().is_relative_to(source) + or (installed_root and args.owner_evidence.resolve().is_relative_to(installed_root))): + raise AttestationError("E5 owner evidence must be outside target and installed trees") + before = e5_snapshot(source) + installed = e5_installed_snapshot(installed_root, before) + environment = {key: value for key, value in os.environ.items() if key.upper() in { + "PATH", "SYSTEMROOT", "WINDIR", "COMSPEC", "TEMP", "TMP", "USERPROFILE", + "APPDATA", "LOCALAPPDATA", "PROGRAMDATA", "PROGRAMFILES", "PSMODULEPATH", "PATHEXT", + }} + environment["PYTHONDONTWRITEBYTECODE"] = "1" + test_runs = [] + commands = {label: [args.pwsh, "-NoLogo", "-NoProfile", "-File", relative] + for label, relative in E5_PS_TESTS.items()} + commands["provider_registry"] = [args.node, "tests/Test-ProviderRegistry.mjs"] + commands["node_regressions"] = [args.node, "--test", "--test-reporter=tap", *E5_NODE_TESTS] + for iteration in range(1, args.iterations + 1): + counts, receipts = {}, {} + for label, command in commands.items(): + try: + completed = run(command, cwd=source, env=environment, timeout=300) + count = (e5_node_counts(completed) if label == "node_regressions" + else parse_node_check(completed) if label == "provider_registry" + else parse_test_json(completed, label)) + if count != E5_ASSERTIONS[label]: + raise AttestationError("E5 assertion count mismatch") + except (AttestationError, OSError, subprocess.SubprocessError) as exc: + print(json.dumps({"event": "e5_suite_rejected", "iteration": iteration, + "suite": label, "failure_kind": type(exc).__name__}), file=sys.stderr) + raise AttestationError("E5 fixed source suite failed: " + label) from exc + counts[label] = count + receipts[label] = {"stdout_sha256": sha256_bytes(completed.stdout.encode("utf-8")), + "command": command[1:], "exit_code": completed.returncode} + print(json.dumps({"event": "e5_suite_measured", "iteration": iteration, + "suite": label, "assertions": count}), file=sys.stderr) + test_runs.append({"iteration": iteration, "observed_at": datetime.now(UTC).isoformat(), + "source_commit": E5_SOURCE, "assertions": counts, + "total": sum(counts.values()), "receipts": receipts}) + if e5_snapshot(source) != before or e5_installed_snapshot(installed_root, before) != installed: + raise AttestationError("E5 source or installed bytes changed during measurement") + owner = {"state": "MISSING"} + if args.owner_evidence: + owner = verify_e5_owner_evidence(args.owner_evidence, + expected_sha256=args.owner_evidence_sha256, installed=installed) + report = { + "schema_version": "echo.account-continuity.e5-measurement.v1", + "run_outcome": "COMPLETE", "release_verdict": "NOT_READY", "unsigned": True, + "repository": REPOSITORY, "source_commit": E5_SOURCE, "branch": E5_BRANCH, + "pull_request": 7, "plugin_version": E5_VERSION, + "observed_at": datetime.now(UTC).isoformat(), "host": socket.gethostname(), + "source_manifest_sha256": sha256_bytes(canonical_json(before)), + "installed": installed, "test_runs": test_runs, "owner_evidence": owner, + "missing_production_prerequisites": [ + "independently_verified_native_enabled_fresh_session", + "three_installed_governed_qwen_live_runs_and_status_readbacks", + "current_exact_source_hosted_app_receipt_and_custody", + "current_public_collector_trust_and_independent_e5_recipe_admission", + "genuine_commander_acceptance", + ] + ([] if installed["state"] == "MATCH" else ["exact_production_installed_bytes"]) + + ([] if args.iterations == 3 else ["three_source_stability_iterations"]), + "signing_available": False, "private_key_accessed": False, "inference_performed": False, + } + atomic_write(output, canonical_json(report) + b"\n") + print(json.dumps({"run_outcome": "COMPLETE", "release_verdict": "NOT_READY", + "unsigned": True, "report_sha256": sha256_bytes(output.read_bytes()), + "iterations": len(test_runs), "assertions_per_iteration": 195})) + return 0 + + def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Attest Account Continuity Bridge from HAMMER") parser.add_argument("--bundle", type=Path, required=True) @@ -754,6 +1021,8 @@ def main() -> int: if __name__ == "__main__": try: + if len(sys.argv) > 1 and sys.argv[1] == "measure-e5": + raise SystemExit(measure_e5(sys.argv[2:])) raise SystemExit(main()) except (AttestationError, OSError, subprocess.SubprocessError, ValueError) as exc: print(json.dumps({"result": "NOT_READY", "error": str(exc)}, sort_keys=True)) diff --git a/tests/test_hammer_account_bridge_attestor.py b/tests/test_hammer_account_bridge_attestor.py index b28bd05..c85bbc2 100644 --- a/tests/test_hammer_account_bridge_attestor.py +++ b/tests/test_hammer_account_bridge_attestor.py @@ -15,6 +15,206 @@ collector = importlib.util.module_from_spec(SPEC) SPEC.loader.exec_module(collector) SOURCE = "d9ffe76ad63b71545d5378f154e15af10e4f7a9e" + + +def e5_fixture(): + """Synthetic owner metadata, never a production admission.""" + document = current_evidence() + document.update({ + "schema_version": "echo.account-continuity.quench-evidence.e5.v1", + "branch": collector.E5_BRANCH, "pull_request": 7, + "installed_version": collector.E5_VERSION, "installed_manifest_sha256": "a" * 64, + }) + for field in ("source_commit", "installed_cache_commit", "remote_branch_commit", "pull_request_head_commit"): + document[field] = collector.E5_SOURCE + for row in document["test_runs"]: + row.update(source_commit=collector.E5_SOURCE, total=195, assertions=dict(collector.E5_ASSERTIONS)) + for row in document["live_runs"]: + row.update(source_commit=collector.E5_SOURCE, model=collector.E5_MODEL, selected_route="forge-qwen-worker") + for row in document["status_runs"]: + row["source_commit"] = collector.E5_SOURCE + return document + + +def verify_e5_fixture(tmp_path, document, *, installed_state="MATCH", custody=None): + path = tmp_path / "synthetic-e5-owner.json" + path.write_text(json.dumps(document), encoding="utf-8") + return collector.verify_e5_owner_evidence( + path, expected_sha256=custody or hashlib.sha256(path.read_bytes()).hexdigest(), + installed={"state": installed_state, "manifest_sha256": "a" * 64}) + + +def test_e5_fixture_is_only_structure_validated(tmp_path): + result = verify_e5_fixture(tmp_path, e5_fixture()) + assert result["state"] == "STRUCTURE_VALIDATED_ONLY" + assert result["authority"] == "owner_readback_not_independently_authenticated" + assert "signature" not in result + + +@pytest.mark.parametrize("field,value", [ + ("source_commit", SOURCE), ("installed_cache_commit", SOURCE), + ("remote_branch_commit", SOURCE), ("pull_request_head_commit", SOURCE), + ("pull_request", 4), ("pull_request", True), ("branch", "main"), + ("installed_version", "old"), ("installation_scope", "isolated_canary"), + ("native_plugin_enabled", False), ("fresh_native_session", False), + ("installed_manifest_sha256", "b" * 64), ("iterations", 1), + ("credentials_in_evidence", True), ("private_key_exported", True), + ("test_runs", []), ("live_runs", []), ("status_runs", []), + ("observed_at", "2000-01-01T00:00:00+00:00"), +]) +def test_e5_rejects_missing_or_mixed_production_boundaries(tmp_path, field, value): + document = e5_fixture() + document[field] = value + with pytest.raises(collector.AttestationError): + verify_e5_fixture(tmp_path, document) + + +@pytest.mark.parametrize("section,field,value", [ + ("test_runs", "total", 119), + ("test_runs", "assertions", {"repository_policy": 8}), + ("test_runs", "critical_journey", "FAIL"), + ("test_runs", "source_commit", SOURCE), + ("live_runs", "selected_provider", "other"), + ("live_runs", "selected_route", "direct-api"), + ("live_runs", "model", "unreviewed-model"), + ("live_runs", "selected_outcome", "failure"), + ("live_runs", "response_sha256", "f" * 64), + ("live_runs", "provenance", "FIXTURE"), + ("live_runs", "credential_copied_or_exposed", True), + ("status_runs", "status_nonspending", False), + ("status_runs", "tool_count", 26), + ("status_runs", "source_commit", SOURCE), + ("live_runs", "observed_at", "2000-01-01T00:00:00+00:00"), +]) +def test_e5_rejects_stale_or_fabricated_nested_metadata(tmp_path, section, field, value): + document = e5_fixture() + document[section][0][field] = value + with pytest.raises(collector.AttestationError): + verify_e5_fixture(tmp_path, document) + + +@pytest.mark.parametrize("field", ["session_id", "canary_sha256"]) +def test_e5_rejects_replayed_live_identity(tmp_path, field): + document = e5_fixture() + document["live_runs"][1][field] = document["live_runs"][0][field] + if field == "canary_sha256": + document["live_runs"][1]["response_sha256"] = document["live_runs"][0][field] + with pytest.raises(collector.AttestationError): + verify_e5_fixture(tmp_path, document) + + +def test_e5_requires_actual_installed_match_and_custody(tmp_path): + with pytest.raises(collector.AttestationError, match="independently matched"): + verify_e5_fixture(tmp_path, e5_fixture(), installed_state="MISMATCH") + with pytest.raises(collector.AttestationError, match="custody"): + verify_e5_fixture(tmp_path, e5_fixture(), custody="f" * 64) + + +def test_e5_installed_bytes_are_measured_and_mismatches_bounded(tmp_path): + installed = tmp_path / "installed" + installed.mkdir() + (installed / "one").write_bytes(b"measured") + manifest = {"one": hashlib.sha256(b"measured").hexdigest()} + first = collector.e5_installed_snapshot(installed, manifest) + assert first["state"] == "MATCH" + (installed / "one").write_bytes(b"changed") + assert collector.e5_installed_snapshot(installed, manifest)["state"] == "MISMATCH" + missing = collector.e5_installed_snapshot(installed, {str(n): "a" * 64 for n in range(50)}) + assert missing["mismatch_count"] == 50 + assert len(missing["mismatches"]) == 32 + + +def test_e5_node_report_requires_all_tests_and_zero_skips(): + valid = "# tests 94\n# pass 94\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n" + assert collector.e5_node_counts(subprocess.CompletedProcess([], 0, valid)) == 94 + for output in (valid.replace("# skipped 0", "# skipped 1"), + valid.replace("# pass 94", "# pass 93"), valid + "# tests 94\n", ""): + with pytest.raises(collector.AttestationError): + collector.e5_node_counts(subprocess.CompletedProcess([], 0, output)) + + +def test_e5_checks_immutable_blobs_despite_a_clean_index(tmp_path, monkeypatch): + source = tmp_path / "source" + (source / ".codex-plugin").mkdir(parents=True) + payload = json.dumps({"version": collector.E5_VERSION}).encode() + plugin = source / ".codex-plugin/plugin.json" + plugin.write_bytes(payload) + blob = hashlib.sha1(b"blob " + str(len(payload)).encode() + b"\0" + payload).hexdigest() + + def metadata(command, **kwargs): + assert kwargs["env"]["GIT_NO_REPLACE_OBJECTS"] == "1" + if "--show-toplevel" in command: + text = source.as_posix() + elif "rev-parse" in command: + text = collector.E5_SOURCE + elif "branch" in command: + text = collector.E5_BRANCH + elif "remote" in command: + text = "https://github.com/echoomegaprime/account-continuity-bridge.git" + elif "ls-tree" in command: + text = f"100644 blob {blob}\t.codex-plugin/plugin.json\0" + else: + text = "" # A falsely clean status cannot authorize changed bytes. + return subprocess.CompletedProcess(command, 0, text, "") + + monkeypatch.setattr(collector, "run", metadata) + assert collector.e5_snapshot(source)[".codex-plugin/plugin.json"] == hashlib.sha256(payload).hexdigest() + plugin.write_bytes(payload + b" ") + with pytest.raises(collector.AttestationError, match="immutable source blob"): + collector.e5_snapshot(source) + + +def test_e5_measurement_is_unsigned_even_with_matching_fixture_bytes(tmp_path, monkeypatch): + source, installed = tmp_path / "source", tmp_path / "installed" + source.mkdir() + installed.mkdir() + output = tmp_path / "unsigned.json" + monkeypatch.setenv("PATHEXT", ".COM;.EXE;.BAT;.CMD") + monkeypatch.setattr(collector, "e5_snapshot", lambda path: {"fixture": "a" * 64}) + monkeypatch.setattr(collector, "e5_installed_snapshot", lambda path, manifest: { + "state": "MATCH", "manifest_sha256": "a" * 64}) + monkeypatch.setattr(collector, "verify_private_key", + lambda *args, **kwargs: pytest.fail("unsigned E5 must never access a signing key")) + executed = [] + + def fixed_fixture_run(command, **kwargs): + assert not any("TOKEN" in key or "API_KEY" in key for key in kwargs["env"]) + assert ".EXE" in kwargs["env"]["PATHEXT"] + executed.append(command) + if "--test-reporter=tap" in command: + text = "# tests 94\n# pass 94\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n" + elif command[-1] == "tests/Test-ProviderRegistry.mjs": + text = json.dumps({"ok": True, "assertions": 16}) + else: + label = next(label for label, path in collector.E5_PS_TESTS.items() if path == command[-1]) + text = json.dumps({"ok": True, "assertions": { + f"fixture-{n}": True for n in range(collector.E5_ASSERTIONS[label])}}) + return subprocess.CompletedProcess(command, 0, text, "") + + monkeypatch.setattr(collector, "run", fixed_fixture_run) + argv = ["--source", str(source), "--installed-root", str(installed), "--node", "node", + "--pwsh", "pwsh", "--iterations", "1", "--output", str(output)] + assert collector.measure_e5(argv) == 0 + report = json.loads(output.read_text()) + assert len(executed) == 8 and report["test_runs"][0]["total"] == 195 + assert report["release_verdict"] == "NOT_READY" and report["unsigned"] is True + assert report["signing_available"] is False and report["private_key_accessed"] is False + assert "three_source_stability_iterations" in report["missing_production_prerequisites"] + with pytest.raises(collector.AttestationError, match="new output"): + collector.measure_e5(argv) + with pytest.raises(SystemExit): + collector.measure_e5(argv + ["--private-key", "forbidden"]) + + +def test_e5_cannot_enter_legacy_signer(monkeypatch): + monkeypatch.setattr(collector.socket, "gethostname", lambda: "HAMMER") + monkeypatch.setattr(collector, "parse_args", lambda: SimpleNamespace( + source_commit=collector.E5_SOURCE, base_commit="a" * 40, + target_identity_digest="b" * 64, environment_identity_digest="c" * 64)) + monkeypatch.setattr(collector, "verify_private_key", + lambda *args, **kwargs: pytest.fail("E5 is not admitted to legacy signing")) + with pytest.raises(collector.AttestationError, match="reviewed exact-source"): + collector.main() ASSERTIONS = { "repository_policy": 8, "account_continuity_core": 6, "provider_auth_monitor": 18, "provider_content_import": 9,