Skip to content

fix(evidence): pull by digest and auto-tag pushes instead of :v1 - #1168

Merged
mchmarny merged 4 commits into
NVIDIA:mainfrom
njhensley:fix/evidence-pull-by-digest-auto-tag
Jun 3, 2026
Merged

mchmarny merged 4 commits into
NVIDIA:mainfrom
njhensley:fix/evidence-pull-by-digest-auto-tag

Conversation

@njhensley

Copy link
Copy Markdown
Member

Summary

Make recipe-evidence verification pin on the content digest and stop defaulting
evidence pushes to a shared :v1 tag — so a committed pointer stays verifiable
regardless of registry tag drift, and distinct attestations never collide on one
tag. Includes the doc clarifications that motivated the change.

Motivation / Context

aicr evidence verify pulled the OCI artifact by the pointer's bundle.oci
tag, then checked the pulled digest against bundle.digest. Because tags are
registry-rewritable, a later push to the same tag floated it to a different
artifact and broke re-verification of any already-committed pointer (the pull
returned the new artifact; the digest check then failed). The push side made this
worse: every tag-less --push defaulted to a shared :v1, so unrelated recipes
collided on one tag immediately. Users and agents also tended to copy the
human-readable bundle.oci tag into verify, which refuses tag-only refs.

Fixes: N/A
Related: N/A

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Documentation update

Component(s) Affected

  • Docs/examples (docs/, examples/)
  • Other: pkg/evidence (recipe-evidence emit + verify)

Implementation Notes

  • Verifier (pkg/evidence/verifier/fetch.go): when the pointer carries a
    content digest, materializeFromPointer now pulls by digest
    (registry/repo@sha256:… derived from bundle.oci via the new
    pointerPullRef), not by the tag — so the exact attested bytes are fetched even
    if the tag has since moved. The post-pull digest cross-check stays as
    defense-in-depth. The no-digest path (local pointer + --bundle) is unchanged.
  • Emitter (pkg/evidence/attestation): dropped the :v1 default. When
    --push omits a tag, the emit/publish orchestration derives a unique per-recipe
    tag, <recipe-slug>-<fingerprint>, where the fingerprint is the first 12 hex of
    the bundle's manifest digest (deterministic, not random). An operator-supplied
    tag is still honored.
  • Behavior change to note: the exported attestation.Push now returns
    ErrCodeInvalidRequest if handed a tag-less reference instead of silently
    defaulting — tag derivation is the orchestration layer's responsibility
    (effectiveEvidenceRef). Both real flows (validate --emit-attestation and
    evidence publish) derive a tag first, so this only affects direct API callers.
  • Docs: the CLI reference, demo, validation, and recipe-development guides now
    explain that the sha256: digest is the canonical pin (verify pulls by digest),
    the tag is a human-readable label, and aicr auto-derives a unique one.

Testing

go test ./pkg/evidence/... ./pkg/cli/...      # pass
go vet ./pkg/evidence/...                     # clean
golangci-lint -c .golangci.yaml run ./pkg/evidence/attestation/... ./pkg/evidence/verifier/...  # 0 issues
./tools/check-docs-mdx                        # OK

New tests: pointerPullRef (digest-pinning, tag drop, passthrough, invalid ref);
deriveEvidenceTag / sanitizeOCITag / manifestFingerprint; Push tag-required
error. Per-package coverage: pkg/evidence/attestation 72.8%, pkg/evidence/verifier
64.7% (new functions covered).

Risk Assessment

  • Medium — Touches the evidence trust path (verify fetch + push tag) and
    changes an exported function's contract (Push now requires a tag).

Rollout notes: Backward-compatible for existing committed pointers — they carry
bundle.digest, so verification now pulls by digest (and can even re-verify
pointers whose tag had drifted, as long as the digest still resolves). No pointer
schema change.

Checklist

  • Tests pass locally (make test equivalent on affected packages, with -race via go test)
  • Linter passes (golangci-lint, 0 issues)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality
  • I updated docs for the user-facing behavior change
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)
njhensley added 3 commits June 2, 2026 19:41
Evidence verification pulled the OCI artifact by the pointer's
bundle.oci
tag, then checked the pulled digest against bundle.digest. Because the
tag
is registry-rewritable, a later push to the same tag floated it to a
different artifact and broke re-verification of any already-committed
pointer. The push side made this worse by defaulting every tag-less push
to a shared ":v1", so unrelated recipes collided on one tag immediately.

Verifier: when the pointer carries a content digest, pull by digest
(registry/repo@sha256:... derived from bundle.oci) rather than by the
tag,
so the exact attested bytes are fetched regardless of tag drift. The
post-pull digest cross-check stays as defense-in-depth.

Emitter: drop the ":v1" default. When --push omits a tag, derive a
unique
per-recipe tag, <recipe-slug>-<fingerprint>, where the fingerprint is
the
first 12 hex of the bundle's manifest digest (deterministic, not
random).
Push now requires an explicit tag; tag derivation lives in the
emit/publish
orchestration. An operator-supplied tag is still honored.

Docs: explain that the sha256 digest is the canonical pin (verify pulls
by
digest), the tag is a human-readable label, and aicr auto-derives a
unique
one; correct the pointer-pull description across the CLI reference,
demo,
validation, and recipe-development guides.

Tests: cover pointerPullRef, deriveEvidenceTag/sanitizeOCITag/
manifestFingerprint, and Push's tag-required error.
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: bf72b82b-d21c-4111-99f2-117b7674275a

📥 Commits

Reviewing files that changed from the base of the PR and between 98639ba and a7687dc.

📒 Files selected for processing (10)
  • demos/evidence.md
  • docs/integrator/recipe-development.md
  • docs/user/cli-reference.md
  • docs/user/validation.md
  • pkg/evidence/attestation/emit.go
  • pkg/evidence/attestation/oci.go
  • pkg/evidence/attestation/tag_test.go
  • pkg/evidence/attestation/types.go
  • pkg/evidence/verifier/fetch.go
  • pkg/evidence/verifier/fetch_test.go
💤 Files with no reviewable changes (1)
  • pkg/evidence/attestation/types.go

📝 Walkthrough

Walkthrough

This PR refactors evidence attestation push and verification to support optional OCI tags with automatic per-recipe derivation. The push pipeline now requires explicit tags at the Push level, and derives deterministic fingerprint-based tags when callers omit them. The verification flow is updated to prefer digest-pinned pulls from pointer files, treating bundle.oci as a human-readable label. Comprehensive unit tests validate tag derivation, reference resolution, and pointer-based pulling. Documentation across CLI reference, validation guide, recipe development, and demo materials is updated to explain the new behavior and emphasize digest-based verification security.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • NVIDIA/aicr#1140: Main PR that refactors the attestation sign+push OCI reference handling (effective per-recipe tag derivation and digest-pinned pointer verification) that the new off-network aicr evidence publish flow relies on.

Suggested labels

area/docs, size/M

Suggested reviewers

  • mchmarny
  • yuanchen8911
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: pulling verification by digest and replacing shared :v1 pushes with auto-derived per-recipe tags.
Description check ✅ Passed The description comprehensively covers the motivation, implementation details, testing, and risk assessment related to the evidence verification and push changes throughout the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@mchmarny
mchmarny merged commit af563b2 into NVIDIA:main Jun 3, 2026
32 checks passed
@njhensley
njhensley deleted the fix/evidence-pull-by-digest-auto-tag branch June 23, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

2 participants