Skip to content

Add check-for-go-fips-test pre-commit hook - #18

Open
AmberArcadia wants to merge 7 commits into
mainfrom
check-for-go-fips-test
Open

AmberArcadia wants to merge 7 commits into
mainfrom
check-for-go-fips-test

Conversation

@AmberArcadia

@AmberArcadia AmberArcadia commented Aug 11, 2025 •

Copy link
Copy Markdown
Member

What

Adds check-for-go-fips-test, for chainguard-dev/internal-dev#9313: a package or subpackage that compiles Go with a FIPS toolchain must have a test/go-fips-check covering it.

How it decides

Per package and per subpackage, after resolving ${{vars.NAME}} from the file's vars: mapping:

  • Builds with FIPS Go when a go/build or go/install step has go-package starting with a FIPS toolchain name, or when the environment provides one and the scope runs go/build/v2 or a runs: block containing go build / go install. A toolchain in the main environment on its own does not implicate a main package that builds nothing.
  • FIPS toolchains are every family test/go-fips-check knows how to verify: go-fips and go-fips-md5 (at 1.27 these are meta packages pointing at go-msft-1.27), go-msft, go-geomys, go-openssl.
  • Covered by its own test pipeline running test/go-fips-check; by test/emptypackage or test/tw/emptypackage; or, for a subpackage, by a main test that runs go-fips-check and installs the subpackage (range names match on the prefix before ${{range.key}}).
  • split/bin in a subpackage moves the main binaries there: that subpackage inherits the obligation and the main package is released.
  • Nested pipeline: lists are searched; a null pipeline: is fine.

Results on stereo main

Tree Rule Flagged Real gaps
2026-10-02, 10,047 files, hook as first reviewed go-fips 25 files 2
2026-10-02, same tree, reworked hook go-fips 2 files, 3 findings 2, fixed in chainguard-dev/stereo#362436 (merged 2026-10-23)
2026-10-23, 10,348 files go-fips 0 0
2026-10-23, same tree all FIPS toolchains (this PR) 15 files 15: every gitlab-rails-ce-fips-* and commercial-gitlab-rails-ee-fips-* stream rebuilds the devfile gem's Go helper with go-msft inside the Rails bundle and has no go-fips-check anywhere

Vars resolution changes nothing on today's tree (every templated toolchain name already began with a matching prefix) but closes the hole for go-package: ${{vars.go-package}} style configs.

Blind-spot census on the same tree: 89 files have a FIPS toolchain in the environment but no Go build the hook can see, 66 of them driving the build through make; 88 of the 89 already carry a go-fips-check. The one that does not is zabbix-fips-7.0 (main test is test/tw/emptypackage, 11 subpackages without the check). Flagging every such file would bring back the 17 false positives this rework removed, so that case stays a documented limit.

Structure

pre_commit_hooks/melange.py holds the config walkers (iter_steps, iter_pipelines, subpackages, build_steps, test_steps, environment_packages, uses_any, resolve_vars) and the load-and-report loop. This hook and check-pipeline-name-only-steps (merged in #20) are each a check function plus argparse on top of it, the shared library dannf asked for on the first review.

Review feedback

  • dannf: don't duplicate the main and subpackage parsing. Done, see Structure.
  • dannf: pre-compiled YAML misses ${{vars.*}} expansions. Plain vars: entries are resolved now; var-transforms are not, and nothing on stereo main depends on one for a toolchain name.
  • dannf: raise in #eng-os. The question for that thread is below.

For #eng-os

Two things to confirm: that "built with a FIPS Go toolchain" means test/go-fips-check is required, enforced at commit time by this hook; and that the rule covers go-msft and go-geomys, not only the go-fips name. The 15 gitlab-rails streams above are the only packages on main that fail the wider rule; the fix is one - uses: test/go-fips-check line in each main test, in a stereo PR gated on that answer.

Test

test-data/go-fips-test-bad.yaml produces three findings (main via go/build, a subpackage via go/build/v2, a subpackage via runs: go build); test-data/go-fips-test-good.yaml passes. pre-commit run --all-files is clean.

@dannf dannf 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.

The test looks good to me, a few comments about optimizations inside. Would you mind raising this in #eng-os? I'd like to give other people a chance to chime in, since this is establishing a de facto policy (and I'm not really a go-fips expert). @murraybd might be interested in it as well, as a test proliferater himself :)

One note: this test is looking at the YAML file in a pre-compiled state, so it will miss things such as packages with names like ${{vars.expands-to-go-fips}}-foo. If we implemented it as a melange linter or melange compiled it, it wouldn't have that problem. I wonder if there's a way to have one hook do the compilation such that all follow-on tests could consume it w/o recompiling?

[^/]+\.ya?ml # matches .yaml or .yml files at the top level only
)$
- id: check-for-go-fips-test
files: '^[^.][^/]*\.yaml$' # matches non-hidden .yaml files at the top level only

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.

It might be more efficient to use this to identify the go-fips packages that need to be parsed. If we can filter out packages at this level, we needn't spawn another python interpreter to run the check. Of course, if it might be the case that only a subpackage will match, then that won't work.

Comment thread pre_commit_hooks/check_for_go_fips_test.py
@AmberArcadia

Copy link
Copy Markdown
Member Author

Rebased onto main and pushed 783c691, a rework driven by running the hook over every package file on stereo main: the previous version flagged 25 files of which 2 were real. It now attributes builds per scope (go/build and go/install via go-package; go/build/v2 and runs: go build via the environment toolchain), accepts coverage from the main test when it installs the subpackage, exempts test/tw/emptypackage as well as test/emptypackage, handles split/bin, and no longer crashes on a null pipeline:. Main and subpackage parsing share one set of helpers. Stereo main now yields exactly the 2 real gaps, fixed in chainguard-dev/stereo#362436. Known limits (go-msft, templated go-package, make-driven builds) are in the description. @dannf

Implements GitHub issue requirements:
- Detects packages using go-fips in environment or pipeline
- Verifies they have corresponding go-fips test (uses: test/go-fips-check)
- Reports failures for packages missing the required test
- Detect any go-fips variant (go-fips, go-fips-md5, etc.) using startswith()
- Check each package/subpackage independently for compliance
- Require matching tests for each go-fips usage (not just any test)
- Provide detailed error messages specifying which component lacks tests
- Handle subpackage test sections properly

Fixes comprehensive validation of go-fips test requirements.
Running the previous version over the 10,047 package files on stereo
main flagged 25 files, of which 2 were real gaps. The rest were main
packages whose environment lists go-fips only for the benefit of
subpackages, range subpackages covered by a go-fips-check in the main
test, one package using test/tw/emptypackage, and five files that
crashed the hook on a null `pipeline:`.

The check now asks, per package and subpackage, whether that scope
compiles Go with a FIPS toolchain and whether a go-fips-check covers it:

- go/build and go/install count when their go-package input starts with
  go-fips. go/build/v2 and hand-written `go build` / `go install` lines
  use the environment's go, so they count only when the environment
  provides a go-fips toolchain. A main environment entry alone no longer
  implicates a main package that builds nothing.
- Coverage is the scope's own test, test/emptypackage or
  test/tw/emptypackage, or for subpackages a main test that runs
  go-fips-check and installs the subpackage (range names match on the
  prefix before ${{range.key}}).
- split/bin in a subpackage moves the main binaries there, so that
  subpackage inherits the obligation and the main package is released.
- Nested `pipeline:` lists are searched; null pipelines no longer crash.
- The main and subpackage code paths share one set of helpers.

With this version stereo main reports exactly the 2 real gaps:
crossplane-provider-aws-cloudsearch-fips and two harvester-fips
subpackages. A stereo PR adds the missing tests.

Known limits, left for follow-ups: FIPS_GO_PREFIXES is only go-fips (not
go-msft or go-geomys), templated go-package values such as
${{vars.go-version}} are invisible without a melange compile, and Go
built through make or a script is not detected.

Fixtures under test-data/ show the three flagged shapes and the covered
ones.
…ain, resolve vars

Review follow-ups on #18 now that #20 is in:

- Move the melange config walkers (iter_steps, iter_pipelines, subpackages,
  build_steps, test_steps, environment_packages, uses_any) and the
  load-and-report loop into pre_commit_hooks/melange.py, and rebuild both
  check-pipeline-name-only-steps and check-for-go-fips-test on it. Each
  hook is now its check function plus argparse.
- Treat every toolchain family test/go-fips-check can verify as FIPS:
  go-fips and go-fips-md5 (at 1.27 these are meta packages pointing at
  go-msft-1.27), go-msft, go-geomys and go-openssl. Limiting the rule to
  go-fips would have exempted the toolchain new FIPS builds are moving to.
  On stereo main this adds 15 findings, all gitlab-rails FIPS streams that
  rebuild the devfile gem's Go helper with go-msft and never run
  go-fips-check.
- Resolve ${{vars.NAME}} from the top-level vars: mapping before matching
  toolchain names, so templated go-package values are visible without a
  melange compile. var-transforms are left alone.
- Repair the rebase onto #20: both hooks keep their full manifest entries
  and example-config lines, which a keep-both merge had truncated.
- Document the go-fips fixtures in test-data/README.md.
@AmberArcadia
AmberArcadia force-pushed the check-for-go-fips-test branch from 783c691 to 458f58e Compare October 23, 2026 20:11
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.

2 participants