fix: update hawk-core-contracts to v0.1.6 and fix hawk-mcpkit replace… #798
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 GrayCodeAI 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.5" | |
| # GrayCodeAI sibling modules are resolved from the local external/ submodules via | |
| # go.work; their go.mod require versions (v0.1.0) intentionally do not match the | |
| # frozen public proxy/sumdb snapshot, so bypass the proxy + checksum DB for them. | |
| GOPRIVATE: "github.com/GrayCodeAI/*" | |
| GONOSUMDB: "github.com/GrayCodeAI/*" | |
| GONOSUMCHECK: "1" | |
| jobs: | |
| # ------------------------------------------------------------------------- | |
| # 1. Format — gofumpt + goimports must be clean (zero tolerance). | |
| # ------------------------------------------------------------------------- | |
| format: | |
| name: format | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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@v0.10.0 | |
| 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@v0.30.0 | |
| out=$(goimports -l .) | |
| if [ -n "$out" ]; then | |
| echo "::error::goimports would reformat:" | |
| echo "$out" | head -20 | |
| exit 1 | |
| fi | |
| - name: shared types import guard | |
| run: bash ./scripts/check-shared-types-imports.sh | |
| - name: ecosystem boundary guard | |
| run: bash ./scripts/check-ecosystem-boundaries.sh | |
| - name: internal layer boundary guard | |
| run: bash ./scripts/check-internal-layer-imports.sh | |
| - name: eyrie client boundary guard | |
| run: bash ./scripts/check-eyrie-client-imports.sh | |
| - name: eyrie engine facade boundary guard | |
| run: bash ./scripts/check-eyrie-engine-boundary.sh | |
| # ------------------------------------------------------------------------- | |
| # 2. Module hygiene — tidy, verify (hawk + external ecosystem repos via go.work). | |
| # ------------------------------------------------------------------------- | |
| module: | |
| name: module hygiene | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: go work sync + module consistency | |
| run: | | |
| # Ecosystem repos are external checkouts under hawk/external. go mod tidy can mis-resolve | |
| # workspace modules here; go work sync is the supported workspace hygiene step. | |
| go work sync | |
| go build -mod=readonly -o /dev/null ./cmd/hawk | |
| if ! git diff --quiet -- go.mod go.sum go.work go.work.sum; then | |
| echo "::error::go.mod / go.sum / go.work files out of date — run 'go work sync' locally and commit" | |
| git diff -- go.mod go.sum go.work go.work.sum | |
| exit 1 | |
| fi | |
| - name: go mod verify | |
| run: go mod verify | |
| - name: workspace points at external checkouts | |
| run: | | |
| for module in hawk-core-contracts eyrie inspect sight tok trace yaad; do | |
| if ! grep -q "./external/${module}" go.work; then | |
| echo "::error::go.work must include ./external/${module}." | |
| cat go.work | |
| exit 1 | |
| fi | |
| done | |
| public-modules: | |
| name: public module graph | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Verify public dependency graph | |
| env: | |
| GOWORK: "off" | |
| run: | | |
| go mod download | |
| go mod verify | |
| go build -mod=readonly ./cmd/hawk | |
| go test ./... -count=1 -timeout=300s | |
| submodule-release-parity: | |
| name: submodule and module parity | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - run: bash ./scripts/check-submodule-release-parity.sh | |
| # ------------------------------------------------------------------------- | |
| # 3. Vet + static analysis — compiler-level correctness. | |
| # ------------------------------------------------------------------------- | |
| vet: | |
| name: vet | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: go vet | |
| run: go vet ./... | |
| - name: support repo coupling guard | |
| run: bash ./scripts/check-support-repo-coupling.sh | |
| # ------------------------------------------------------------------------- | |
| # 4. Lint — golangci-lint with project-specific config. | |
| # ------------------------------------------------------------------------- | |
| lint: | |
| name: lint | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Run golangci-lint | |
| run: | | |
| go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.0 | |
| golangci-lint run --timeout=5m | |
| # ------------------------------------------------------------------------- | |
| # 5. Tests — race detector, coverage threshold, test shuffling. | |
| # ------------------------------------------------------------------------- | |
| test: | |
| name: test (race + coverage) | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - 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 -skip=TestDefaultSkillDirsCrossAgent | |
| - name: Coverage summary | |
| run: | | |
| coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | tr -d '%' | tail -1) | |
| echo "Coverage: ${coverage}%" | |
| echo "COVERAGE=${coverage}" >> "$GITHUB_ENV" | |
| - name: Coverage threshold (minimum 60%) | |
| run: | | |
| if (( $(echo "${COVERAGE} < 60" | bc -l) )); then | |
| echo "::error::Coverage ${COVERAGE}% is below minimum 60%" | |
| exit 1 | |
| fi | |
| - name: Upload coverage | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: coverage-${{ github.job }} | |
| path: coverage.out | |
| retention-days: 30 | |
| - name: Enforce test skip policy | |
| continue-on-error: true | |
| run: | | |
| # Find all t.Skip() calls without a tracking issue comment | |
| # Policy: t.Skip() should have a comment with a GitHub issue link on the same or previous line | |
| violations="" | |
| while IFS= read -r line; do | |
| file=$(echo "$line" | cut -d: -f1) | |
| lineno=$(echo "$line" | cut -d: -f2) | |
| # Check previous line for issue link | |
| prev_line=$((lineno - 1)) | |
| if [ "$prev_line" -gt 0 ]; then | |
| prev_content=$(sed -n "${prev_line}p" "$file") | |
| if echo "$prev_content" | grep -qE '(github\.com/.*issues/|#\d+|TODO|FIXME|HACK)'; then | |
| continue | |
| fi | |
| fi | |
| # Check same line for issue link | |
| content=$(sed -n "${lineno}p" "$file") | |
| if echo "$content" | grep -qE '(github\.com/.*issues/|#\d+|TODO|FIXME|HACK)'; then | |
| continue | |
| fi | |
| violations="${violations}\n${file}:${lineno}: t.Skip() without tracking issue" | |
| done < <(grep -rn 't\.Skip(' --include='*_test.go' . --exclude-dir=external 2>/dev/null | grep -v '// nolint' || true) | |
| if [ -n "$violations" ]; then | |
| echo "::warning::Found t.Skip() without tracking issue:${violations}" | |
| echo "" | |
| echo "Policy: Every t.Skip() should have a comment linking to a GitHub issue." | |
| echo "Example:" | |
| echo " // TODO: https://github.com/GrayCodeAI/hawk/issues/123" | |
| echo " t.Skip(\"not yet implemented\")" | |
| fi | |
| # ------------------------------------------------------------------------- | |
| # 6. Security — vulnerability scan + secret detection. | |
| # ------------------------------------------------------------------------- | |
| security: | |
| name: security | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - 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@v1.1.4 | |
| govulncheck ./... | |
| - name: gosec | |
| run: | | |
| go install github.com/securego/gosec/v2/cmd/gosec@v2.22.4 | |
| # Full-strength scan: no rule exclusions. The repo reached a | |
| # 0-findings baseline (2026-07 full-repo audit); keep it that way. | |
| # Suppressions must be inline `#nosec <rule> -- <justification>`. | |
| gosec -quiet -exclude-dir external ./... | |
| # ------------------------------------------------------------------------- | |
| # 7. Secret scan — detect leaked API keys, tokens, credentials. | |
| # ------------------------------------------------------------------------- | |
| secrets: | |
| name: secrets | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: trufflesecurity/trufflehog@27b0417c16317ca9a472a9a8092acce143b49c55 # v3.95.9 | |
| with: | |
| extra_args: --only-verified | |
| # ------------------------------------------------------------------------- | |
| # 8. Markdown lint — validate documentation quality. | |
| # ------------------------------------------------------------------------- | |
| markdown: | |
| name: markdown | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Run markdownlint-cli2 | |
| run: | | |
| npm install -g markdownlint-cli2 | |
| markdownlint-cli2 '**/*.md' | |
| # ------------------------------------------------------------------------- | |
| # Dead code detection. | |
| # ------------------------------------------------------------------------- | |
| deadcode: | |
| name: deadcode | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c | |
| with: | |
| go-version: "${{ env.GO_VERSION }}" | |
| cache: true | |
| - name: deadcode | |
| run: | | |
| go install golang.org/x/tools/cmd/deadcode@v0.30.0 | |
| output=$(mktemp) | |
| trap 'rm -f "$output"' EXIT | |
| deadcode ./... >"$output" | |
| count=$(wc -l <"$output" | tr -d ' ') | |
| echo "deadcode inventory: ${count} unreachable functions" | |
| { | |
| echo "### Deadcode inventory (${count} findings; first 50 shown)" | |
| echo | |
| echo '```text' | |
| head -50 "$output" | |
| echo '```' | |
| } >>"$GITHUB_STEP_SUMMARY" | |
| # ------------------------------------------------------------------------- | |
| # Duplication detection — jscpd. | |
| # ------------------------------------------------------------------------- | |
| jscpd: | |
| name: duplication | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: '24' | |
| - name: jscpd | |
| run: | | |
| npx jscpd --min-lines 5 --min-tokens 50 --reporters console --blame . 2>&1 | head -50 | |
| # ------------------------------------------------------------------------- | |
| # 9. 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - 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: | | |
| # Use -ldflags="-s -w" to match release build size (Makefile LDFLAGS). | |
| # This catches binary bloat regressions against the actual shipped artifact size. | |
| size=$(go build -trimpath -ldflags="-s -w" -o /tmp/hawk-bin ./cmd/hawk && wc -c < /tmp/hawk-bin) | |
| size_mb=$((size / 1024 / 1024)) | |
| echo "Binary size: ${size_mb}MB" | |
| # Threshold lowered from 110MB → 80MB. With -ldflags="-s -w" the | |
| # release binary is ~76MB. A 80MB threshold gives 4MB headroom for | |
| # regression detection while still being realistic. | |
| if [ "$size_mb" -gt 80 ]; then | |
| echo "::warning::Binary size ${size_mb}MB exceeds 80MB threshold" | |
| fi | |
| rm -f /tmp/hawk-bin | |
| # ------------------------------------------------------------------------- | |
| # Fuzz — short corpus runs to catch panics in fuzz targets. | |
| # ------------------------------------------------------------------------- | |
| fuzz: | |
| name: fuzz (60s) | |
| runs-on: ubuntu-latest | |
| needs: [test] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Run fuzz targets | |
| run: | | |
| go test -fuzz=FuzzScanForAIComments -fuzztime=60s ./cmd/... || true | |
| go test -fuzz=FuzzValidateSettings -fuzztime=60s ./internal/config/... || true | |
| go test -fuzz=FuzzIsSuspicious -fuzztime=60s ./internal/tool/... || true | |
| go test -fuzz=FuzzIsSafeGitCommit -fuzztime=60s ./internal/tool/... || true | |
| go test -fuzz=FuzzParseMessage -fuzztime=60s ./internal/session/... || true | |
| go test -fuzz=FuzzParseSessionMeta -fuzztime=60s ./internal/session/... || true | |
| # ------------------------------------------------------------------------- | |
| # 10. Smoke — build hawk and verify ecosystem CLI wiring. | |
| # ------------------------------------------------------------------------- | |
| smoke: | |
| name: smoke | |
| runs-on: ubuntu-latest | |
| needs: [format, vet] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - uses: ./.github/actions/checkout-eyrie | |
| with: | |
| ref: ${{ github.head_ref || github.ref_name }} | |
| - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: smoke-hawk.sh | |
| run: ./scripts/smoke-hawk.sh |