fix(validate): never emit evidence in --no-cluster dry-run mode#1810
fix(validate): never emit evidence in --no-cluster dry-run mode#1810njhensley wants to merge 1 commit into
Conversation
|
🌿 Preview your docs: https://nvidia-preview-fix-no-cluster-skip-evidence-emit.docs.buildwithfern.com/aicr |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Enterprise Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthrough
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/user/cli-reference.md`:
- Line 835: Update the no-cluster CLI documentation to match runValidation’s
actual behavior: either ensure noCluster also suppresses evidenceDir-driven
conformance artifacts, or narrow the description to state that only
recipe-attestation bundles and related options are ignored. Keep the documented
behavior consistent with the implementation.
In `@pkg/cli/validate.go`:
- Line 761: Update the --cncf-submission flow in pkg/cli/validate.go around
runCNCFSubmission and evidenceConfigForRunMode so --cncf-submission --no-cluster
cannot reach the live-cluster evidence collector; either reject the combination
or pass noCluster into runCNCFSubmission and honor it. In
docs/user/cli-reference.md, narrow the --no-cluster description to match the
supported --evidence-dir behavior.
In `@tests/uat/lib/phases.sh`:
- Around line 183-191: Update the temporary config setup in the deployment
validation flow to register a scoped cleanup trap immediately after prep_config
is created with mktemp. Ensure the trap removes prep_config on command failure,
interruption, or normal completion, and avoid relying solely on the later
explicit rm command.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: fc4c2150-81f5-49b4-bc4f-b158ea84363a
📒 Files selected for processing (5)
docs/user/cli-reference.mdpkg/cli/validate.gopkg/cli/validate_evidence.gopkg/cli/validate_evidence_test.gotests/uat/lib/phases.sh
Recipe evidence checkNo leaf overlays affected by this PR. This gate is warning-only and never blocks merge. |
8682ef3 to
0f48a8f
Compare
|
Addressed the CodeRabbit review (all 3 findings) in the amended commit:
|
0f48a8f to
168d1d3
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/cli/validate_test.go`:
- Around line 208-213: Extend the “cncf-submission with no-cluster” validation
test to assert the returned error has code ErrCodeInvalidRequest, not only the
expected message. Add a separate case where no-cluster is enabled through
resolved configuration, and verify it produces the same validation error and
code.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 326af2e3-b12e-4986-81e3-12d97b285466
📒 Files selected for processing (6)
docs/user/cli-reference.mdpkg/cli/validate.gopkg/cli/validate_evidence.gopkg/cli/validate_evidence_test.gopkg/cli/validate_test.gotests/uat/lib/phases.sh
A --no-cluster validate is an offline dry-run that reports every check as
"skipped", yet it still honored spec.validate.evidence.attestation.{out,push}
and built, signed, and wrote attestation.intoto.jsonl into the evidence output
dir (and pushed the bundle).
In the UAT flow the emit output dir (attestation.out: ./evidence) is shared
across phases in the runner workspace. The prep phase's dry-run therefore left a
signed attestation.intoto.jsonl (subject = prep's content-hash OCI digest) in
./evidence/. The later conformance-phase emit re-packs ./evidence/ into the
run-<id> artifact; the closed-world pack sweeps in that stale attestation, so the
run-tag artifact embeds a signature for a FOREIGN subject (prep's digest, not the
run-tag digest). Normally the conformance emit's own Sigstore referrer overwrites
the staged attestation at verify time and masks this; when that referrer push
fails to attach (observed: GHCR timeouts), `aicr evidence verify` (and the
Evidence: Ingest job) fall back to the embedded stale attestation and fail with
"signed subject digest (<prep digest>) does not match pulled artifact digest
(<run-tag digest>)". Confirmed by `oras pull` of the run-tag artifact: it embeds
attestation.intoto.jsonl signing the prep digest, and the run-tag artifact has
zero referrers.
Fix in two layers:
- CLI: evidenceConfigForRunMode drops the recipe-evidence config when
--no-cluster is set, so an offline dry-run can never sign or push an
attestation regardless of config. Emitting evidence over an all-skipped run
attests to nothing.
- UAT: the prep phase validates against a config copy with
spec.validate.evidence stripped (mirroring the readiness-gate strip in the
conformance phase), keeping prep safe even against an older released aicr
that predates the CLI guard.
With prep no longer emitting, no attestation.intoto.jsonl is left in ./evidence/
for the conformance pack to embed, so the run-tag artifact carries only its own
signature. Documents the behavior on the --no-cluster row of the CLI reference.
- flag-combination tests assert ErrCodeInvalidRequest (structured code), not
just the message text.
Signed-off-by: Nathan Hensley <nhensley@nvidia.com>
Review (CodeRabbit) follow-ups:
- Reject --cncf-submission --no-cluster: the behavioral evidence collector
short-circuits to the live cluster, bypassing the noCluster handling, so the
combination must fail closed rather than silently contact the cluster.
- Narrow the --no-cluster doc to what actually changes (recipe-evidence
attestation is not signed/pushed); CNCF conformance markdown via --evidence-dir
is still rendered locally.
- prep temp config cleanup runs on every exit path via a subshell + EXIT trap
(matches the signing subshell in phases.sh), not just the normal path.
Signed-off-by: Nathan Hensley <nhensley@nvidia.com>
168d1d3 to
198e45c
Compare
Summary
validate --no-cluster(an offline dry-run) still emitted and signed a full evidence bundle when the config setspec.validate.evidence.attestation.*, writingattestation.intoto.jsonlinto the shared evidence output dir. In the UAT flow this lets the prep phase's leftover signature get packed into the authoritative run-tag artifact, which breaksaicr evidence verifyand theEvidence: Ingestjob with a signed-subject/pulled-digest mismatch.Motivation / Context
The UAT emit output dir is
attestation.out: ./evidence, shared across phases in the runner workspace.preprunsvalidate --no-cluster(dry-run, all checksskipped). It still honored the config's evidence block, signed a bundle to the aicr content-hash tag (…-59266d32abc3, digestd3466f4c…), and leftattestation.intoto.jsonl(subject =d3466f4c…) in./evidence/.conformancethen runs the authoritativevalidate --phase all, which re-packs./evidence/into therun-<id>artifact (2a486d77…). The closed-world pack sweeps in prep's staleattestation.intoto.jsonl, so the run-tag artifact embeds a signature for a foreign subject (d3466f4c…, not2a486d77…).MaterializeBundlefound no referrer to overwrite the embedded stale file, andVerifySignatureread the embeddedd3466f4cattestation → mismatch.Directly confirmed against the registry:
oras pull …@sha256:2a486d77…→ the artifact embedsattestation.intoto.jsonl, and its DSSE payload signs subjectd3466f4c…(prep's content-tag ref).oras discover …@sha256:2a486d77…→ zero referrers (the conformance signature never attached).This is why it is intermittent / "new": it needs prep's stale attestation (present on every emit-enabled config) and the conformance referrer failing to attach (a GHCR write hiccup). Healthy runs overwrite the stale file via the referrer and pass — which is why the H100/release cells are green. Observed on run 29611408651 (verify) and 29619695743 (ingest). An offline dry-run over an all-
skippedrun attests to nothing, so it should never sign or write an attestation in the first place.Fixes: N/A
Related: #1793 (@main verify regression since #1758 closed-world pack)
Type of Change
Component(s) Affected
cmd/aicr,pkg/cli)docs/,examples/)tests/uat/lib/phases.sh)Implementation Notes
Two layers so a dry-run can never leave a signed attestation behind:
evidenceConfigForRunModedrops the recipe-evidence config whenever--no-clusteris set, so an offline dry-run can never sign, push, or writeattestation.intoto.jsonl, regardless of config. Logs once when it suppresses emission.prepphase validates against a config copy withspec.validate.evidencestripped (mirroring the readiness-gate strip already used in the conformance phase). Keepsprepsafe even against an older releasedaicrthat predates the CLI guard.With prep no longer emitting,
./evidence/holds no stale attestation for the conformance pack to embed, so the run-tag artifact carries only its own signature. Producer-side fix — no change needed in verify/ingest.Possible follow-up (out of scope): have the emit exclude any pre-existing
attestation.intoto.jsonlfrom the pack, and/or haveMaterializeBundleprefer the referrer over an embedded attestation — defense-in-depth against any stray signed file in the output dir.Testing
Added
TestEvidenceConfigForRunModecovering live-cluster pass-through,--no-clustersuppression, and nil-in/nil-out. Verified the mechanism against the live registry withoras pull/oras discover(see Motivation).Risk Assessment
Rollout notes: Behavior change is limited to
--no-clusterruns, which are dry-runs that should not have been producing evidence; live-cluster validate (the only path that emits authoritative evidence) is unchanged. Backwards compatible.Checklist
make testwith-race) — rango test ./pkg/cli/make lint) —golangci-lint0 issues onpkg/cligit commit -S)