feat(bundler): bundle-time GPU driver-ownership coherence check - #1819
Conversation
|
🌿 Preview your docs: https://nvidia-preview-issue-1757-driver-coherence.docs.buildwithfern.com/aicr |
Recipe evidence check
Protected recipesRecipes with committed evidence (
Other affected recipes without evidence yet: 62These recipes are affected by this PR but carry no committed evidence pointer, so there is
How to refresh evidenceRun on a cluster matching the recipe's aicr snapshot -o snapshot.yaml
aicr validate \
-r recipes/overlays/<slug>.yaml \
-s snapshot.yaml \
--emit-attestation ./out \
--push ghcr.io/<your-fork>/aicr-evidence
# Copy to the per-source path printed in the emit 'copyTo' hint:
# recipes/evidence/<slug>/<source>/<bundle-digest>.yamlThis gate is warning-only and never blocks merge. See ADR-007 for the trust model. |
|
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:
📝 WalkthroughWalkthroughThe change records snapshot-observed NVIDIA driver state in typed recipe metadata and exposes it through the recipe response schema. Snapshot resolution handles preinstalled and absent driver states with provider-specific warnings and conditional overrides. Bundle generation registers Estimated code review effort: 4 (Complex) | ~60 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: 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/client/v1/gpu_driver_state.go`:
- Around line 59-74: The driverAbsentRemedy logic must distinguish GKE-COS from
other GKE profiles instead of branching on CriteriaServiceGKE alone. Pass the
resolved OS or full criteria into driverAbsentRemedy, return the COS-specific
wording only for GKE with COS, and use the generic GPU-Operator-managed remedy
for other GKE profiles; apply the same condition to the duplicated bundler
helper.
🪄 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: c7e1ca99-6ff1-4e0e-a26e-b6a1dd73ecd2
📒 Files selected for processing (24)
api/aicr/v1/server.yamldocs/contributor/validator.mddocs/integrator/aks-gpu-setup.mddocs/integrator/recipe-development.mddocs/user/cli-reference.mddocs/user/component-catalog.mdexamples/recipes/aks-training.yamlpkg/bundler/bundler_dra_annotation_parity_test.gopkg/bundler/deployer/helm/helm_test.gopkg/bundler/validations/checks.gopkg/bundler/validations/checks_test.gopkg/client/v1/aicr.gopkg/client/v1/aicr_test.gopkg/client/v1/gpu_driver_state.gopkg/client/v1/gpu_driver_state_test.gopkg/recipe/builder_test.gopkg/recipe/driver_root_lockstep_test.gopkg/recipe/metadata.gopkg/validator/v1/conversion_test.gorecipes/components/gpu-operator/values-aks-training.yamlrecipes/components/gpu-operator/values-aks.yamlrecipes/overlays/aks.yamlrecipes/registry.yamltests/uat/azure/cluster-config.yaml
281f0bc to
cfccc06
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/contributor/validator.md`:
- Line 671: Update the CheckDriverOwnershipCoherence description in the
validator documentation to explicitly include --set-file alongside --set and
--set-json as supported override sources, while preserving the existing
validation behavior and wording.
In `@docs/integrator/recipe-development.md`:
- Line 374: Clarify the snapshot-driven override paragraph to state that
explicit CLI --set flags retain higher precedence only during bundle generation,
not when running aicr recipe or ResolveRecipeFromSnapshot. Avoid implying that
--set is supported by the recipe-resolution commands, while preserving the
existing override precedence behavior.
🪄 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: 94b1e057-5098-4071-a8df-eaebfcaa27eb
📒 Files selected for processing (29)
api/aicr/v1/server.yamldocs/contributor/validator.mddocs/integrator/aks-gpu-setup.mddocs/integrator/recipe-development.mddocs/user/cli-reference.mddocs/user/component-catalog.mdexamples/recipes/aks-training.yamlpkg/bundler/bundler_dra_annotation_parity_test.gopkg/bundler/deployer/helm/helm_test.gopkg/bundler/validations/checks.gopkg/bundler/validations/checks_test.gopkg/client/v1/aicr.gopkg/client/v1/aicr_test.gopkg/client/v1/gpu_driver_state.gopkg/client/v1/gpu_driver_state_test.gopkg/recipe/builder_test.gopkg/recipe/driver_root_lockstep_test.gopkg/recipe/metadata.gopkg/recipe/nodewright_tuning_gate_test.gopkg/validator/v1/conversion_test.gorecipes/components/gpu-operator/values-aks-training.yamlrecipes/components/gpu-operator/values-aks.yamlrecipes/components/nodewright-customizations/manifests/tuning.yamlrecipes/overlays/a100-aks-training.yamlrecipes/overlays/aks.yamlrecipes/overlays/h100-aks-inference.yamlrecipes/overlays/h100-aks-training.yamlrecipes/registry.yamltests/uat/azure/cluster-config.yaml
cfccc06 to
3d9f22a
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 `@docs/user/component-catalog.md`:
- Line 79: Align the preinstalled-profile guarantee with
hasPreinstalledDriverProfile in pkg/client/v1/gpu_driver_state.go: require the
complete coordinated profile, including toolkit, gdrcopy, and driver-root
settings, rather than only driver.enabled=false; alternatively, narrow the
documentation claim to match the existing marker check. Ensure incomplete
overlays cannot receive preinstalled-driver behavior as a valid profile.
🪄 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: 6e17f1b9-85ff-478d-a3c0-99e6bc6b2d12
📒 Files selected for processing (18)
api/aicr/v1/server.yamldocs/contributor/validator.mddocs/integrator/aks-gpu-setup.mddocs/user/component-catalog.mdpkg/bundler/bundler_dra_annotation_parity_test.gopkg/bundler/deployer/helm/helm_test.gopkg/bundler/validations/checks.gopkg/bundler/validations/checks_test.gopkg/client/v1/aicr.gopkg/client/v1/aicr_test.gopkg/client/v1/gpu_driver_state.gopkg/client/v1/gpu_driver_state_test.gopkg/recipe/builder_test.gopkg/recipe/metadata.gopkg/recipe/query.gopkg/recipe/query_test.gopkg/validator/v1/conversion_test.gorecipes/registry.yaml
3d9f22a to
d00ee61
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/client/v1/gpu_driver_state.go`:
- Around line 404-417: Clear r.Metadata.GPUDriverState before the switch that
classifies state in the GPU driver observation flow, so gpuDriverUnknown and
gpuDriverNotObserved reset any prior value while preinstalled and absent states
still assign their corresponding values.
🪄 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: 0dd8a5c7-1718-4fae-a59d-1df417dba626
📒 Files selected for processing (34)
api/aicr/v1/server.yamldocs/contributor/validator.mddocs/integrator/aks-gpu-setup.mddocs/integrator/recipe-development.mddocs/user/cli-reference.mddocs/user/component-catalog.mdexamples/recipes/aks-training.yamlpkg/bundler/bundler.gopkg/bundler/bundler_dra_annotation_parity_test.gopkg/bundler/deployer/helm/helm_test.gopkg/bundler/validations/checks.gopkg/bundler/validations/checks_test.gopkg/bundler/validations/registry.gopkg/bundler/validations/registry_test.gopkg/client/v1/aicr.gopkg/client/v1/aicr_test.gopkg/client/v1/gpu_driver_state.gopkg/client/v1/gpu_driver_state_test.gopkg/recipe/builder_test.gopkg/recipe/driver_root_lockstep_test.gopkg/recipe/metadata.gopkg/recipe/nodewright_tuning_gate_test.gopkg/recipe/query.gopkg/recipe/query_test.gopkg/validator/v1/conversion_test.gorecipes/components/gpu-operator/values-aks-training.yamlrecipes/components/gpu-operator/values-aks.yamlrecipes/components/nodewright-customizations/manifests/tuning.yamlrecipes/overlays/a100-aks-training.yamlrecipes/overlays/aks.yamlrecipes/overlays/h100-aks-inference.yamlrecipes/overlays/h100-aks-training.yamlrecipes/registry.yamltests/uat/azure/cluster-config.yaml
d00ee61 to
fe630f4
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/recipe/driver_root_lockstep_test.go`:
- Around line 160-169: The root-path normalization currently occurs after the
earlier root-rejection guard, allowing equivalent spellings such as /./ or // to
bypass it. Normalize driverInstallDir before that guard, then reuse the
normalized value in the subsequent draRoot and opInstallDir comparisons while
preserving the empty-string unset behavior.
🪄 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: af1e2df3-23cc-4e3e-880b-15847acd23c7
📒 Files selected for processing (34)
api/aicr/v1/server.yamldocs/contributor/validator.mddocs/integrator/aks-gpu-setup.mddocs/integrator/recipe-development.mddocs/user/cli-reference.mddocs/user/component-catalog.mdexamples/recipes/aks-training.yamlpkg/bundler/bundler.gopkg/bundler/bundler_dra_annotation_parity_test.gopkg/bundler/deployer/helm/helm_test.gopkg/bundler/validations/checks.gopkg/bundler/validations/checks_test.gopkg/bundler/validations/registry.gopkg/bundler/validations/registry_test.gopkg/client/v1/aicr.gopkg/client/v1/aicr_test.gopkg/client/v1/gpu_driver_state.gopkg/client/v1/gpu_driver_state_test.gopkg/recipe/builder_test.gopkg/recipe/driver_root_lockstep_test.gopkg/recipe/metadata.gopkg/recipe/nodewright_tuning_gate_test.gopkg/recipe/query.gopkg/recipe/query_test.gopkg/validator/v1/conversion_test.gorecipes/components/gpu-operator/values-aks-training.yamlrecipes/components/gpu-operator/values-aks.yamlrecipes/components/nodewright-customizations/manifests/tuning.yamlrecipes/overlays/a100-aks-training.yamlrecipes/overlays/aks.yamlrecipes/overlays/h100-aks-inference.yamlrecipes/overlays/h100-aks-training.yamlrecipes/registry.yamltests/uat/azure/cluster-config.yaml
fe630f4 to
5db05f6
Compare
0a3a813 to
e2cc501
Compare
f3d065f to
6e7c5d8
Compare
fe6508d to
eee7076
Compare
|
@yuanchen8911 this PR now has merge conflicts with |
eee7076 to
cce10a6
Compare
d3998af to
db644c3
Compare
db644c3 to
6c31f06
Compare
2ed82f3 to
f7826f2
Compare
Adds the blocking bundle-generation validation CheckDriverOwnershipCoherence (registered on gpu-operator at severity: error). It evaluates the final effective values — recipe merge plus all --set/--set-json/--set-file overrides, resolved under canonical component names and registry aliases in the bundler's own application order — and blocks incoherent GPU driver-ownership profiles before a bundle is produced. Rule 1 (driverless cluster, gated on recorded snapshot state): when the snapshot observed no NVIDIA kernel driver (metadata.gpuDriverState=absent), an effective config with driver.enabled=false (or toolkit.enabled explicitly false) is blocked — deploying it would leave GPU nodes driverless. Empty state disarms the gate, so older recipes and GPU-less snapshots never trip it. Rule 2 (DRA driver-root lockstep, metadata-independent): with driver.enabled=true, nvidia-dra-driver-gpu.nvidiaDriverRoot must equal gpu-operator hostPaths.driverInstallDir or CDI spec generation fails. With a preinstalled driver, the DRA root must avoid the unpopulated operator container root and may intentionally differ from hostPaths.driverInstallDir. This also catches legacy pre-NVIDIA#1756 recipes that carry no recorded state. Two adjacent hardening fixes on the bundler value path the gate depends on: extractComponentValues now fails closed on a value-resolution error instead of logging a warning and rendering the component from an empty map; and component validation failures preserve an already-coded error (ErrCodeTimeout / ErrCodeInternal) instead of flattening every failure to ErrCodeInvalidRequest. Fixes: NVIDIA#1757 Related: NVIDIA#1756 Signed-off-by: Yuan Chen <yuanchen97@gmail.com>
f7826f2 to
77b66ee
Compare
Summary
This PR supersedes #1756's interim AKS-only warn-text scoping with the fully provider/OS-aware remedy.
Adds the blocking bundle-generation validation
CheckDriverOwnershipCoherence(registered ongpu-operatoratseverity: error). It evaluates the final effective values — recipe merge plus all--set/--set-json/--set-fileoverrides, resolved under canonical component names and registry aliases in the bundler's own application order — and blocks incoherent GPU driver-ownership profiles before a bundle is produced.Motivation / Context
PR #1756 ships the AKS default flip to the Azure-managed GPU driver profile without a bundle-time guard; this is the release-blocking coherence check agreed in its review. It resurrects the reference implementation from #1756's history (
c412d598) and fixes the three review findings the issue lists: honor the complete override tuple (not--set gpuoperator:driver.enabled=truealone), resolve overrides under canonical names and registry aliases, and gate legacy pre-flip recipes via a metadata-independent effective-values lockstep rule.Fixes: #1757
Related: #1756
Type of Change
Component(s) Affected
cmd/aicr,pkg/cli)cmd/aicrd,pkg/server)pkg/recipe)pkg/bundler,pkg/component/*)pkg/collector,pkg/snapshotter)pkg/validator)pkg/errors,pkg/k8s)docs/,examples/)Implementation Notes
Rule 1 — driverless cluster (gated on recorded snapshot state). Snapshot-driven resolution (
applyGPUDriverAutoOverride) now records the observed NVIDIA kernel driver state inmetadata.gpuDriverState(preinstalled/absent; empty = unknown, gate disarmed — older recipes and GPU-less snapshots never trip it). When the snapshot observed no driver on the sampled GPU node, an effective config withdriver.enabled=false(ortoolkit.enabledexplicitly false) is blocked: deploying it would leave GPU nodes driverless. The gate clears when the effective values havedriver.enabled=trueandtoolkit.enablednot explicitly false; a partial flip is still caught because Rule 2 independently enforces the DRA driver-root leg.operator.runtimeClassis deliberately not validated — the toolkit derives its containerd handler name from it, so any consistent value works (the documented tuple setsnvidiaby convention).Rule 2 — DRA driver-root lockstep (metadata-independent). With
driver.enabled=true,nvidia-dra-driver-gpu.nvidiaDriverRootmust equalgpu-operator hostPaths.driverInstallDir(default/run/nvidia/driver) or CDI spec generation fails (issue #1087'sTestDriverRootLockstepinvariant, enforced on effective values at bundle time). Withdriver.enabled=false, the root must not be the operator container root/run/nvidia/driver— nothing populates it in that mode. This is the signature of a legacy pre-#1756 recipe (stalevaluesFileresolution + old baked DRA override) and catches those recipes even though they carry no recorded state.Override resolution.
componentOverrideKeys/mergeOverridesAcrossKeysare reimplemented locally inpkg/bundler/validations(importingpkg/bundlerwould be a cycle), mirroring the bundler exactly: exact name first, then registryvalueOverrideKeysaliases; scalar--setapplied before typed--set-json/--set-file; theenabledtoggle stripped. A recipe-side resolution failure fails closed on both paths: the gate blocks it, andextractComponentValuesnow also returns a blockingErrCodeInternal(rather than warning and rendering the component from an empty map), so neither can emit a bundle whose driver ownership could not be verified. Override-apply failures are blocking too:ApplyMapOverridesapplies scalar--setpaths in Go's randomized map-iteration order, so an overlapping pair (e.g.gpuoperator:a.b=1alongsidegpuoperator:a=2) can apply cleanly child-first during extraction yet fail parent-first when the gate reapplies them — a silent skip there would disarm the gate for exactly the override sets whose effective values it cannot reconstruct.Provider-aware warning. The resolution-time mismatch warning now derives its remedy from
criteria.serviceandcriteria.os: AKS → recreate pools without--gpu-driver noneor the four-flag override tuple; GKE+cos→ COS-only wording (the operator cannot install the driver on COS; use the GKE-managed driver installgpu-driver-version); GKE+ubuntu→ the GPU-Operator-managed override set extended with--set gpuoperator:hostPaths.driverInstallDir=/run/nvidia/driver(the only GKE node image where the pinned operator v26.3.2 supports driver management; GKE Google-installer profiles pin both driver roots to/home/kubernetes/bin/nvidia, so the remedy must move both roots or the DRA lockstep rule would block the bundle it recommends); any other GKE OS (unknown,any, or one GKE does not offer) → the combined wording, so an off-catalogservice: gkerecipe never gets an unsupported operator-managed recommendation; other → generic reprovision wording plus the tuple. The remedy helper is deliberately duplicated betweenpkg/client/v1andpkg/bundler/validations(documented in both; a shared package for two small helpers was rejected).Type promotion.
RecipeResult's anonymous metadata struct is promoted to the namedrecipe.RecipeResultMetadatato carry the new field;DeepCopycopies it, and the OpenAPIRecipeResponseschema documentsgpuDriverState.Two synthetic bundler test fixtures (
bundler_dra_annotation_parity_test.go) gained an explicitnvidiaDriverRootoverride — they previously modeled an incoherent recipe (operator-managed driver, no DRA root) that the new check correctly blocks.Cross-review fix set (applied after the multi-reviewer pass): fail closed with a blocking error when a component's effective values cannot be resolved (see Override resolution above); resolve
--setenabled toggles with the bundler's exact semantics (canonical-name-wins merge across registry aliases,strconv.ParseBoolsoenabled=0counts);path.Cleanthe driver-root comparisons so trailing-slash spellings compare equal in both Rule 2 directions; reject an explicithostPaths.driverInstallDirof/regardless of DRA presence or equality (the #1106 regression — runc refuses a bind-mount destination of/); projectmetadata.gpuDriverStatein the hydrated query output soaicr query/SelectFromRecipematches the recipe YAML and OpenAPI schema; scope the GKE remedy wording to COS node images; fail closed when override reapplication fails inside the gate (see Override resolution above); reject a recordedmetadata.gpuDriverStateoutside the two documented constants — nothing validates the field at the load/adopt boundaries, so a typo'd spelling (Absent) in a loaded or hand-edited recipe would otherwise silently degrade to the deliberate empty=unknown disarm state and clear Rule 1. A second cross-review round added: OS-aware wording for Rule 2's legacy-recipe alternative clause (GKE+COS must not be told to use the operator-managed tuple the operator cannot deploy there — it gets a DRA-root retarget at the GKE-managed install path instead); resolver error codes preserved through the fail-closed wrap (anErrCodeInternal/ErrCodeTimeoutresolution failure is no longer reclassified asErrCodeInvalidRequest, so SDK/server consumers keep retryability and HTTP-status fidelity); and a surfaced bundler warning when gpu-operator is excluded from the bundle (--set gpuoperator:enabled=false, recipe-level disable, or the bundlers filter) while the recorded driver state isabsent— exclusion is deliberate ("satisfied externally") and subset bundles are first-class, so it warns rather than blocks, but nothing in such a bundle installs a driver and a silent skip would hide that.Guessed-value remedies are suppressed. When the declared
driverInstallDiris rejected, when the DRA root is invalid, or when either value is dynamic (bundle-time-deferred), the lockstep switch is skipped — the rejection already blocks the bundle, and a second remedy computed from a guessed default or a stale static value would mislead. The legacy-recipe message says "commonly the signature of" (user-created states can produce the same values) and its override tuple is GKE-aware.Invalid and relative driver-root declarations fail closed. Present-but-invalid declarations are rejected instead of treated as absent: a null/empty/non-string DRA
nvidiaDriverRoot, and a null/non-maphostPathsor non-stringdriverInstallDir(Helm null-coalescing deletes chart defaults; the ClusterPolicy CRD types the field as string). Declared roots that clean to a relative path are rejected too (path.IsAbsafterpath.Clean): host-path mounts require absolute paths, and a relative spelling of the operator root (run/nvidia/driver) compares unequal to/run/nvidia/driver, so withdriver.enabled=falseno Rule 2 branch would fire and the broken mount would bundle.Testing
New coverage: a 32-case table for
CheckDriverOwnershipCoherence(including the partial-flip regression test for review finding 1, canonical-name + alias +--set-jsonoverride resolution, the legacy-recipe signature, unresolvable-values fail-closed errors, canonical-beats-alias andenabled=0toggle semantics, trailing-slash roots in both directions, anddriverInstallDir=/with and without a DRA ref), a hydrated-query projection test formetadata.gpuDriverState(recorded vs omitted),Metadata.GPUDriverStaterecording assertions for preinstalled/absent/unknown/not-observed, andDeepCopycoverage for the new field. Invalid/relative-root cases:nvidiaDriverRootnull/empty/bool,hostPathsnull/non-map,driverInstallDirbool/null, relative DRA root with driver off (the Rule 2 bypass), relativedriverInstallDir, a matching relative pair (both rejected), and a..-spelling legacy-root regression; fail-closed override-reapplication errors on all three legs (scalar--set, typed--set-json, and the DRA component); unrecognized recorded-state rejection (typo'dAbsentblocked, reported alongside a Rule 2 finding without masking it, and still firing when values resolution itself fails); remedy-wording branches for GKE+COS (COS-only), GKE+ubuntu (operator-managed), GKE with unknown OS (combined), and GKE+rhel (no such node image → combined, no unsupported recommendation); Rule 2 legacy-remedy OS branches (GKE+COS → no operator-managed tuple, GKE+ubuntu → five-flag tuple, unknown GKE OS → both paths); a resolver-code preservation test (TestEffectiveComponentValues_PreservesResolverCode); a 7-case excluded-driver-installer warning table (TestFilterEnabledComponents_ExcludedDriverInstallerWarning); GKE Google-installer-profile lockstep regressions (remedy carries the fifthhostPaths.driverInstallDirflag; the five-flag tuple applied to that profile passes both rules).This branch is rebased onto current
main;make qualifyruns on the rebased result (#1756has merged).go build,go test, andgolangci-linton the affected packages are all clean.Known follow-ups (non-blocking):
gpu-operator-ocpis registered outside the gate (OCP ships DRA disabled; no supported config trips it today) — coverage note for a follow-up. Per-OS install capability (e.g. GKE-COS with a deliberatedriver.enabled=true) is out of the coherence check's scope by design; documented incomponent-catalog.mdwithgpu-operator-healthas the deploy-time backstop.Scope & follow-up work
This PR is deliberately scoped to the bundle-time coherence gate for #1757. A multi-reviewer cross-review produced a broader set of hardening changes; the small, gate-adjacent ones are kept here and the larger, orthogonal ones are split out to keep the PR focused and reviewable. Kept in this PR:
extractComponentValuesreturns a blocking error instead of warning and rendering from an empty map.ErrCodeTimeout/ErrCodeInternal) at theMakecall site instead of flattening every failure toErrCodeInvalidRequest(which returned a non-retryable HTTP 400 and could expose the internal cause on a 4xx).The gate runs on both bundle paths:
DefaultBundler.Make(the CLI and the server'sMakeBundle) and the publicClient.BundleComponentsSDK path. That SDK preflight is baseline #1757 coverage — an external Go caller ofBundleComponentswould otherwise produce component bundles the CLI/server reject — so it is intentionally retained; only the exact-value reuse (follow-up A) is deferred.Deferred to their own follow-up PRs (each independently reasonable, none required for #1757). Tracked in #1873 (A, B — gate-integrity hardening) and #1874 (C, D — recipe/SDK cleanups):
DefaultBundler.Make(CLI and the server'sMakeBundle) and the publicClient.BundleComponentsSDK path — but each currently self-resolves component values independently of the read used to emit the bundle. Follow-up: resolve values once and validate the exact maps that are emitted on both paths, so a mutable provider cannot change values between check and emit. Reachable via--data/LayeredDataProvider(external files are re-read per call). Acceptance criterion: validation examines exactly the values emitted, proven by aFilesystemSourcemutation test.argocd-helmchart so a--setat install cannot bypass the bundle-time verdict.ComponentRef.Namevalidation inPrepareAndValidate.facadeResultFromInternal(omit disabled components from the facade's deployable set).Two carry-over open questions from the cross-review, applicable to the gate as written (not introduced here):
pkg/bundler/validationsandpkg/bundler(import-cycle-driven), kept in sync by comment only — a golden test or shared package would prevent silent drift.driver.enabled=falseand a DRAnvidiaDriverRootthat cleans to/run/nvidia/driver. OSS overlays (OKE, GKE-COS, AKS) are confirmed coherent; internal overlays should be confirmed not to ship that combination.Risk Assessment
Rollout notes: The check is fail-closed on two previously-undetected misconfigurations. Recipes generated by this AICR version are coherent by construction; legacy pre-#1756 AKS recipes are blocked with an actionable message (regenerate, or supply the four-flag override set). No migration steps beyond those documented in
docs/integrator/aks-gpu-setup.md.Checklist
make testwith-race)make lint)git commit -S) — GPG signing info