diff --git a/scripts/action_anchor_resolve.py b/scripts/action_anchor_resolve.py index 258622c..276e536 100644 --- a/scripts/action_anchor_resolve.py +++ b/scripts/action_anchor_resolve.py @@ -71,9 +71,17 @@ "temporary failure", "cancelled", "canceled", ) # Only these reach `contradicted`: an attestation WAS found and did not survive. +# +# `verifying with issuer` is the REAL shape, captured from live gh against this repo's +# first verifiable attestation with a deliberately wrong --signer-workflow +# (scripts/fixtures/gh_attestation_verify/signer_denied.txt). The rest of this tuple was +# a pre-merge guess, and the guess did not match: without this marker the most common +# denial fell through to the fail-closed default and was reported as `unavailable`, which +# is non-promoting either way but loses D5's observability distinction — "it said no" read +# as "I could not look". The fixture is why that was caught rather than assumed. _CONTRADICTED_MARKERS = ( - "verification failed", "failed to verify", "signature", "does not match", - "not signed by", "unable to verify", "policy", "mismatch", + "verifying with issuer", "verification failed", "failed to verify", "signature", + "does not match", "not signed by", "unable to verify", "policy", "mismatch", ) diff --git a/scripts/fixtures/gh_attestation_verify/signer_denied.txt b/scripts/fixtures/gh_attestation_verify/signer_denied.txt new file mode 100644 index 0000000..4a6ae2b --- /dev/null +++ b/scripts/fixtures/gh_attestation_verify/signer_denied.txt @@ -0,0 +1,2 @@ + +Error: verifying with issuer "sigstore.dev" diff --git a/scripts/test_action_anchor_resolve.py b/scripts/test_action_anchor_resolve.py index 57b0a27..3ae1a59 100644 --- a/scripts/test_action_anchor_resolve.py +++ b/scripts/test_action_anchor_resolve.py @@ -22,7 +22,9 @@ ROOT = pathlib.Path(__file__).resolve().parent.parent SCRIPT = ROOT / "scripts" / "action_anchor_resolve.py" -FIXTURE_404 = ROOT / "scripts" / "fixtures" / "gh_attestation_verify" / "no_attestation_404.txt" +_FIXTURES = ROOT / "scripts" / "fixtures" / "gh_attestation_verify" +FIXTURE_404 = _FIXTURES / "no_attestation_404.txt" +FIXTURE_DENIED = _FIXTURES / "signer_denied.txt" _HEAD = "a1" * 32 _REPO = "SollanSystems/loop-engineer" @@ -150,6 +152,24 @@ def test_resolve_classifies_the_real_captured_404_stderr(tmp_path): assert outputs["anchor-outcome"] == "unavailable" +def test_resolve_classifies_the_real_captured_denial_stderr(tmp_path): + """M2's second half, capturable only AFTER a verifiable attestation existed. + + Captured from live gh against this repo's first verifiable verdict@1 attestation with + a deliberately wrong --signer-workflow. It is the reason the marker set was corrected: + the pre-merge guess did not contain gh's real denial shape, so "it said no" was being + reported as "I could not look". + """ + assert FIXTURE_DENIED.is_file() + captured = FIXTURE_DENIED.read_text(encoding="utf-8") + assert "verifying with issuer" in captured + bin_dir, _log = _shim(tmp_path, stderr=captured, exit_code=1) + proc, outputs, _temp = _resolve(tmp_path, bin_dir=bin_dir) + assert proc.returncode == 1 + assert outputs["anchor-outcome"] == "contradicted" + assert "anchor_attestation_contradicted" in proc.stdout + + def test_resolve_maps_an_unclassifiable_failure_to_unavailable(tmp_path): """M2's fallback rule: an unrecognized shape is the most suspicious case.""" bin_dir, _log = _shim(tmp_path, stderr="weasel", exit_code=1)