Skip to content

ci: harden the pipeline with lint, race tests, vulnerability, and CodeQL jobs - #44

Merged
giraffesyo merged 2 commits into
canaryfrom
ci/harden-pipeline
Aug 4, 2026
Merged

ci: harden the pipeline with lint, race tests, vulnerability, and CodeQL jobs#44
giraffesyo merged 2 commits into
canaryfrom
ci/harden-pipeline

Conversation

@giraffesyo

@giraffesyo giraffesyo commented Aug 4, 2026

Copy link
Copy Markdown
Member

Follow-up to #43, which added a deliberately minimal workflow to stop the bleeding. This brings it to what a public Go repo should actually have.

What #43 left on the table

  • One serial job, ubuntu only — the generator is go installed on macOS and Windows too, and nothing exercised those paths.
  • No linter beyond go vet.
  • No race detector, no test shuffling.
  • No dependency or vulnerability scanning, despite an open Dependabot alert on the repo.
  • actions/checkout@v4 and actions/setup-go@v5 are on the deprecated Node 20 runtime — every run emitted a deprecation annotation.

Jobs

lintgofmt -l (with a diff on failure), go mod tidy drift check, go vet, and golangci-lint. The tidy check catches a go.mod/go.sum that a contributor forgot to regenerate, which is otherwise invisible until it breaks someone else's build.

test — matrix over ubuntu / macos / windows. go build ./..., then go test -race -shuffle=on -coverprofile. Race matters because the generator's e2e tests spawn nested go test runs; shuffle catches order-dependent tests. Coverage is summarized into the job summary and uploaded as an artifact (no third-party service, no token).

vulncheckgovulncheck ./....

codeqlsecurity-and-quality queries on PRs, pushes to canary, and weekly, so newly published queries reach code that has already merged.

Two decisions worth flagging

govulncheck runs on stable, not go.mod's version. govulncheck reports standard-library advisories against the toolchain it runs with. The go directive (1.25.5) declares the minimum release this module supports, not the one to build with — pinning the scan to it would report every stdlib CVE fixed since, permanently red, for something no change to this repo can address. Scanning with the current toolchain reports what a fresh go install actually produces.

Worth knowing what this does not cover: a user building with an older toolchain gets that toolchain's stdlib. That's inherent to go install and not fixable from CI.

The open Dependabot alert is not reachable. github.com/buger/jsonparser (DoS) comes in transitively via libopenapi. govulncheck's call-graph analysis confirms this repo doesn't reach the vulnerable code — it's in the "modules you require, but your code doesn't appear to call" bucket. The added dependabot.yml (weekly, grouped, chore(deps) prefix so release-please classifies the commits) will pick up the fix when upstream ships it.

.golangci.yml

Starts conservative: the standard set (errcheck, govet, ineffassign, staticcheck, unused) plus misspell and usetesting, with errcheck relaxed in _test.go. Deliberately not a maximal linter set — a lint gate that lands with hundreds of pre-existing findings gets ignored or disabled. Easy to widen once it's green and habitual.

Still needed (org-level, outside this PR)

The parallelworks ruleset on the default branch requires 2 approvals and linear history but sets no required_status_checks. Until ci / lint and ci / test are marked required, a red run still won't block a merge — which is the difference between having CI and being protected by it.

Verification

gofmt, go vet, go mod tidy drift, and go test -race -shuffle=on ./... all pass locally. The remaining jobs — golangci-lint, the macOS/Windows matrix legs, govulncheck, and CodeQL — are verified by this PR's own run.


What the new jobs caught on their first run

The pipeline found three real defects immediately, all fixed in the second commit here.

1. Two unchecked errors (errcheck, cmd/generate.go). generateCmd.MarkFlagRequired("spec") and ("out") discarded their returns. init can't return, so the errors are now joined into a package-level setupErr that Execute reports before running anything — no panic, per the repo's Go standards. Verified generate with no flags still errors with required flag(s) "out", "spec" not set.

2. A genuine Windows bug in the generator, not just a test failure. TestGenerate_EmbeddedFields failed on windows-latest. Cause: git checks templates out with CRLF on Windows, and the generator writes template bytes verbatim through text/template — so a Windows clone emitted CRLF in every generated .go file. Fixed at the root with .gitattributes (* text=auto eol=lf) rather than by loosening the assertion. This only affects building from a source checkout; go install pulls LF bytes from the module proxy.

3. The Windows test step never even started. The runner defaults to PowerShell, which split -coverprofile=coverage.out into two arguments, leaving go test looking for a package named .out. The workflow now pins defaults.run.shell: bash across the matrix.

Worth noting the second one is exactly the class of bug the old single-OS pipeline could never have surfaced.

Final status

All seven checks pass: lint, test (ubuntu-latest), test (macos-latest), test (windows-latest), vulncheck, analyze, CodeQL. CodeQL's security-and-quality suite reported no findings.

…eQL jobs

The initial workflow ran a single serial job on ubuntu with no linter, no race
detector, and no dependency scanning, and its actions were still on the
deprecated Node 20 runtime.

Split it into lint, test, and vulncheck jobs, add CodeQL, and add a dependabot
config so the gomod and github-actions ecosystems stay current. Tests now run
with -race and -shuffle=on across ubuntu, macos, and windows, since the
generator is installed on all three.

govulncheck deliberately runs on the stable toolchain: it reports
standard-library advisories against whatever Go it runs with, and the go
directive names the minimum supported release, not the one to build with.
@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

errcheck flagged two unchecked MarkFlagRequired calls in generate's init.
init cannot return, so the error is now joined into a package-level setupErr
that Execute reports before running the command.

TestGenerate_EmbeddedFields failed on windows because git checks templates out
with CRLF there. The generator writes template bytes verbatim, so a windows
clone emitted CRLF in every generated .go file; .gitattributes pins the working
tree to LF.

The test step itself failed to even start on windows: the runner defaults to
PowerShell, which split -coverprofile=coverage.out into two arguments and left
go test looking for a package named .out. Pin the workflow to bash.
@giraffesyo
giraffesyo merged commit 49ba1b5 into canary Aug 4, 2026
7 checks passed
@giraffesyo
giraffesyo deleted the ci/harden-pipeline branch August 4, 2026 23:54
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