test(provenance): honor declared digest algorithm in depth oracle - #243
test(provenance): honor declared digest algorithm in depth oracle#243solloek369-arch wants to merge 1 commit into
Conversation
Signed-off-by: Loek <solloek369@gmail.com>
lywinged
left a comment
There was a problem hiding this comment.
Approving. The fix is right and the defect was fully latent: all six vectors in examples/build-provenance-depth/ declare sha256, so nothing in the set could reach the hardcoded lookup. Adding the first sha384 case is what makes it reachable. Four CI steps green here, 830 passed.
One gap, and it is the half the title names.
I deleted and substituted the rule rather than reading it:
_attestation_subject_mismatch replaced by |
tests failing |
|---|---|
the old hardcoded sha256 lookup |
1 |
wanted in entry.get("digest", {}).values() |
0 |
return False |
3 |
return True |
12 |
The second row is a verifier that ignores the declared algorithm entirely and accepts a match found under any label. Nothing in the file catches it. "Honor the declared algorithm" has two halves: use the one that was declared, and do not accept a value declared under a different one. This pins the first and leaves the second open.
To be clear about whose gap it is: the same substitution on main also fails nothing, 46 passed. This branch inherits the hole rather than introducing it, so it is a follow-up and not a reason to hold anything up.
The case that closes it holds the value fixed and moves only the label:
def _mislabelled_control() -> dict[str, Any]:
"""Record declares sha384:X; the subject carries the same hex under `sha256`."""
vector = copy.deepcopy(CONTROL)
hexadecimal = "a" * 96
digest = "sha384:" + hexadecimal
vector["build_provenance"]["digest"] = digest
vector["context"]["artifact_digest"] = digest
statement = _attestation(vector)
assert statement is not None
statement["subject"][0]["digest"] = {"sha256": hexadecimal}
return vector
def test_a_hex_declared_under_another_algorithm_does_not_bind() -> None:
assert verify(_mislabelled_control(), "builder")["failures"] == ["attestation_subject_mismatch"]It passes on this branch as submitted and fails under the permissive substitution above, which is the property the other two cannot report on.
Related, and the reason I looked: of the two tests added here, only test_sha384_subject_binding_selects_the_declared_algorithm separates the fixed rule from the broken one. test_sha384_subject_binding_rejects_the_wrong_digest passes under the old hardcoded lookup too, because that lookup rejects every sha384 record and the test expects a rejection. It is a sound control in the accept and reject sense and it is not evidence for this change.
Nothing else: _hex had two occurrences and none remain, and no other rule in the file reads an algorithm from a literal.
What this changes
build_provenance.digestsupports SHA-256 and SHA-384, but the informative provenance-depth oracle previously inspected onlysubject.digest.sha256when checking the SLSA attestation subject.This patch selects the subject digest using the algorithm declared by
build_provenance.digest. It adds a positive SHA-384 control with an irrelevant nonmatching SHA-256 member, plus a negative control with the wrong SHA-384 value. The existing SHA-256 corpus remains green.No schema, wire, normative specification, or production-verifier behavior changes.
Refs #66
Type of change
Spec section
No specification text changes. The informative oracle exercises the existing build-provenance subject-binding behavior in §3.3.1.
Verification
pytest -q tests/test_build_provenance_depth_vectors.py: 48 passedpytest -q: 830 passed, 1 skippedruff check src tests: passedmypy src/agentrust_trace: passedChecklist
git commit -s)CHANGELOG.mdupdated (not applicable: no normative change)<!-- CHANGED: #NNN: description -->(not applicable)