Skip to content

Evidence signing: unsigned-commit flow contradicts pointer contract; sign script scans wrong path #1530

Description

@yuanchen8911

Summary

The unsigned-commit-then-CI-sign evidence-publishing flow is internally contradictory with the on-disk pointer contract, and the signing script it relies on is effectively dead (and mis-fires on allowlist.yaml). This needs a maintainer design decision, not a one-line path fix.

Details

.github/scripts/evidence-sign-unsigned.sh (invoked by .github/workflows/evidence-publish.yaml:130) discovers "committed-but-unsigned" pointers and signs them in place. It globs the flat path:

for pointer in recipes/evidence/*.yaml; do

Three problems:

  1. Wrong location. Every committed pointer in the tree is nested, e.g. recipes/evidence/h100-gke-cos-training/<source>/sha256-….yaml. The flat glob matches none of them — it matches only recipes/evidence/allowlist.yaml.

  2. Mis-fires on the allowlist. allowlist.yaml is not a pointer and has no .attestations[0].signer, so the script's yq check returns "null", classifies it as "unsigned," and would attempt aicr evidence sign allowlist.yaml (which fails).

  3. No relocation, and the flow is circular. The script signs in place and never moves the pointer to its derived nested path. But the nested <source> segment is SourceSlug(issuer, identity) — derived from the signer, which an unsigned (--no-sign) pointer does not have (pkg/evidence/attestation/pointer.go PointerCopyToHint returns guidance, not a path, when there is no signer). So an unsigned pointer cannot be committed at its nested path to begin with. The only coherent unsigned-commit design is commit-flat → CI-sign → CI-relocate-to-nested, and the relocate step does not exist.

  4. Blocking gate rejects the intermediate. .github/workflows/evidence-pointer-contract.yaml runs on any recipes/evidence/** PR change and requires every committed pointer to be a signed, nested single-attestation V1 pointer under <recipe>/<source>/. A flat unsigned pointer is rejected on the PR before the signing leg can help.

Net: the commit-unsigned-then-CI-sign path cannot pass the contract gate as designed; the script that supports it scans the wrong location and trips on the allowlist.

Options (maintainer decision)

  1. Deprecate the unsigned-commit flow. Require contributors to sign locally and commit the nested signed pointer directly (or use the ingest-by-ref GP2 path), then delete evidence-sign-unsigned.sh and its evidence-publish.yaml step.
  2. Make the flow coherent. Have the script scan nested pointer paths, exclude allowlist.yaml, sign, and then relocate the now-signed pointer to its derived nested path — and reconcile that ordering with the blocking contract gate.

Related

Metadata

Metadata

Assignees

Type

Fields

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions