Skip to content

ci: pin action versions to commit SHAs and enable test shuffling #214

ci: pin action versions to commit SHAs and enable test shuffling

ci: pin action versions to commit SHAs and enable test shuffling #214

Workflow file for this run

# 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