Tracked items are organised by phase. Each phase is independently shippable. Phases build on each other but v3 users are never broken by v4 work.
[ ]Not started[~]In progress[x]Done[!]Blocked / needs decision[s]Stretch goal (nice to have, not required for phase completion)
Goal: helm plugin install https://github.com/your-org/helm-map works. Developers can run helm map chart ./my-chart and see a dependency tree in the terminal. No cluster access required.
- Initialise Go module (
go mod init github.com/senet/helm-map) - Set up
cmd/helm-map/main.gowith Cobra root command - Add sub-commands:
chart,deps,release,live,push,version - Wire
--output,--depth,--with-images,--dry-run,--namespace,--kubeconfig,--kube-contextglobal flags - Bind flags to environment variables via Viper (
HELM_MAP_*prefix) - Read config from
$HELM_DATA_HOME/helm-map/config.yamlwith Viper - Set up
Makefiletargets:build,test,lint,release,install-local - Set up
goreleaserfor cross-platform builds (linux/amd64, darwin/amd64, darwin/arm64, windows/amd64) - Add
.pre-commit-config.yamlfor pre-commit validation (fmt, lint, test, security)
- Write
plugin.yamlwithhooks,platformCommandentries - Write
scripts/install.sh— downloads binary or builds from source, verifies SHA256 - Write
scripts/verify.sh— standalone checksum verification helper - Publish SHA256 checksums alongside GitHub Release assets (via goreleaser)
- Test
helm plugin installend-to-end on linux/amd64 (Helm v3 + v4) - Test
helm plugin installend-to-end on darwin/arm64 - Test
helm plugin installend-to-end on windows/amd64 - Verify
helm map --helpandhelm map versionwork after install
- Parse
Chart.yamldependencies block (Helm v3/v4 format) - Parse
requirements.yamlfor legacy Helm v2 charts (read-only support) - Read pinned versions from
Chart.lock - Resolve version constraints against repository index (
index.yaml) when no lock file - Resolve
repository: "file://..."local chart dependencies - Resolve
repository: "oci://..."dependencies (OCI tag listing) - Implement remote chart downloading logic (fetch via
helm pullor SDK into temp dir if argument is remoterepo/name:version) - Handle
conditionfield on dependencies (mark edge as optional + store condition string) - Handle
tagsfield on dependencies - Implement
--depthflag limiting for recursive resolution - Write unit tests covering: flat deps, nested deps, conditional deps, file:// deps, missing lock file, missing repo (9 tests)
- Write integration test with a real multi-level chart fixture (testdata/multi-level-chart)
- Define
Node,Edge,Graph,GraphMetatypes - Implement stable node ID generation (
chart:name:version, etc.) - Implement
Build()from[]ResolvedDep(chart-only path, Phase 1) - Implement
Roots()— nodes with no incoming DependsOn edges - Implement
Children(id)— direct children of a node - Implement
MaxDepth()— longest path in the DAG - Implement
TopoSort()using Kahn's algorithm (stable, deterministic order) - Write unit tests for graph construction, root detection, cycle detection (12 tests)
- Implement ANSI tree rendering (custom implementation using golang.org/x/term)
- Colour scheme: Chart=cyan, Release=green, K8sResource=yellow, Image=magenta
- Show optional/conditional deps as dimmed with
[condition]annotation - Show
[tags: x, y]annotation for tagged deps - Detect non-TTY (piped output) and emit plain-text tree without ANSI codes
- Write unit tests for tree output (5 tests)
- Accept local path (
./my-chart) - Fetch remote chart tarball if reference is
repo/name:version - Wire to
resolver.Resolve+graph.Build+renderer.New(terminal) - Write integration tests using fixture charts (6 testdata directories)
- Flat list output:
name | version | repository | condition | tags - Honour
--depthflag - Machine-readable:
--output jsonemits a JSON array of dep objects
- Add GitHub Actions workflow: lint (
golangci-lint), test (go test ./...), build - Enforce
go vetin CI - Add test coverage reporting (target: >80% on
internal/engine/) - Add
CONTRIBUTING.md - Add
LICENSE(Apache 2.0) - Write
README.mdwith install instructions, usage examples - Add GitHub Actions release workflow with GPG signing (goreleaser +
.provfiles)
- Simplify
install.sh— remove auth/private-repo code, direct URL download + SHA-256 checksum + source fallback - Pin all GitHub Actions to commit SHAs (supply-chain security)
- Add
.github/CODEOWNERS— all files require owner review - Add
.github/SECURITY.md— responsible vulnerability disclosure policy - Add
.github/dependabot.yml— weekly Go modules + GitHub Actions updates - Add PR template + issue templates (bug report, feature request)
- Update
README.md— CI/Release/License/Go Report badges, simplified install instructions - Update
CONTRIBUTING.md— branch protection notes, CODEOWNERS reference, security guidance - Create
mainbranch ruleset — require PR + 1 approval + CODEOWNERS review + CI checks (lint/test/build) + linear history + block force push/delete - Create
v*tag protection ruleset — block deletion + force push - Make repo public
- Re-release v0.1.0 with all hardened changes
Goal: helm map release my-release and helm map live work. The graph includes Kubernetes resource nodes owned by releases.
- Implement
Inspect()using Helm SDKaction.Get(nokubectlsubprocess) - Extract release metadata: name, namespace, chart name+version, revision, status, timestamp
- Parse rendered manifest YAML into
[]K8sResource(GVK, name, namespace, labels, annotations) - Filter resources to those owned by the release (via
app.kubernetes.io/managed-by: Helmlabel) - Implement
--with-imagesflag: extract container image refs from Pod specs in Deployments, StatefulSets, DaemonSets, CronJobs, Jobs - Write unit tests with mock Helm action responses
- Write integration test against a real kind/k3d cluster (CI optional, local required)
- Extend
Build()to accept[]InspectedReleasealongside[]ResolvedDep - Generate
Releasenodes andDeployedAsedges (chart → release) - Generate
K8sResourcenodes andOwnsedges (release → resource) - Generate
Imagenodes andUsesedges (resource → image) whenWithImages=true - Write unit tests for mixed chart+release graphs
- Accept release name as positional arg
- Accept
--namespaceflag (default fromHELM_NAMESPACE) - Wire to
inspector.Inspect+graph.Build+ renderer - Show resource count summary in terminal output header
- Write integration tests
- List all releases in namespace via Helm SDK
action.List - Inspect each release in parallel (bounded goroutine pool,
--concurrencyflag, default 4) - Merge into single graph, deduplicate shared chart dependencies
- Write integration tests
- Implement JSON rendering matching the
helm-map.comschema v1 - Include all
NodeandEdgefields - Include
metablock (generatedAt, pluginVersion) - Validate output against the JSON Schema before writing (
pkg/schema/v1) - Write unit tests (JSON validity test in renderer_test.go)
- Accept
--urlflag (default from config / envHELM_MAP_PUSH_URL) - Accept
--tokenflag (default from envHELM_MAP_PUSH_TOKEN) - POST JSON graph to helm-map.com API endpoint
- Print returned graph URL to stdout on success
- Handle HTTP errors with clear user messages
- Write unit tests with mock HTTP server
Goal: --output dot and --output svg work. Plugin binary published as an OCI artifact alongside GitHub Release.
- Emit valid Graphviz DOT syntax
- Node styling: shape, colour, and label based on
NodeKind - Edge styling: solid for
DependsOn/Owns, dashed for optional deps, labelled withEdgeKind - Emit
subgraph cluster_*for namespace grouping when graph includes release nodes - Write unit tests (DOT syntax validation via
dot -Tsvgin CI)
- Implement Fruchterman-Reingold force-directed layout in pure Go
- Render Chart nodes as rounded rectangles (blue)
- Render Release nodes as rounded rectangles (green)
- Render K8sResource nodes as rectangles (yellow), grouped by Kind
- Render Image nodes as ellipses (magenta)
- Render optional edges as dashed lines with condition label
- Embed CSS for light/dark mode (using
prefers-color-scheme) - Make nodes clickable:
onclickopenshttps://helm-map.com/node/{id} - Include a legend panel (node kinds + edge types)
- Self-contained: no external fonts, images, or scripts
- Write unit tests (SVG well-formedness, node count validation)
- Publish Go binary as tarball to GitHub Releases via goreleaser
- Publish SHA256
checksums.txtalongside release assets - Publish OCI artifact of the binary (for Helm v4 OCI-install path) via
oras push - Set up GitHub Actions release workflow triggered on
git tag v* - Sign GitHub Release assets with GPG (
.provfiles via goreleaser) - Test OCI install from
ghcr.ioregistry
- Add
--output dotand--output svgexamples toREADME.md - Add "Piping to Graphviz" section to docs
- Add rendered example SVG to
README.md - Write
CHANGELOG.mdfor v0.3.0
Goal: helm plugin install oci://ghcr.io/your-org/helm-map works on Helm v4. The WASM module passes Helm v4's plugin verification. Falls back to binary on Helm v3 or environments without WASM runtime.
- Set up
cmd/wasm/main.gowith Extism Go PDK entrypoint (//export map_run) - Implement
hostFunctions()wrapper mapping Extism host calls to the core engine'sHostFunctionsinterface - Verify all core engine code compiles with TinyGo (resolve
reflect,fmt,oscompatibility) - Replace
os.Execand direct filesystem calls in resolver/inspector with host function equivalents - Compile to WASM:
tinygo build -o helm-map.wasm -target wasm ./cmd/wasm/ - Verify WASM binary size is under 10 MB (TinyGo target; optimise if needed with
-no-debug) - Write smoke test: load WASM binary with Extism Go runtime, call
map_run, verify output
- Define
HostFunctionsinterface with all host function signatures - Implement
DefaultHostFunctionsusing Helm SDK + client-go (used by v3 binary) - Implement
WasmHostFunctionsusing Extismpdk.Callhost function invocations (used by WASM) - Write unit tests for both implementations with mock backends
- Add
wasm.oci,wasm.digest,wasm.typefields toplugin.yaml - Add
fallback.commandpointing to v3 binary (backwards compat) - Test Helm v4 plugin install from OCI registry
- Test Helm v4 plugin invocation (
helm map chart ./fixture --output terminal) - Test fallback to v3 binary when WASM runtime is unavailable
- Test that Helm v3 still installs and runs correctly from the same
plugin.yaml
- Publish WASM binary to
ghcr.io/your-org/helm-map-wasm:<version>viaoras push - Sign WASM OCI artifact with cosign (
cosign sign) - Pin digest in
plugin.yaml:wasm.digest: sha256:... - Add
WASM_PUBLISH=truestep to GitHub Actions release workflow - Set up cosign key management (keyless via GitHub OIDC recommended)
- Document OCI install steps in
README.mdunder "Helm v4" section
- Set up Helm v4 in CI (
helm/helmreleases, v4.x branch) - Run full
helm map chart,helm map release,helm map livetest suite against Helm v4 - Test
--output json | helm map pushend-to-end on Helm v4 - Test that post-renderer plugin type is NOT needed for
helm-map(it is CLI only)
Goal: helm map push delivers a graph to helm-map.com and returns a shareable URL. The web UI renders the graph interactively.
- Define
helm-map.comAPI v1 interface (POST/v1/graphs, GET/v1/graphs/{id}) - Implement
Client.Push(graph)— POST JSON, return graph URL - Implement authentication: Bearer token via
--tokenflag orHELM_MAP_PUSH_TOKENenv var - Implement retry with exponential backoff (3 retries, max 30s)
- Implement request timeout (default 30s, configurable via
--push-timeout) - Write unit tests with mock HTTP server
- Print shareable URL to stdout on success:
Graph published: https://helm-map.com/g/abc123 - Support
--openflag to open URL in default browser after push - Support
--stdinflag to read JSON graph from stdin (compose withhelm map chart … | helm map push --stdin) - Add
--privateflag to mark graphs as private (not publicly listed) - Handle API errors gracefully with actionable messages
- Publish
pkg/schema/v1as a Go module (github.com/your-org/helm-map/pkg/schema/v1) for import by helm-map.com backend - Publish the JSON Schema file to
https://helm-map.com/schema/graph/v1.json - Version the schema: add
$schemaversion field; bump to v2 only for breaking changes
- Set up kind/k3d cluster in GitHub Actions for integration tests
- Create fixture charts for testing:
fixtures/simple/,fixtures/nested/,fixtures/conditional/,fixtures/oci/ - Add
make test-integrationtarget (requires cluster) - Add
make test-unittarget (no cluster required, fast) - Target: >80% unit test coverage on all
internal/packages - Target: integration tests cover all CLI commands on both Helm v3 and v4
-
README.md— install, quickstart, all commands with examples, output format reference -
ARCHITECTURE.md— this file (keep up to date with code) -
TODO.md— this file (check off items as completed) -
CONTRIBUTING.md— dev setup, test commands, PR process -
CHANGELOG.md— per-release changes -
docs/schema-v1.md— JSON schema reference -
docs/helm-v4-wasm.md— WASM plugin deep dive for contributors - Add inline GoDoc comments to all exported types and functions in
pkg/schema/v1
- Profile memory usage on large charts (50+ transitive deps)
- Implement bounded concurrency for parallel release inspection (
--concurrencyflag) - Benchmark
TopoSort()andBuild()on graphs with 1000+ nodes - Implement chart metadata cache with TTL to avoid re-fetching repository indexes on repeat runs
- [s] Implement incremental graph updates — only re-resolve changed charts
- Structured logging via
go.uber.org/zap—--debugflag enables verbose log output - Log all Helm SDK and Kubernetes API calls at debug level
- Log cache hit/miss for chart resolution at debug level
- Emit timing summary at debug level: "Resolved 23 charts in 1.2s, inspected 3 releases in 0.8s"
- Verify SHA256 of all downloaded chart tarballs (not just plugin binary)
- Reject
Chart.yamlfiles with dependencyrepositoryvalues pointing tofile://paths outside the chart directory (path traversal guard) - Sanitise all node IDs before embedding in SVG/DOT output (XSS/injection guard)
- Rotate cosign signing key annually; document rotation process
- [s]
helm map diff <release-a> <release-b>— show graph diff between two releases or revisions - [s]
helm map watch— live terminal UI that refreshes the graph on release changes - [s]
--output mermaid— emit Mermaid.js flowchart syntax for embedding in Markdown - [s]
--output cytoscape— emit Cytoscape.js JSON for advanced web graph rendering - [s] Multi-cluster support:
--kube-contexts ctx1,ctx2to merge graphs across clusters - [s] ArgoCD integration: annotate release nodes with ArgoCD Application sync status
- [s] Flux integration: annotate chart nodes with HelmRelease/HelmRepository CR references
- [s]
helm map lint— detect dependency graph issues: cycles, missing conditions, version conflicts - [s] Neovim / VS Code extension that renders the graph inline in the editor sidebar
- [s] GitHub Action: post graph as PR comment with SVG diff when
Chart.yamlchanges
- All phase items for this version are checked off
-
go test ./...passes with zero failures -
golangci-lint runpasses with zero errors - Integration tests pass on kind cluster with Helm v3 and Helm v4
-
CHANGELOG.mdupdated -
plugin.yamlversion bumped -
go.mod/go.sumtidy (go mod tidy) - goreleaser dry-run passes:
goreleaser release --snapshot --clean - Tag pushed:
git tag v0.x.0 && git push origin v0.x.0 - GitHub Release created with assets and checksums
- OCI artifact published and signed (Phase 3+)
-
README.mdinstall instructions tested from a clean environment - Announcement in Helm Slack
#helm-userschannel