diff --git a/.github/workflows/offline-tests.yaml b/.github/workflows/offline-tests.yaml index e03a3a1..0b644e9 100644 --- a/.github/workflows/offline-tests.yaml +++ b/.github/workflows/offline-tests.yaml @@ -74,6 +74,12 @@ jobs: # endpoints. Compares each standalone OVAL check against its copy in the # datastream, which no schema validation covers because each copy is only # ever checked against the schema in isolation. + # Formatting and full vet. `go test` runs only a subset of vet and no + # formatting check at all, so without this an unformatted file reaches + # main unnoticed — which is how one did. + - name: Lint Go tooling + run: make lint-go + - name: Check OVAL mirrors against the datastream run: make validate_mirrors diff --git a/Makefile b/Makefile index 38bf46c..2100d38 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,27 @@ test-offline-clean: .PHONY: test-offline test-offline-clean +# Formatting and static analysis for the Go test tooling. Neither was gated +# anywhere until now: CI ran `go test` only, so an unformatted file reached main +# unnoticed. +# +# gofmt -l is checked by its output rather than its exit status on purpose — it +# exits 0 whether or not it lists anything, so `gofmt -l . && ...` silently +# succeeds on unformatted input. `go test` runs only a subset of vet, so vet is +# run in full here to cover the rest. +lint-go: + @cd tests/oscap-offline && \ + unformatted=$$(gofmt -l .); \ + if [ -n "$$unformatted" ]; then \ + echo "::error::gofmt: these files are not formatted; run 'gofmt -w' on them:"; \ + echo "$$unformatted" | sed 's/^/ /'; \ + exit 1; \ + fi; \ + echo "gofmt: clean"; \ + go vet ./... && echo "go vet: clean" + +.PHONY: lint-go + # Trust-store sidecar guard. CertificateAudit pins no digest; it reads each # expected value from a sidecar file the image build writes beside the trust # store. This target checks that premise against a real image: the sidecars diff --git a/README.md b/README.md index c7c9a1b..daf9338 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,13 @@ The comparison lives in it also runs as part of `make test-offline` and on PRs via the offline workflow. +**Go tooling lint** — `make lint-go` checks `gofmt` and runs `go vet` +in full across `tests/oscap-offline`. Neither was gated before: CI ran +`go test` only, which applies no formatting check and only a subset of +vet, so an unformatted file reached `main` unnoticed. Note `gofmt -l` +exits 0 whether or not it lists anything, so the target inspects its +output rather than its exit status. + ### Tier 1 (fast) — offline Go harness `make test-offline` runs the `tests/oscap-offline` Go module. For each