feat: add support for helm vendoring#846
Conversation
19b5e50 to
fd3eee4
Compare
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/bundler/deployer/localformat/writer_test.go (1)
37-50:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winMove
res.Foldersaccess after the error check to avoid nil dereference in failing paths.Line 48/115/175/258/311 reads
res.Foldersbefore validatingerr. IfWritefails and returnsres == nil, the test panics and hides the real failure reason.Suggested fix pattern (apply to each affected test)
res, err := localformat.Write(context.Background(), localformat.Options{ ... }) -folders := res.Folders if err != nil { t.Fatalf("Write: %v", err) } +folders := res.FoldersAlso applies to: 82-117, 141-177, 227-260, 300-313
🤖 Prompt for 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. In `@pkg/bundler/deployer/localformat/writer_test.go` around lines 37 - 50, The tests call localformat.Write(...) and immediately access res.Folders before checking err, which can nil-deref if Write fails; in each affected test (e.g., the block that calls localformat.Write in writer_test.go) move the statement "folders := res.Folders" (or any use of res) to after the error check "if err != nil { t.Fatalf... }" so you first assert err is nil and only then read res.Folders; update all similar occurrences around the localformat.Write calls referenced (lines near the blocks using res, err, folders) to follow this pattern.
🤖 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 `@api/aicr/v1/server.yaml`:
- Around line 894-903: Update the parameter description for the boolean
"vendor-charts" option in the schema so it documents runtime prerequisites and
failure modes: mention that vendoring requires a working Helm client and any
necessary upstream auth/registry credentials on the host performing bundling
(Helm and auth must be available at bundle time), and state the observable
failure behavior when those prerequisites are missing (the bundle request will
fail and return an error indicating the missing Helm/tooling or credentials
rather than producing a vendored chart). Edit the existing description text (the
"vendor-charts" description block adjacent to the schema:type boolean/default
false) to append these prerequisite and failure-mode sentences so API clients
can reason about outcomes without cross-referencing other docs.
In `@docs/user/cli-reference.md`:
- Around line 1107-1173: The fenced code block that shows the bundle layout
("my-bundle/ ...") in the "Vendoring Charts for Air-Gap" section is missing a
language identifier and triggers markdownlint; update the opening fence for that
block to include a language specifier (e.g., change ``` to ```text) so the block
becomes fenced with a language, targeting the block that begins with
"my-bundle/" in docs/user/cli-reference.md.
In `@pkg/bundler/deployer/localformat/provenance.go`:
- Around line 80-112: Change WriteProvenance to accept a context.Context
parameter and use it for cancellable I/O: update the signature of
WriteProvenance(ctx context.Context, outputDir string, records []VendorRecord),
propagate the new ctx through its callers in pkg/bundler/deployer/helm/helm.go
and pkg/bundler/deployer/argocd/argocd.go, check ctx.Err() before doing file
operations (after computing abs via deployer.SafeJoin), and perform the file
write in a context-aware way (e.g., start the write in a goroutine and select on
ctx.Done() to cancel or return an error if canceled, or use an OS file handle
and ensure you abort/close on ctx cancellation) instead of directly calling
os.WriteFile; keep existing error wrapping and return values, and ensure you
still use ProvenanceFileName and deployer.SafeJoin as before.
In `@pkg/cli/bundle.go`:
- Around line 400-409: Update the help text for the vendor-charts CLI flag so it
references the actual output filename provenance.yaml instead of
provenance.json: locate the cli.BoolFlag with Name: "vendor-charts" in bundle.go
and edit the Usage string to replace "provenance.json" with "provenance.yaml" so
the documented filename matches the vendoring behavior.
---
Outside diff comments:
In `@pkg/bundler/deployer/localformat/writer_test.go`:
- Around line 37-50: The tests call localformat.Write(...) and immediately
access res.Folders before checking err, which can nil-deref if Write fails; in
each affected test (e.g., the block that calls localformat.Write in
writer_test.go) move the statement "folders := res.Folders" (or any use of res)
to after the error check "if err != nil { t.Fatalf... }" so you first assert err
is nil and only then read res.Folders; update all similar occurrences around the
localformat.Write calls referenced (lines near the blocks using res, err,
folders) to follow this pattern.
🪄 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: 810fafe1-1721-4e55-b602-055beb726d28
📒 Files selected for processing (28)
api/aicr/v1/server.yamldocs/contributor/api-server.mddocs/contributor/cli.mddocs/user/api-reference.mddocs/user/cli-reference.mdpkg/bundler/bundler.gopkg/bundler/config/config.gopkg/bundler/config/config_test.gopkg/bundler/deployer/argocd/argocd.gopkg/bundler/deployer/argocdhelm/argocdhelm.gopkg/bundler/deployer/helm/helm.gopkg/bundler/deployer/localformat/provenance.gopkg/bundler/deployer/localformat/provenance_test.gopkg/bundler/deployer/localformat/templates/wrapper-chart.yaml.tmplpkg/bundler/deployer/localformat/vendor.gopkg/bundler/deployer/localformat/vendor_folder.gopkg/bundler/deployer/localformat/vendor_test.gopkg/bundler/deployer/localformat/vendor_wrapper.gopkg/bundler/deployer/localformat/vendor_wrapper_test.gopkg/bundler/deployer/localformat/vendor_write_test.gopkg/bundler/deployer/localformat/writer.gopkg/bundler/deployer/localformat/writer_test.gopkg/bundler/handler.gopkg/cli/bundle.gopkg/config/config.gopkg/config/resolve.gopkg/defaults/timeouts.gotests/chainsaw/cli/bundle-vendor-charts/chainsaw-test.yaml
Coverage Report ✅
Coverage BadgeMerging this branch changes the coverage (4 decrease, 2 increase)
Coverage by fileChanged files (no unit tests)
Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code. |
cdc1084 to
01afd79
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (2)
docs/user/cli-reference.md (1)
1122-1140:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix fenced code block language identifier.
The fenced code block showing the bundle layout is missing a language specifier, triggering a markdownlint warning (MD040). Add
textas the language identifier.📝 Suggested fix
-``` +```text my-bundle/ 001-gpu-operator/ Chart.yaml # wrapper, declares the vendored subchartBased on learnings: As per coding guidelines, ensure all markdown files pass yamllint/markdownlint validation before submitting.
🤖 Prompt for 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. In `@docs/user/cli-reference.md` around lines 1122 - 1140, The fenced code block showing the bundle layout in docs/user/cli-reference.md is missing a language identifier (MD040); update the opening fence from ``` to ```text so the block starts with ```text to satisfy markdownlint and mark the snippet as plain text.pkg/bundler/deployer/localformat/provenance.go (1)
80-112:⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy liftAdd context-aware cancellation to provenance file writes.
WriteProvenanceperforms filesystem I/O but has nocontext.Contextparameter, so callers cannot enforce timeout/cancellation during bundle generation.Proposed direction
-func WriteProvenance(outputDir string, records []VendorRecord) (string, int64, error) { +func WriteProvenance(ctx context.Context, outputDir string, records []VendorRecord) (string, int64, error) { + if err := ctx.Err(); err != nil { + return "", 0, errors.Wrap(errors.ErrCodeTimeout, "context cancelled", err) + } if len(records) == 0 { return "", 0, errors.New(errors.ErrCodeInternal, "WriteProvenance: empty records slice") } ... + if err := ctx.Err(); err != nil { + return "", 0, errors.Wrap(errors.ErrCodeTimeout, "context cancelled", err) + } if err = os.WriteFile(abs, body, 0o644); err != nil { ... }Also update all call sites to pass the already-available request/bundle context.
As per coding guidelines: "All I/O operations must use context with timeout" and "Never use
context.Background()in I/O methods."🤖 Prompt for 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. In `@pkg/bundler/deployer/localformat/provenance.go` around lines 80 - 112, Change WriteProvenance to accept a context.Context (e.g., func WriteProvenance(ctx context.Context, outputDir string, records []VendorRecord) ...) and update all call sites to pass the request/bundle context; keep the existing sort/marshal and SafeJoin (deployer.SafeJoin) usage but perform a ctx.Err() check before/after expensive steps and use a context-aware file write instead of os.WriteFile (open the file with os.Create/os.OpenFile and perform the write while watching ctx.Done(), aborting and returning context.Canceled or a wrapped error if canceled); ensure the file is closed on all paths and preserve existing error wrapping and returned values (file path and byte length) for provenanceFile/ProvenanceFileName flows.
🤖 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/bundler/config/config_test.go`:
- Around line 84-94: The test TestConfigVendorCharts uses three separate
assertions; convert it into a table-driven test to match the suite pattern:
define a slice of test cases each with a name, optional config option (nil or
WithVendorCharts(true/false)), and expected bool, then loop over cases calling
NewConfig(...) and c.VendorCharts() and use t.Run(name, func(t *testing.T){ if
got != want { t.Errorf(...) } }). Reference TestConfigVendorCharts, NewConfig,
WithVendorCharts and VendorCharts when locating the test to replace.
In `@pkg/bundler/deployer/localformat/vendor_folder.go`:
- Around line 205-267: The loop in writeMixedManifests can run long and should
respect cancellation; update writeMixedManifests to accept a context.Context
(add ctx parameter to its signature and update all callers), and at the top of
the for _, p := range sortedPaths loop do a ctx cancellation check (select {
case <-ctx.Done(): return nil, errors.Wrap(errors.ErrCodeInternal, "operation
cancelled", ctx.Err()) default: }) before calling manifest.Render,
injectPostInstallHooks or writeFile so work stops promptly on cancellation;
ensure the new ctx is threaded through any helper calls that may need it.
In `@pkg/bundler/deployer/localformat/vendor_test.go`:
- Around line 26-48: The test TestValidateForPull currently only checks presence
of an error (wantErr) but ignores the expected error code in the test vector
(code); update the loop that calls validateForPull to assert the specific error
code: when tt.wantErr is true ensure err != nil and if tt.code != "" type-assert
the returned error to an interface with Code() string (or use the concrete
structured error type used in this package) and compare Code() == tt.code,
falling back to checking err.Error() contains tt.code if the structured type is
not present; when tt.wantErr is false ensure err == nil. Reference
validateForPull and the test table (tests / TestValidateForPull) to locate where
to add these assertions.
In `@pkg/bundler/deployer/localformat/vendor_write_test.go`:
- Around line 171-172: The test currently ignores the error returned by
os.ReadDir(outDir) which can lead to false-positive passes; update the call that
sets entries (the os.ReadDir(outDir) invocation and its result assigned to
entries) to capture the error, assert or fail on non-nil error (e.g., t.Fatalf
or require.NoError) before iterating over entries (for _, e := range entries) so
the test fails loudly when directory enumeration fails.
In `@pkg/bundler/deployer/localformat/vendor.go`:
- Around line 225-231: Replace the substring-only detection with sentinel error
checks before the fallback: in the block that examines runErr and combined
(using symbols runErr and combined), first check errors.Is(runErr,
exec.ErrNotFound) || errors.Is(runErr, os.ErrNotExist) and if true return the
wrapped errors.Wrap(errors.ErrCodeUnavailable, "vendor-charts: helm CLI not
found on PATH (install helm or unset --vendor-charts)", runErr); only if those
sentinel checks fail, keep the existing strings.Contains(combined, "...")
fallback to preserve behavior for non-sentinel cases.
---
Duplicate comments:
In `@docs/user/cli-reference.md`:
- Around line 1122-1140: The fenced code block showing the bundle layout in
docs/user/cli-reference.md is missing a language identifier (MD040); update the
opening fence from ``` to ```text so the block starts with ```text to satisfy
markdownlint and mark the snippet as plain text.
In `@pkg/bundler/deployer/localformat/provenance.go`:
- Around line 80-112: Change WriteProvenance to accept a context.Context (e.g.,
func WriteProvenance(ctx context.Context, outputDir string, records
[]VendorRecord) ...) and update all call sites to pass the request/bundle
context; keep the existing sort/marshal and SafeJoin (deployer.SafeJoin) usage
but perform a ctx.Err() check before/after expensive steps and use a
context-aware file write instead of os.WriteFile (open the file with
os.Create/os.OpenFile and perform the write while watching ctx.Done(), aborting
and returning context.Canceled or a wrapped error if canceled); ensure the file
is closed on all paths and preserve existing error wrapping and returned values
(file path and byte length) for provenanceFile/ProvenanceFileName flows.
🪄 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: 20c62d1c-1d9b-446a-8e71-ed9098ae792f
📒 Files selected for processing (28)
api/aicr/v1/server.yamldocs/contributor/api-server.mddocs/contributor/cli.mddocs/user/api-reference.mddocs/user/cli-reference.mdpkg/bundler/bundler.gopkg/bundler/config/config.gopkg/bundler/config/config_test.gopkg/bundler/deployer/argocd/argocd.gopkg/bundler/deployer/argocdhelm/argocdhelm.gopkg/bundler/deployer/helm/helm.gopkg/bundler/deployer/localformat/provenance.gopkg/bundler/deployer/localformat/provenance_test.gopkg/bundler/deployer/localformat/templates/wrapper-chart.yaml.tmplpkg/bundler/deployer/localformat/vendor.gopkg/bundler/deployer/localformat/vendor_folder.gopkg/bundler/deployer/localformat/vendor_test.gopkg/bundler/deployer/localformat/vendor_wrapper.gopkg/bundler/deployer/localformat/vendor_wrapper_test.gopkg/bundler/deployer/localformat/vendor_write_test.gopkg/bundler/deployer/localformat/writer.gopkg/bundler/deployer/localformat/writer_test.gopkg/bundler/handler.gopkg/cli/bundle.gopkg/config/config.gopkg/config/resolve.gopkg/defaults/timeouts.gotests/chainsaw/cli/bundle-vendor-charts/chainsaw-test.yaml
01afd79 to
62fbb16
Compare
mchmarny
left a comment
There was a problem hiding this comment.
Solid shape overall — the ChartPuller interface boundary, the documented license rationale for shelling out vs SDK, the WriteResult struct for forward-compat, and the hermetic chainsaw fake-helm shim are all clean choices. The provenance.yaml audit log emitted from all three deployers is exactly the right place for the bundle-time freeze record.
One medium concern on validateForPull: the HTTP(S) branch of helm pull passes chartName as a separate argv token, so a chart name beginning with -- (e.g., --insecure-skip-tls-verify) injects as a helm flag rather than a chart name. The OCI branch is safe (single URL token). Recipes are repo-controlled today, but --vendor-charts also flows through the API surface so input validation at the boundary is the right defense.
Three lows: user-visible error message references provenance.json while the file is provenance.yaml (five stale references total, only helm.go:204 is user-visible); injectHookOnDoc can silently overwrite existing annotations on an unexpected map type; helm.sh/hook-delete-policy: before-hook-creation is unconditional and may surprise mixed-component recipes that include stateful resources.
CI: lint, build, security scan, malware-scan all green at review time; Test, E2E, analyze, GPU smoke still in flight; mergeable_state: blocked (review gate). Nothing blocks merge from this review.
There was a problem hiding this comment.
Actionable comments posted: 5
♻️ Duplicate comments (1)
pkg/bundler/deployer/helm/helm.go (1)
99-103:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix stale
provenance.jsonreferences toprovenance.yaml.Line 204 surfaces
"failed to generate provenance.json"even though the writer emitsprovenance.yaml; this can mislead operators during failures. The same mismatch appears in the field comment near Line 100.Suggested patch
- // vendorRecords is populated by Generate when VendorCharts is on. - // Captured here so generateProvenanceFile can write provenance.json + // vendorRecords is populated by Generate when VendorCharts is on. + // Captured here so Generate can write provenance.yaml // without re-threading the slice through every helper call. The // field is unset (nil) when VendorCharts is off. vendorRecords []localformat.VendorRecord @@ - // Generate provenance.json for vendored bundles. Written before + // Generate provenance.yaml for vendored bundles. Written before // checksums.txt so the audit file is itself checksummed. if len(g.vendorRecords) > 0 { provPath, provSize, provErr := localformat.WriteProvenance(ctx, outputDir, g.vendorRecords) if provErr != nil { return nil, errors.Wrap(errors.ErrCodeInternal, - "failed to generate provenance.json", provErr) + "failed to generate provenance.yaml", provErr) }Also applies to: 198-205
🤖 Prompt for 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. In `@pkg/bundler/deployer/helm/helm.go` around lines 99 - 103, The struct field comment for vendorRecords and the error message inside generateProvenanceFile incorrectly reference "provenance.json" even though the writer emits "provenance.yaml"; update the comment on vendorRecords to say provenance.yaml and change the error string in generateProvenanceFile (the log/return that says "failed to generate provenance.json") to "failed to generate provenance.yaml" so both documentation and runtime errors match the actual output file name.
🤖 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/bundler/deployer/localformat/vendor_test.go`:
- Around line 82-112: Test table only exercised substring matching because every
runErr was stderrors.New("exit status 1"); add cases that pass the sentinel
errors so the errors.Is(...) branch in classifyHelmCLIError is covered. Update
TestClassifyHelmCLIError's test struct to include a runErr field and add rows
with runErr = exec.ErrNotFound and runErr = os.ErrNotExist (with appropriate
names and expected ErrCodeUnavailable), and use that runErr when calling
classifyHelmCLIError instead of the hardcoded stderrors.New; this will ensure
the typed sentinel-path is regression-proof.
In `@pkg/bundler/deployer/localformat/vendor_write_test.go`:
- Around line 248-259: The test calls localformat.Write with
context.Background(), which can hang; replace that with a timeout context (e.g.,
ctx, cancel := context.WithTimeout(context.Background(), time.Second*X)) and
pass ctx into localformat.Write, ensuring you defer cancel() to release
resources; update the call site around the localformat.Write invocation
(referencing localformat.Write, localformat.Options and fakePuller) and
import/time usage accordingly.
In `@pkg/bundler/deployer/localformat/writer.go`:
- Around line 49-65: The comments on the WriteResult type still refer to the old
artifact name "provenance.json"; update those doc comments (on WriteResult, its
VendoredCharts field, and the other similar comment block near the end of the
file) to mention "provenance.yaml" (and update any reference to WriteProvenance
usage text accordingly) so the exported API docs correctly state the emitted
artifact name.
- Around line 127-135: The guard currently multiplies component count by 2
unconditionally and rejects bundles in vendored mode; change the condition to
only apply the 2× bound when opts.VendorCharts is false. Specifically, in the
block that checks "if 2*len(opts.Components) > 999" use a conditional that uses
len(opts.Components) > 999 when opts.VendorCharts is true, otherwise keep the
2*len(...) > 999 check; update the error path that returns WriteResult{} and
errors.New(...) accordingly so valid vendored bundles aren't rejected.
In `@pkg/defaults/timeouts.go`:
- Line 544: The comment above the Helm timeouts in pkg/defaults/timeouts.go is
misleadingly labeled "Helm SDK chart-pull"; update the comment to clarify that
these timeouts apply to the bundle-time --vendor-charts path which currently
uses CLIChartPuller (exec.CommandContext invoking `helm pull`), and optionally
note that an SDKChartPuller could be supported in the future—mention
CLIChartPuller and SDKChartPuller by name so readers know which implementation
the timeout refers to.
---
Duplicate comments:
In `@pkg/bundler/deployer/helm/helm.go`:
- Around line 99-103: The struct field comment for vendorRecords and the error
message inside generateProvenanceFile incorrectly reference "provenance.json"
even though the writer emits "provenance.yaml"; update the comment on
vendorRecords to say provenance.yaml and change the error string in
generateProvenanceFile (the log/return that says "failed to generate
provenance.json") to "failed to generate provenance.yaml" so both documentation
and runtime errors match the actual output file name.
🪄 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: e56a125a-8ceb-4d38-a9fe-62e533ebade5
📒 Files selected for processing (28)
api/aicr/v1/server.yamldocs/contributor/api-server.mddocs/contributor/cli.mddocs/user/api-reference.mddocs/user/cli-reference.mdpkg/bundler/bundler.gopkg/bundler/config/config.gopkg/bundler/config/config_test.gopkg/bundler/deployer/argocd/argocd.gopkg/bundler/deployer/argocdhelm/argocdhelm.gopkg/bundler/deployer/helm/helm.gopkg/bundler/deployer/localformat/provenance.gopkg/bundler/deployer/localformat/provenance_test.gopkg/bundler/deployer/localformat/templates/wrapper-chart.yaml.tmplpkg/bundler/deployer/localformat/vendor.gopkg/bundler/deployer/localformat/vendor_folder.gopkg/bundler/deployer/localformat/vendor_test.gopkg/bundler/deployer/localformat/vendor_wrapper.gopkg/bundler/deployer/localformat/vendor_wrapper_test.gopkg/bundler/deployer/localformat/vendor_write_test.gopkg/bundler/deployer/localformat/writer.gopkg/bundler/deployer/localformat/writer_test.gopkg/bundler/handler.gopkg/cli/bundle.gopkg/config/config.gopkg/config/resolve.gopkg/defaults/timeouts.gotests/chainsaw/cli/bundle-vendor-charts/chainsaw-test.yaml
62fbb16 to
7ddb60e
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/bundler/deployer/argocd/argocd.go (1)
260-266:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReset
vendorRecordsat the start ofGenerateto avoid stale reads after early failures.If
Generatereturns before the new assignment (e.g., early error path),VendorRecords()can expose records from a previous successful call on the sameGeneratorinstance.🛠️ Minimal fix
func (g *Generator) Generate(ctx context.Context, outputDir string) (*deployer.Output, error) { start := time.Now() + g.vendorRecords = nil output := &deployer.Output{ Files: make([]string, 0), }Also applies to: 315-327
🤖 Prompt for 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. In `@pkg/bundler/deployer/argocd/argocd.go` around lines 260 - 266, Reset the Generator's vendorRecords at the start of Generator.Generate to avoid exposing stale data if Generate returns early: set g.vendorRecords = nil (or an empty struct/value as appropriate) at the top of Generate before any early-returning work so VendorRecords() cannot return previous-call data; apply the same reset in the other Generate-like path referenced around the 315-327 section to ensure both code paths clear g.vendorRecords before proceeding.
🤖 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/api-reference.md`:
- Line 332: Update the `vendor-charts` API reference row in
docs/user/api-reference.md to append a short failure clause stating that the
request will fail if prerequisites are missing, and that it returns the same
status/code behavior as documented in server.yaml; specifically, modify the
`vendor-charts` table cell (the line mentioning provenance.yaml and Helm
binary/credentials) to add a brief phrase like "request fails (see server.yaml
for status/code)" so consumers know the observable failure mode without needing
to cross-reference.
In `@pkg/bundler/deployer/localformat/vendor_folder.go`:
- Around line 89-95: After calling puller.Pull (which returns tgz, rec, tarball)
ensure VendorRecord.TarballName is canonicalized to the actual tarball filename
written by writeVendoredHelmFolder: set rec.TarballName = tarball immediately
after the successful pull and before writing the tarball/provenance so
provenance.yaml points to the real file; apply the same fix in the other pull
site (the second pull block around the later lines) so both uses of
rec.TarballName reflect the written charts/<tarball>.
In `@pkg/cli/bundle.go`:
- Around line 402-407: The help text for the --vendor-charts flag (the Usage
string in bundle.go that describes vendoring Helm charts) overstates offline
capabilities; update that Usage text to clarify that vendoring removes Helm
chart registry egress only and does not guarantee full offline deployability of
all bundle artifacts or external dependencies, and ensure the message references
that vendoring records provenance (name, version, source URL, SHA256) but may
still require network access for other assets; edit the string associated with
--vendor-charts/Usage to reflect this narrower scope.
In `@tests/chainsaw/cli/bundle-vendor-charts/chainsaw-test.yaml`:
- Around line 47-49: The test uses a fixed WORK directory
(WORK="/tmp/chainsaw-bundle-vendor-charts") which can collide across concurrent
runs; change the setup in the test script to create a per-run unique work
directory (e.g., use mktemp -d or append $$/timestamp/UUID) and use that
variable wherever WORK is referenced (the current creation/removal block and the
other occurrences in the same file). Ensure the cleanup still removes the unique
directory and update all spots that reference WORK so they use the new per-run
path.
---
Outside diff comments:
In `@pkg/bundler/deployer/argocd/argocd.go`:
- Around line 260-266: Reset the Generator's vendorRecords at the start of
Generator.Generate to avoid exposing stale data if Generate returns early: set
g.vendorRecords = nil (or an empty struct/value as appropriate) at the top of
Generate before any early-returning work so VendorRecords() cannot return
previous-call data; apply the same reset in the other Generate-like path
referenced around the 315-327 section to ensure both code paths clear
g.vendorRecords before proceeding.
🪄 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: 8520456a-5bcf-4f10-9907-c7a173c9d65d
📒 Files selected for processing (28)
api/aicr/v1/server.yamldocs/contributor/api-server.mddocs/contributor/cli.mddocs/user/api-reference.mddocs/user/cli-reference.mdpkg/bundler/bundler.gopkg/bundler/config/config.gopkg/bundler/config/config_test.gopkg/bundler/deployer/argocd/argocd.gopkg/bundler/deployer/argocdhelm/argocdhelm.gopkg/bundler/deployer/helm/helm.gopkg/bundler/deployer/localformat/provenance.gopkg/bundler/deployer/localformat/provenance_test.gopkg/bundler/deployer/localformat/templates/wrapper-chart.yaml.tmplpkg/bundler/deployer/localformat/vendor.gopkg/bundler/deployer/localformat/vendor_folder.gopkg/bundler/deployer/localformat/vendor_test.gopkg/bundler/deployer/localformat/vendor_wrapper.gopkg/bundler/deployer/localformat/vendor_wrapper_test.gopkg/bundler/deployer/localformat/vendor_write_test.gopkg/bundler/deployer/localformat/writer.gopkg/bundler/deployer/localformat/writer_test.gopkg/bundler/handler.gopkg/cli/bundle.gopkg/config/config.gopkg/config/resolve.gopkg/defaults/timeouts.gotests/chainsaw/cli/bundle-vendor-charts/chainsaw-test.yaml
7ddb60e to
f011043
Compare
Summary
Add
--vendor-chartsopt-in flag (CLI + API + config-file) that pulls upstream Helm chart bytes into the bundle at bundle time, producing a self-contained, air-gap-deployable artifact with aprovenance.yamlaudit log.Motivation / Context
The uniform numbered local-chart layout from #662 still references upstream Helm chart registries at deploy time, so
bundles can't deploy in air-gapped clusters, behind flaky networks, or against private registries that aren't reachable
at install time.
--vendor-chartscollapses every Helm-typed component into a single wrapped local chart with theupstream tarball checked in at
NNN-<name>/charts/<chart>-<version>.tgz, eliminating deploy-time registry egress.Vendoring is intentionally opt-in for two reasons documented inline:
provenance.yamlexposes the audit surface for cross-referencing yank lists.air-gap shouldn't pay.
Closes: #663, #516
Related: #516 (epic), #662 (predecessor layout)
Type of Change
Component(s) Affected
cmd/aicr,pkg/cli)cmd/aicrd,pkg/api,pkg/server)pkg/recipe)pkg/bundler,pkg/component/*)pkg/collector,pkg/snapshotter)pkg/validator)pkg/errors,pkg/k8s)docs/,examples/)Implementation Notes
ChartPuller shim, not the Helm SDK (yet). Vendoring
helm.sh/helm/v4/pkg/downloadertransitively pulls ingithub.com/cyphar/filepath-securejoin(MPL-2.0), which the repo allowlist (Apache-2.0/MIT/BSD/ISC/Zlib only — explicitly "DO NOT ADD IGNORES") rejects. To unblock, the bundler calls aChartPullerinterface inpkg/bundler/deployer/localformat/vendor.go. Today's implementation isCLIChartPuller, which shells out tohelm pullviaexec.CommandContext(no shell). When legal approves the SDK, swap in anSDKChartPulleralongside; nothing else changes.Single wrapped folder per component. Mixed components (Helm + raw manifests) used to emit primary +
-posttwo-folder shape (#662). With--vendor-charts, they collapse into one folder: wrapperChart.yamldeclares the vendored chart as adependencies:entry with emptyrepository:(Helm resolves fromcharts/<chart>-<ver>.tgzadjacent), values are nested under the subchart name so Helm forwards them, and recipe-side raw manifests live intemplates/withhelm.sh/hook: post-install+ stable hook-weight injected.Provenance is shared, K8s-shape YAML.
pkg/bundler/deployer/localformat/WriteProvenanceemitsprovenance.yamlat the bundle root withapiVersion: aicr.nvidia.com/v1alpha1,kind: BundleProvenance, and one entry per vendored chart(name, chart, version, repository, sha256, tarballName, pullerVersion). Called by all three deployer Generators —helm,argocd, andargocd-helm— so air-gap audit works regardless of--deployer. Format matches every other AICR persisted file (Recipe, Snapshot, RecipeCriteria); pipe throughyq -o=jsonfor tools that expect JSON.Hook injection uses
gopkg.in/yaml.v3for streaming document boundaries — handles leading---,---inside literal-block strings, and interleaved comments correctly.Writereturns a struct (WriteResult). Previous([]Folder, error)became([]Folder, []VendorRecord, error)while iterating; settled onWriteResult{Folders, VendoredCharts}so future fields don't keep breaking the signature.Auth flows through Helm conventions unchanged:
HELM_REPOSITORY_USERNAME/HELM_REPOSITORY_PASSWORDfor HTTP(S); docker config (~/.docker/config.jsonor$DOCKER_CONFIG) for OCI. Documented indocs/user/cli-reference.md("Vendoring Charts for Air-Gap" section) anddocs/user/api-reference.md.Testing
# Commands run (prefer `make qualify` for non-trivial changes) make qualifyRisk Assessment
Rollout notes:
Checklist
make testwith-race)make lint)git commit -S) — GPG signing info