Skip to content

refactor(misconf): replace custom Helm archive parsing with Helm SDK loaders#10718

Merged
nikpivkin merged 16 commits into
aquasecurity:mainfrom
nikpivkin:refactor/helm-parser-archive
May 27, 2026
Merged

refactor(misconf): replace custom Helm archive parsing with Helm SDK loaders#10718
nikpivkin merged 16 commits into
aquasecurity:mainfrom
nikpivkin:refactor/helm-parser-archive

Conversation

@nikpivkin

@nikpivkin nikpivkin commented May 22, 2026

Copy link
Copy Markdown
Contributor

Description

Replaces Trivy's custom Helm archive parsing with the Helm SDK's own loaders, cleans up the parser/scanner architecture, and overhauls the test structure.

Background

Since the initial Helm support (f5e655e22a), Trivy unpacked chart archives manually via a custom unpackArchive implementation in parser_tar.go. Over time this accumulated several problems:

  • No path traversal protection and no size limits on extracted content — the Helm SDK provides both out of the box.
  • Divergence from Helm: custom parsing could behave differently from how Helm itself reads archives, particularly around validation and path normalisation.
  • Accidental .tar support: Trivy accepted plain .tar as a Helm chart format, but Helm never produces it — helm package always outputs .tgz. A symlink-handling workaround was later added (4eae37c52b) to deal with non-Helm archives that were being incorrectly processed as charts. The root fix is to not accept .tar at all. By delegating to LoadArchiveFiles, the symlink workaround is no longer needed — Helm itself does not handle symlinks because helm package resolves them into regular files, so they simply don't appear in legitimate chart archives.
  • Architectural duplication: the scanner discovered charts, and the parser rediscovered and re-dispatched them internally, recursing into archives it found itself.

Breaking changes

None. The removed behaviour was never part of a supported contract:

  • .tar without gzip: helm package never produces plain .tar archives, so no legitimate chart scanner input is affected.
  • Symlink handling: as helm package resolves symlinks into regular files at pack time, symlinks cannot appear in legitimate chart archives. The workaround existed solely to handle non-Helm-produced archives that should not have been accepted in the first place.

This can be verified empirically:

$ ln -s dangerous.yaml testchart/templates/dangerous-link.yaml
$ helm package testchart
Successfully packaged chart and saved it to: testchart-0.1.0.tgz
$ tar tvf testchart-0.1.0.tgz | grep dangerous
-rw-r--r--  0 0      0         194 May 27 16:25 testchart/templates/dangerous-link.yaml
-rw-r--r--  0 0      0         194 May 27 16:25 testchart/templates/dangerous.yaml

helm package produces .tgz (not .tar), and both entries are regular files — the symlink was resolved at pack time.

To confirm no regression on a real-world chart, the same archive was scanned with both the released version and the patched one:

$ trivy fs --scanners misconf kube-prometheus-stack-85.2.2.tgz -f json -o report-released.json
$ ./trivy fs --scanners misconf kube-prometheus-stack-85.2.2.tgz -f json -o report-patched.json
$ diff report-released.json report-patched.json
4c4
<     "Version": "0.69.3"
---
>     "Version": "0.69.0-141-gad030a8904"
6,7c6,7
<   "ReportID": "..."
<   "CreatedAt": "..."
---
>   "ReportID": "..."
>   "CreatedAt": "..."

Changes

Parser — simplified API, no internal state

The custom archive unpacking logic is removed. Archive loading is delegated to loader.LoadArchiveFiles from helm.sh/helm/v4.

The parser now has two focused entry points:

// For a chart directory already present as an fs.FS
ParseFS(ctx, fsys, dir) ([]Manifest, error)

// For a chart archive
ParseArchive(ctx, fsys, archivePath) ([]Manifest, error)

Previously, ParseFS both discovered charts and rendered them, accumulating state across calls. Now the parser is stateless — it holds only the Helm action client — and each call is independent. The caller decides what to parse.

Scanner — owns chart discovery

Chart discovery is now handled entirely by the scanner. It distinguishes two skip scenarios to avoid duplicate results:

  • An archive inside a chart directory (my-chart/my-chart-1.0.0.tgz alongside my-chart/Chart.yaml) — the unpacked directory takes precedence.
  • An archive next to a chart directory (./my-chart-1.0.0.tgz alongside ./my-chart/) — same rule.

Forward compatibility

Delegating to the Helm SDK makes Charts v3 support straightforward in the future: detect the chart API version and call the appropriate SDK loader. No changes to Trivy's own parsing logic will be needed.

Test changes

The test suite was overhauled alongside the logic changes:

  • Split by package: parser tests live in parser/, scanner tests in helm/. Previously everything was mixed in a test/ subdirectory.
  • Table-driven tests throughout, replacing a collection of standalone test functions.
  • txtar instead of binary archives: .tar.gz and .tgz testdata files are replaced with .txtar text archives. Chart content is visible directly in the file; archives are constructed programmatically in tests using new helpers. This makes chart structure transparent during code review and removes binary blobs from the repository.
  • Removed oversized test dependency: the full Bitnami MySQL production chart (~4800 lines across values.yaml, README.md, nested templates and a bundled common subchart) was used solely as a parser test fixture. It is replaced with a minimal chart written for this purpose.

Related issues

Checklist

  • I've read the guidelines for contributing to this repository.
  • I've followed the conventions in the PR title.
  • I've added tests that prove my fix is effective or that my feature works.
  • I've updated the documentation with the relevant information (if needed).
  • I've added usage information (if the PR introduces new options)
  • I've included a "before" and "after" example to the description (if the PR is a user interface change).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the Helm misconfiguration scanner to delegate chart-archive loading to the Helm v4 SDK (instead of Trivy’s custom tar extraction), simplifies the parser API, and restructures the Helm scanner/parser tests around txtar-based fixtures.

Changes:

  • Replace custom Helm archive unpacking with Helm SDK archive loaders; stop treating plain .tar files as Helm chart archives.
  • Move chart discovery/skip rules into the scanner and make the parser stateless with focused ParseFS / ParseArchive entry points.
  • Overhaul Helm tests and fixtures (txtar fixtures, new archive-building helpers), removing large/legacy binary fixture trees.

Reviewed changes

Copilot reviewed 118 out of 143 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/iac/scanners/helm/scanner.go Refactors chart discovery and scanning flow; adds archive skip heuristics and uses new parser API.
pkg/iac/scanners/helm/scanner_test.go Reworks scanner tests to use txtar fixtures and adds chart discovery/skip scenarios.
pkg/iac/scanners/helm/parser/parser.go Replaces internal stateful parsing with stateless ParseFS/ParseArchive returning rendered manifests via Helm SDK loaders.
pkg/iac/scanners/helm/parser/parser_test.go Rebuilds parser tests into table-driven cases; adds archive parsing coverage and txtar-based expected outputs.
pkg/iac/scanners/helm/parser/parser_tar.go Removes custom tar extraction implementation.
pkg/iac/detection/peek.go Drops .tar from “archive” detection (Helm chart archives are now .tgz/.tar.gz only).
internal/testutil/gzip.go Adds helpers to build tar/tar.gz archives from fs.FS for tests.
pkg/iac/scanners/helm/testdata/with-subchart.txtar Adds txtar fixture for verifying subchart scanning occurs exactly once.
pkg/iac/scanners/helm/testdata/templated-name.txtar Updates txtar fixture description/header content for templated chart names.
pkg/iac/scanners/helm/testdata/simmilar-templates.txtar Expands fixture and adds second similar template for code-snippet selection tests.
pkg/iac/scanners/helm/testdata/non-helm-chart.txtar Adds non-Helm txtar fixture to ensure scanner doesn’t error on unrelated input.
pkg/iac/scanners/helm/testdata/aws-cluster-autoscaler.txtar Adds real-world-ish fixture to test parser/scanner recovery scenarios.
pkg/iac/scanners/helm/test/parser_test.go Removes legacy parser tests (replaced by new parser package tests).
pkg/iac/scanners/helm/test/option_test.go Removes legacy option tests (covered by new parser tests).
pkg/iac/scanners/helm/test/helpers_test.go Removes legacy test helpers (replaced by internal/testutil helpers).
pkg/iac/scanners/helm/test/testdata/with-tarred-dep/renovate.json Removes legacy fixture file as part of testdata overhaul.
pkg/iac/scanners/helm/test/testdata/with-tarred-dep/LICENSE Removes legacy fixture file as part of testdata overhaul.
pkg/iac/scanners/helm/test/testdata/with-tarred-dep/.helmignore Removes legacy fixture file as part of testdata overhaul.
pkg/iac/scanners/helm/test/testdata/with-subchart/Chart.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-subchart/values.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/Chart.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/values.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/templates/pod.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-kube-version/Chart.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-kube-version/.helmignore Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/pdb.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-api-version/Chart.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-api-version/.helmignore Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/with-api-version/templates/pdb.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/Chart.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/.helmignore Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/values.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/_helpers.tpl Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/deployment.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/hpa.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/ingress.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/NOTES.txt Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/service.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/serviceaccount.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/testchart/templates/tests/test-connection.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/simmilar-templates/Chart.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/simmilar-templates/templates/manifest.yaml Removes legacy on-disk fixture (replaced by txtar).
pkg/iac/scanners/helm/test/testdata/numberName/Chart.yaml Removes legacy on-disk fixture (replaced by new parser txtar fixtures).
pkg/iac/scanners/helm/test/testdata/expected/with-tarred-dep/templates/ingress.yaml Removes legacy expected-render output (expected outputs moved/reworked).
pkg/iac/scanners/helm/test/testdata/expected/with-tarred-dep/templates/service.yaml Removes legacy expected-render output (expected outputs moved/reworked).
pkg/iac/scanners/helm/test/testdata/expected/testchart/templates/service.yaml Removes legacy expected-render output (expected outputs moved/reworked).
pkg/iac/scanners/helm/test/testdata/expected/testchart/templates/serviceaccount.yaml Removes legacy expected-render output (expected outputs moved/reworked).
pkg/iac/scanners/helm/test/testdata/expected/options/testchart/templates/service.yaml Removes legacy expected-render output (expected outputs moved/reworked).
pkg/iac/scanners/helm/test/testdata/expected/options/testchart/templates/serviceaccount.yaml Removes legacy expected-render output (expected outputs moved/reworked).
pkg/iac/scanners/helm/test/testdata/expected/mysql/templates/serviceaccount.yaml Removes legacy MySQL expected output fixture.
pkg/iac/scanners/helm/test/testdata/expected/mysql/templates/secrets.yaml Removes legacy MySQL expected output fixture.
pkg/iac/scanners/helm/test/testdata/expected/mysql/templates/primary/svc.yaml Removes legacy MySQL expected output fixture.
pkg/iac/scanners/helm/test/testdata/expected/mysql/templates/primary/svc-headless.yaml Removes legacy MySQL expected output fixture.
pkg/iac/scanners/helm/test/testdata/expected/mysql/templates/primary/statefulset.yaml Removes legacy MySQL expected output fixture.
pkg/iac/scanners/helm/test/testdata/expected/mysql/templates/primary/configmap.yaml Removes legacy MySQL expected output fixture.
pkg/iac/scanners/helm/test/mysql/Chart.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/Chart.lock Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/.helmignore Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/values.schema.json Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/ci/values-production-with-rbac.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/NOTES.txt Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/_helpers.tpl Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/extra-list.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/metrics-svc.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/networkpolicy.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/role.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/rolebinding.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/secrets.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/serviceaccount.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/servicemonitor.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/primary/configmap.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/primary/initialization-configmap.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/primary/pdb.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/primary/statefulset.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/primary/svc.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/primary/svc-headless.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/secondary/configmap.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/secondary/pdb.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/secondary/statefulset.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/secondary/svc.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/templates/secondary/svc-headless.yaml Removes legacy large MySQL chart fixture.
pkg/iac/scanners/helm/test/mysql/charts/common/Chart.yaml Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/values.yaml Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_affinities.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_capabilities.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_errors.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_images.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_ingress.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_labels.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_names.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_secrets.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_storage.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_tplvalues.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_utils.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/_warnings.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/validations/_cassandra.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/validations/_mariadb.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/validations/_mongodb.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/validations/_postgresql.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/validations/_redis.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/test/mysql/charts/common/templates/validations/_validations.tpl Removes legacy large MySQL chart fixture dependency.
pkg/iac/scanners/helm/parser/testdata/testchart.txtar Adds base chart fixture for parser tests in txtar form.
pkg/iac/scanners/helm/parser/testdata/values.yaml Adds shared values file used by parser option tests.
pkg/iac/scanners/helm/parser/testdata/with-api-version.txtar Updates API-version-dependent chart fixture to txtar chart structure.
pkg/iac/scanners/helm/parser/testdata/with-kube-version.txtar Updates kube-version-dependent chart fixture to txtar chart structure.
pkg/iac/scanners/helm/parser/testdata/chart-without-name.txtar Adds fixture for missing name: handling.
pkg/iac/scanners/helm/parser/testdata/chart-with-integer-name.txtar Adds fixture intended to exercise non-string chart name handling.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/Chart.yaml Adds minimal chart with a packaged dependency.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/.helmignore Adds helmignore for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/values.yaml Adds values for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/templates/deployment.yaml Adds minimal deployment template for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/templates/ingress.yaml Adds minimal ingress template for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/templates/service.yaml Adds minimal service template for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/templates/secrets-crdb-ca.yaml Adds secret template for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/chart-with-packaged-dep/templates/secrets-dbconn.yaml Adds secret template for packaged-dependency chart fixture.
pkg/iac/scanners/helm/parser/testdata/non-deps-archives/Chart.yaml Removes old fixture (dependency/archive classification tests removed/changed).
pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/Chart.yaml Removes old fixture (dependency/archive classification tests removed/changed).
pkg/iac/scanners/helm/parser/testdata/chart-and-archived-chart/my-chart/Chart.yaml Removes old fixture (archive-vs-dir skip logic moved to scanner tests).
pkg/iac/scanners/helm/parser/testdata/chart-and-archived-chart/my-chart/templates/pod.yaml Removes old fixture (archive-vs-dir skip logic moved to scanner tests).
pkg/iac/scanners/helm/parser/testdata/expected/testchart.txtar Updates expected rendered output format for new txtar fixtures.
pkg/iac/scanners/helm/parser/testdata/expected/testchart-with-options.txtar Updates expected rendered output for option-based rendering.
pkg/iac/scanners/helm/parser/testdata/expected/with-api-version.txtar Updates expected rendered output for API version option.
pkg/iac/scanners/helm/parser/testdata/expected/with-kube-version.txtar Updates expected rendered output for kube version option.
pkg/iac/scanners/helm/parser/testdata/expected/chart-with-packaged-dep.txtar Adds/updates expected render output for packaged-dependency fixture.
Comments suppressed due to low confidence (1)

pkg/iac/scanners/helm/testdata/simmilar-templates.txtar:2

  • There is trailing whitespace at the end of the first line, which makes diffs noisier and can trip whitespace linters. Please trim it.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/iac/scanners/helm/scanner.go
Comment thread pkg/iac/scanners/helm/parser/testdata/chart-with-integer-name.txtar
@nikpivkin nikpivkin force-pushed the refactor/helm-parser-archive branch from 3850eee to 4665293 Compare May 22, 2026 13:44
@nikpivkin nikpivkin marked this pull request as ready for review May 27, 2026 10:55
DmitriyLewen
DmitriyLewen previously approved these changes May 27, 2026

@DmitriyLewen DmitriyLewen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM
left small comment

Comment thread internal/testutil/gzip.go Outdated
@nikpivkin nikpivkin added this pull request to the merge queue May 27, 2026
Merged via the queue into aquasecurity:main with commit 441251e May 27, 2026
18 checks passed
@nikpivkin nikpivkin deleted the refactor/helm-parser-archive branch May 27, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(misconf): use Helm v4 SDK loaders instead of custom tar parsing

3 participants