diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index 7e47fee..e68ac5f 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -26,6 +26,10 @@ identity/E2E mismatch is a normal `NOT_READY` result, never a bypass. 6. Promote atomically, health-check production, and roll back on any mismatch. 7. Publish immutable machine certificates and the repository certificate graphic. +The Echo GitHub Autonomy production collector must use profile +`echo-github-autonomy-remote-mcp-v2` and exactly the three governed accounts. +Profile v1 and evidence containing the retired `Bmcbob76` identity fail closed. + ## Incident triage Capture the run ID, target SHA, environment digest, policy version, service health, dispatcher state, diff --git a/docs/PROJECT_CONTRACT.md b/docs/PROJECT_CONTRACT.md index e452ded..845bfb4 100644 --- a/docs/PROJECT_CONTRACT.md +++ b/docs/PROJECT_CONTRACT.md @@ -52,8 +52,11 @@ acceptance. Source checks, local journeys, HTTP 200, unsigned status fields, and target-authored evidence cannot satisfy this gate. Missing, expired, untrusted, partially passing, or identity-mismatched attestations remain `NOT_READY`. -For Echo GitHub Autonomy the target-specific profile additionally requires the -canonical MCP and OAuth surface, 30-tool schema, repeated discovery plus -invocation without registry loss, reconciled public/private inventory and -read/write/certify authority for all four exact GitHub account IDs, and matching -private-repository fingerprints from ChatGPT, Claude, Codex, and Grok. +For Echo GitHub Autonomy, target-specific profile +`echo-github-autonomy-remote-mcp-v2` additionally requires the canonical MCP +and OAuth surface, 30-tool schema, repeated discovery plus invocation without +registry loss, reconciled public/private inventory and read/write/certify +authority for exactly the three governed GitHub account IDs (`echoomegaprime`, +`ECHO-OMEGA-PRIME`, and `bobmcwilliams4`), and matching private-repository +fingerprints from ChatGPT, Claude, Codex, and Grok. The retired `Bmcbob76` +identity is invalid evidence for this profile. diff --git a/src/echo_certification_forge/production_e2e.py b/src/echo_certification_forge/production_e2e.py index b35e4eb..9712462 100644 --- a/src/echo_certification_forge/production_e2e.py +++ b/src/echo_certification_forge/production_e2e.py @@ -22,7 +22,7 @@ RULE_ID = "production_e2e" SCHEMA_VERSION = "certforge.production-e2e.v1" GENERIC_PROFILE = "generic-production-v1" -ECHO_GITHUB_AUTONOMY_PROFILE = "echo-github-autonomy-remote-mcp-v1" +ECHO_GITHUB_AUTONOMY_PROFILE = "echo-github-autonomy-remote-mcp-v2" ECHO_GITHUB_AUTONOMY_REPOSITORY = "echoomegaprime/echo-github-autonomy" ECHO_GITHUB_AUTONOMY_CANONICAL_MCP = "https://echo-ghub.grok.me/api/plugin/mcp" @@ -44,7 +44,7 @@ "tool_schema", "repeated_tool_invocation", "registry_persistence", - "four_account_reconciliation", + "three_account_reconciliation", "private_public_visibility", "read_write_certify", "cross_client_consistency", @@ -53,7 +53,6 @@ ECHO_GITHUB_ACCOUNTS = { "echoomegaprime": 314902331, "ECHO-OMEGA-PRIME": 264607697, - "Bmcbob76": 203470412, "bobmcwilliams4": 235318155, } ECHO_CLIENTS = frozenset({"chatgpt", "claude", "codex", "grok"}) diff --git a/tests/test_production_e2e.py b/tests/test_production_e2e.py index 81460f5..1c7dc19 100644 --- a/tests/test_production_e2e.py +++ b/tests/test_production_e2e.py @@ -118,7 +118,9 @@ def test_echo_github_autonomy_requires_complete_exact_cross_client_e2e() -> None (lambda value: value.__setitem__("deployment_sha", "6" * 40), "production_e2e_deployment_sha_mismatch"), (lambda value: value.__setitem__("tool_count", 27), "production_e2e_tool_count_mismatch"), ( - lambda value: value["accounts"]["Bmcbob76"].__setitem__("private_count", 0), + lambda value: value["accounts"]["bobmcwilliams4"].__setitem__( + "private_count", 0 + ), "production_e2e_account_reconciliation_failed", ), ( @@ -126,19 +128,19 @@ def test_echo_github_autonomy_requires_complete_exact_cross_client_e2e() -> None "production_e2e_client_not_accepted", ), ( - lambda value: value["accounts"]["Bmcbob76"].__setitem__( + lambda value: value["accounts"]["bobmcwilliams4"].__setitem__( "credential_source", "model_config_pat" ), "production_e2e_credential_source_invalid", ), ( - lambda value: value["accounts"]["Bmcbob76"].__setitem__( + lambda value: value["accounts"]["bobmcwilliams4"].__setitem__( "secret_exposed", True ), "production_e2e_secret_boundary_failed", ), ( - lambda value: value["sample_private_repositories"]["Bmcbob76"].__setitem__( + lambda value: value["sample_private_repositories"]["bobmcwilliams4"].__setitem__( "repository_id", True ), "production_e2e_sample_repository_id_invalid", @@ -163,6 +165,27 @@ def test_stale_e2e_attestation_fails_closed() -> None: assert reason == "production_e2e_attestation_not_current" +def test_retired_account_and_v1_profile_are_rejected() -> None: + retired_account = _payload() + retired_account["accounts"]["Bmcbob76"] = { + **retired_account["accounts"]["bobmcwilliams4"], + "account_id": 203470412, + } + valid, reason = validate_production_e2e( + retired_account, _target(), _environment(), now=NOW + timedelta(minutes=1) + ) + assert not valid + assert reason == "production_e2e_accounts_incomplete" + + retired_profile = _payload() + retired_profile["profile"] = "echo-github-autonomy-remote-mcp-v1" + valid, reason = validate_production_e2e( + retired_profile, _target(), _environment(), now=NOW + timedelta(minutes=1) + ) + assert not valid + assert reason == "production_e2e_profile_mismatch" + + def test_attestation_loader_requires_a_pinned_collector_key(tmp_path) -> None: signer = Ed25519VerdictSigner.generate() payload = _payload(signing_key_id=signer.key_id)