helm/helm

Trojan-Source defence + GitHub Actions hardening + a structural floor on top of golangci-lint — net-new findings the existing pipeline doesn't catch.

Narrative
Adds a structural floor on top of mature tooling
Rules
58
Last revalidated
Engineering reference
README on GitHub · .alint.yml

Why this matters

helm is the canonical midsize, modular Go OSS monorepo with the standard CNCF/Go shape: ~530 production .go files, one root go.mod, ~150k LoC, a single 240-line Makefile that drives the dev workflow, one ~120-line .golangci.yml enabling 17 linters + 2 formatters, one ~50-line scripts/validate-license.sh, and the standard GitHub Actions + OWNERS + dependabot CNCF-project shape.

It’s neither the kubernetes-style verify-script empire nor the golang/go-style minimal-tooling extreme. It has the typical CNCF shape: golangci-lint config, license-header bash, OWNERS file, GHA workflows, dependabot, goreleaser. That’s the population alint needs to convert.

The structural-validation surface is deliberately small: ~22 distinct checks across the Makefile (test-style, test-source-headers, tidy), the .golangci.yml formatters block, scripts/validate-license.sh, the GitHub Actions workflows, and the on-disk metadata files (OWNERS, .github/env, dependabot.yml, .goreleaser.yaml, AGENTS.md, ADOPTERS.md, KEYS, code-of-conduct).

Headline catch

helm has mature, well-curated tooling. golangci-lint orchestrates 17 linters; scripts/validate-license.sh walks the tree for the Apache-2 + Helm-Authors header literals; goreleaser handles the release matrix. What’s missing is the structural floor underneath all of it.

Running the alint config against the live tree surfaces real findings the existing pipeline doesn’t catch:

  1. Zero-width character (U+200B) in internal/plugin/plugin.go:80 — line 80, column 70 contains zero-width spaces inside a comment block. Caught by the bundled go-sources-no-zero-width rule (Trojan-Source CVE-2021-42574 defence). validate-license.sh doesn’t look at character-class hygiene; golangci-lint doesn’t either by default. Net-new structural finding alint catches that no existing tool in helm’s pipeline does.

  2. 5 GitHub workflows declare permissions: read-all or permissions: {} instead of contents: readcodeql-analysis.yml, govulncheck.yml, release.yml, scorecards.yml, stale.yaml. The OpenSSF Scorecard Token-Permissions check would surface these as well, but only on its weekly cron. The bundled gha-workflow-contents-read rule catches them on every PR.

  3. Plus a structural drift the bundled oss-no-trailing-whitespace rule catches: .golangci.yml line 43 has trailing whitespace.

The pitch:

“helm is the typical CNCF-shape Go monorepo: one Makefile orchestrates lint via golangci-lint and a 50-line bash script that greps for license headers. alint replaces the orchestration layer with one declarative file, keeps golangci-lint as the deep- Go AST workhorse, and adds a structural floor (Trojan-Source defence, GitHub Actions hardening, top-level-file conventions) that helm doesn’t currently enforce.”

Where alint earns its keep here

The complementary case study to kubernetes/golang-go: those two anchor the extremes (mega-monorepo with a bespoke verify-script empire vs canonical-with-minimal-tooling). helm anchors the centre — the population alint actually needs to win.

In numbers:

One declarative 58-rule config replaces the Makefile’s test-style orchestration plus the scripts/validate-license.sh 50-liner plus the half-dozen shape-implicit assertions buried inside .golangci.yml and the release pipeline.

helm also surfaces the v0.10 *_path_contains set-membership shorthand as a v0.10 design candidate (now 3 sources: helm + deno

Future story angles

The factual engineering writeup (tooling inventory, mapping table, gap catalogue, validation status footer) lives in the public alint repo at github.com/asamarts/alint/tree/main/examples/helm-helm/README.md.