ci: pin action versions to commit SHAs and enable test shuffling #214
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Strict CI pipeline for hawk-eco Go repos. | |
| # All jobs must pass — no continue-on-error except where explicitly noted. | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| security-events: write | |
| pull-requests: read | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| GO_VERSION: "1.26.3" | |
| jobs: | |
| # ------------------------------------------------------------------------- | |
| # 1. Format — gofumpt + goimports must be clean (zero tolerance). | |
| # ------------------------------------------------------------------------- | |
| format: | |
| name: format | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: gofumpt | |
| run: | | |
| go install mvdan.cc/gofumpt@latest | |
| out=$(gofumpt -l .) | |
| if [ -n "$out" ]; then | |
| echo "::error::gofumpt would reformat:" | |
| echo "$out" | head -20 | |
| exit 1 | |
| fi | |
| - name: goimports | |
| run: | | |
| go install golang.org/x/tools/cmd/goimports@latest | |
| out=$(goimports -l .) | |
| if [ -n "$out" ]; then | |
| echo "::error::goimports would reformat:" | |
| echo "$out" | head -20 | |
| exit 1 | |
| fi | |
| # ------------------------------------------------------------------------- | |
| # 2. Module hygiene — tidy, verify, no stray replace directives. | |
| # ------------------------------------------------------------------------- | |
| module: | |
| name: module hygiene | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: go mod tidy | |
| run: | | |
| go mod tidy | |
| if ! git diff --quiet -- go.mod go.sum; then | |
| echo "::error::go.mod / go.sum out of date — run 'go mod tidy'" | |
| git diff -- go.mod go.sum | |
| exit 1 | |
| fi | |
| - name: go mod verify | |
| run: go mod verify | |
| - name: no stray replace directives | |
| run: | | |
| if grep -q "^\s*replace" go.mod; then | |
| echo "::warning::go.mod contains replace directives (should use go.work for local dev)" | |
| fi | |
| # ------------------------------------------------------------------------- | |
| # 3. Vet + static analysis — compiler-level correctness. | |
| # ------------------------------------------------------------------------- | |
| vet: | |
| name: vet | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: go vet | |
| run: go vet ./... | |
| # ------------------------------------------------------------------------- | |
| # 4. Lint — golangci-lint with zero-tolerance policy. | |
| # ------------------------------------------------------------------------- | |
| lint: | |
| name: lint | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Remove go.work (local dev only) | |
| run: rm -f go.work go.work.sum | |
| - uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v8.0.0 | |
| with: | |
| version: v2.1.0 | |
| install-mode: goinstall | |
| args: --timeout=5m | |
| env: | |
| GOWORK: "off" | |
| # ------------------------------------------------------------------------- | |
| # 5. Tests — race detector, coverage threshold, test shuffling. | |
| # ------------------------------------------------------------------------- | |
| test: | |
| name: test (race + coverage) | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Test with race detector | |
| run: go test ./... -race -count=1 -shuffle=on -coverprofile=coverage.out -covermode=atomic -timeout=300s | |
| - name: Coverage summary | |
| run: | | |
| coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | tr -d '%') | |
| echo "Coverage: ${coverage}%" | |
| echo "coverage=${coverage}" >> $GITHUB_ENV | |
| - name: Coverage threshold (minimum 10%) | |
| run: | | |
| if (( $(echo "${coverage} < 10" | bc -l) )); then | |
| echo "::error::Coverage ${coverage}% is below minimum 10%" | |
| exit 1 | |
| fi | |
| - name: Upload coverage | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: coverage-${{ github.job }} | |
| path: coverage.out | |
| retention-days: 30 | |
| # ------------------------------------------------------------------------- | |
| # 6. Security — vulnerability scan + secret detection. | |
| # ------------------------------------------------------------------------- | |
| security: | |
| name: security | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: govulncheck | |
| run: | | |
| go install golang.org/x/vuln/cmd/govulncheck@latest | |
| govulncheck ./... | |
| - name: gosec (strict) | |
| run: | | |
| go install github.com/securego/gosec/v2/cmd/gosec@latest | |
| gosec -exclude=G104 -confidence=high -severity=medium ./... | |
| # ------------------------------------------------------------------------- | |
| # 7. Secret scan — detect leaked API keys, tokens, credentials. | |
| # ------------------------------------------------------------------------- | |
| secrets: | |
| name: secrets | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: 0 | |
| - uses: gitleaks/gitleaks-action@3838638076c55b796d98e7f7bc1f8d93fda089e4 # v2.11.0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ------------------------------------------------------------------------- | |
| # 8. Dependency review — only on pull requests. | |
| # ------------------------------------------------------------------------- | |
| dependency-review: | |
| name: dependency review | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0 | |
| # ------------------------------------------------------------------------- | |
| # 9. Markdown lint — validate documentation quality. | |
| # ------------------------------------------------------------------------- | |
| markdown: | |
| name: markdown | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: DavidAnson/markdownlint-cli2-action@43d16a9f5a242a4e2109391f3d7e7e4d8e3b6c7d # v19.0.0 | |
| with: | |
| globs: '**/*.md' | |
| config: | | |
| { | |
| "default": true, | |
| "line-length": false, | |
| "no-inline-html": false, | |
| "first-line-h1": false, | |
| "no-duplicate-heading": false, | |
| "no-emphasis-as-heading": false | |
| } | |
| # ------------------------------------------------------------------------- | |
| # 10. Cross-platform build matrix — zero CGO, all targets. | |
| # ------------------------------------------------------------------------- | |
| build: | |
| name: build (${{ matrix.goos }}/${{ matrix.goarch }}) | |
| runs-on: ubuntu-latest | |
| needs: [format, lint, test, security] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| goos: [linux, darwin, windows] | |
| goarch: [amd64, arm64] | |
| exclude: | |
| - goos: windows | |
| goarch: arm64 | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Build | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| CGO_ENABLED: "0" | |
| run: go build -trimpath -v ./... | |
| - name: Binary size check (linux/amd64 only) | |
| if: matrix.goos == 'linux' && matrix.goarch == 'amd64' | |
| run: | | |
| size=$(go build -trimpath -o /tmp/hawk-bin . && wc -c < /tmp/hawk-bin) | |
| size_mb=$((size / 1024 / 1024)) | |
| echo "Binary size: ${size_mb}MB" | |
| if [ "$size_mb" -gt 100 ]; then | |
| echo "::warning::Binary size ${size_mb}MB exceeds 100MB threshold" | |
| fi | |
| rm -f /tmp/hawk-bin |