heft is a small CLI tool that scans Helm charts and reports the container images they use. It prefers high-confidence information from rendered Kubernetes manifests (via helm template), and falls back to static YAML and regex-based detection when necessary.
brew install tonur/heft/heftgo build ./cmd/heftheft scan <chart-ref> [flags]Where <chart-ref> can be:
- A local chart directory
- A local packaged chart:
*.tgz - An HTTP(S) URL to a chart archive (
.tgz) - An
oci://reference to an OCI-backed chart
When a remote chart reference (HTTP(S) URL or oci:// ref) is used, heft
will download the chart into a temporary directory, extract it, and run all
its detectors (rendered, static, and regex) against the local copy.
Examples:
# Scan a local chart directory
heft scan ./charts/my-app
# Scan a local packaged chart
printf "" | helm template test ./charts/my-app # sanity check
heft scan ./charts/my-app-0.1.0.tgz
# Scan a remote chart URL (full scan after download)
heft scan https://charts.example.com/my-app-0.1.0.tgz
# Scan an OCI chart (Helm must be configured for OCI)
heft scan oci://registry.example.com/my-app:0.1.0-
--min-confidence=low|medium|high- Filter results by minimum confidence.
high: only rendered-manifest images (fromhelm template).medium: rendered-manifest + static YAML-based images.low(default): include regex-based heuristic matches as well.
-
--no-helm-deps- Disable the automatic
helm dependency buildretry when rendering a local chart directory fails due to missing dependencies.
- Disable the automatic
-
--include-optional-deps- When set, also scan subcharts under
charts/that may be brought in via optional/conditional dependencies. For remote charts,heftrunshelm dependency buildfirst so OCI/remote deps are available locally.
- When set, also scan subcharts under
-
--verbose,-v- Enable verbose logging on stderr, including which charts/subcharts are scanned and what
helm templatecommands are run.
- Enable verbose logging on stderr, including which charts/subcharts are scanned and what
-
--set=key=val,--set-string=key=val- Passed through to
helm templateunchanged.
- Passed through to
-
--values=path,-f=path- Passed through to
helm templateunchanged.
- Passed through to
heft prints a YAML document describing discovered images, for example:
images:
- name: ghcr.io/external-secrets/external-secrets:v1.2.1
confidence: high
source: rendered-manifest
- name: example.com/basic/app:v1
confidence: medium
source: static-yaml
file: internal/scan/testdata/basic-chart/values.yamlconfidence: one ofhigh,medium,low.source:rendered-manifestfor images found viahelm template.static-yamlfor images inferred from values/manifests without rendering.regex-scanfor heuristic matches in files.
Higher-confidence images are preferred and de-duplicated per repository:
- Rendered images win over static and regex-based ones for the same repo.
- Tagged images win over untagged configs at the same confidence level.
- Go toolchain (to build the binary):
go build ./cmd/heft- Helm 3 on
PATHfor rendered-manifest detection and end-to-end tests.
A bunch of popular Helm charts are available under internal/scan/testdata/popular-charts/ for testing and benchmarking purposes.
The heft-e2e-scaffold tool can be used to download and update these charts.
Run the tests like so:
go run ./cmd/heft-e2e-scaffold --update # refresh metadata for existing charts and warn if expected images drift
go test ./... -tags=e2e # download charts and test the output placed under internal/system/testdata/chartsheft downloads remote charts when needed, runs Helm to render manifests, and then combines several detection strategies to find container images. It de-duplicates results and lets you filter them by confidence level using --min-confidence.
This project has been substantially generated and maintained with the help of OpenCode, including refactors, test additions, and documentation updates.