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

fix(evidence): pull by digest and auto-tag pushes instead of :v1#1168
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

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants