docs(rfc): state qualified identifiers in the RFC headers #878
Workflow file for this run
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
| name: Build | |
| # Runs on every PR + every push to develop/main. Validates the binary | |
| # builds cleanly across all 8 release-target platforms, the tests pass, | |
| # and the linter is green. Release-time signing + tag artifacts live | |
| # in release.yml (Phase 5). | |
| on: | |
| push: | |
| branches: [develop, main] | |
| pull_request: | |
| branches: [develop, main] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: build-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| schema-drift: | |
| timeout-minutes: 10 | |
| name: Schema drift check | |
| # Verifies the embedded internal/schema/ingest.v1.json matches | |
| # tracebloc/data-ingestors at the PINNED ref (scripts/.data-ingestors-ref), | |
| # not a floating branch. A green PR that silently diverges from the schema | |
| # jobs-manager enforces is a real correctness hazard — a customer's YAML | |
| # could pass `tracebloc ingest validate` locally but be rejected in-cluster | |
| # (or vice versa). Pinning stops an unrelated upstream commit from redding | |
| # every open CLI PR; adopting upstream is a deliberate SHA bump + re-sync | |
| # (backend#1009). | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: scripts/sync-schema.sh --check | |
| run: ./scripts/sync-schema.sh --check | |
| installer: | |
| timeout-minutes: 10 | |
| name: Installer (shell) | |
| # The curl|sh installer is the most privileged code we ship (it places the | |
| # binary on PATH) and had NO automated test until R8. shellcheck it under | |
| # the POSIX sh dialect it actually runs as, parse it with dash, and run the | |
| # functional harness that asserts cosign verification is mandatory / fails | |
| # closed when cosign is absent (RFC-0001 R8, backend#889). | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: shellcheck + dash parse | |
| run: | | |
| sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck dash | |
| shellcheck --shell=sh --severity=error scripts/install.sh | |
| shellcheck --shell=bash --severity=error scripts/check-style.sh | |
| dash -n scripts/install.sh | |
| bash -n scripts/tests/install-verify.sh | |
| - name: Verification harness (mandatory cosign / fail-closed) | |
| run: bash scripts/tests/install-verify.sh | |
| test: | |
| timeout-minutes: 15 | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| - name: go vet | |
| run: go vet ./... | |
| - name: go test | |
| # -race catches data races in the test process. The CLI is | |
| # not concurrent today (Phase 0), but the watch/log-stream | |
| # path in Phase 4 will be — enabling -race from day one keeps | |
| # us from having to retrofit it later. | |
| run: go test -race -cover ./... | |
| - name: Coverage floor (cli, submit, push, cluster must not rot) | |
| # `go test -cover` above prints numbers but asserts nothing. This | |
| # enforces a per-package floor on the load-bearing, historically | |
| # thin-tested packages (the money path + submit orchestration) so a | |
| # test deletion can't silently drop coverage. Floors ratchet UP only — | |
| # see scripts/coverage-floor.sh (backend#1009). | |
| run: ./scripts/coverage-floor.sh | |
| lint: | |
| timeout-minutes: 10 | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| # golangci-lint-action@v6 reproducibly time-budgeted out at | |
| # ~2 minutes on this module's k8s.io-heavy dep tree (3 runs | |
| # in a row in early 2026 — see #6). Stand-alone tools run | |
| # against the same code in <30 seconds and catch the bugs | |
| # we've actually hit this week (unchecked Fprintf errors | |
| # were errcheck-catchable; gofmt -s drift was a recurring | |
| # nit). Going back to the action when #6 has a strategy. | |
| # Tool versions are pinned for reproducibility (was @latest, which | |
| # drifted — see #127). The current tags build cleanly against this | |
| # module's Go floor; the old "stale x/tools breaks the build" worry | |
| # is gone now that these tools ship newer tags. Keep these in lockstep | |
| # with the *_VERSION vars in the Makefile. Bump deliberately. | |
| - name: errcheck | |
| run: | | |
| go install github.com/kisielk/errcheck@v1.20.0 | |
| errcheck ./... | |
| - name: gofmt -s | |
| run: | | |
| drift="$(gofmt -s -l .)" | |
| if [ -n "$drift" ]; then | |
| echo "::error::gofmt -s drift in:" | |
| echo "$drift" | sed 's/^/ /' | |
| echo "::error::run \`make fmt\` to fix" | |
| exit 1 | |
| fi | |
| # goimports -local: enforce the stdlib / third-party / our-own import | |
| # grouping that .golangci.yml's local-prefixes already declares. gofmt | |
| # doesn't check grouping, so drift accumulated silently until now. | |
| - name: goimports -local | |
| run: | | |
| go install golang.org/x/tools/cmd/goimports@v0.48.0 | |
| drift="$(goimports -local github.com/tracebloc/cli -l .)" | |
| if [ -n "$drift" ]; then | |
| echo "::error::goimports (import grouping) drift in:" | |
| echo "$drift" | sed 's/^/ /' | |
| echo "::error::run \`make fmt\` to fix" | |
| exit 1 | |
| fi | |
| - name: ineffassign | |
| run: | | |
| go install github.com/gordonklaus/ineffassign@v0.2.0 | |
| ineffassign ./... | |
| - name: misspell | |
| run: | | |
| go install github.com/client9/misspell/cmd/misspell@v0.3.4 | |
| misspell -error . | |
| # staticcheck (standalone, pinned): the full `all` suite minus ST1005. | |
| # ST1005 (error-string style) flags ~58 customer-visible error strings | |
| # that need a deliberate wording review — follow-up to #279, not a | |
| # mechanical sweep. The old golangci-lint OOM story does not apply to | |
| # the standalone binary: full run is ~12s wall on this module. | |
| - name: staticcheck | |
| run: | | |
| go install honnef.co/go/tools/cmd/staticcheck@2025.1.1 | |
| staticcheck -checks all,-ST1005 ./... | |
| # deadcode: BLOCKING reachability scan from the CLI entrypoint (~5s). | |
| # The four legit unreachables — Stringer methods (Status.String, | |
| # JobOutcome.String) reached only via fmt reflection that static | |
| # analysis can't see, plus the di#349 test-only parity harnesses | |
| # (ReadLabelValues, inferColumnType) — are declared with reasons in | |
| # scripts/deadcode-allowlist.txt. Anything else unreachable fails the | |
| # job (#281 flipped this from advisory/continue-on-error). Tool version | |
| # pinned inside the script; DEADCODE_VERSION overrides. | |
| - name: deadcode | |
| run: ./scripts/deadcode-check.sh | |
| - name: File budget (line-count ratchet) | |
| # Per-file line ceilings; they only ratchet DOWN — raising one is a | |
| # deliberate, reviewed edit to scripts/file-budget.sh. Keeps the next | |
| # 1500-line data.go from growing quietly (backend#1106 WS-B). | |
| run: ./scripts/file-budget.sh | |
| - name: Style + terminology guard | |
| # Enforces the terminal style system (STYLE.md): no hardcoded brand colour | |
| # outside the tone engine (internal/ui), no status/traffic-light emoji, and | |
| # "secure environment" not "workspace" in user-facing text. Mechanical | |
| # checks only — role/wording judgement stays with review. | |
| run: bash scripts/check-style.sh | |
| govulncheck: | |
| timeout-minutes: 10 | |
| name: govulncheck | |
| # Reachability-scans the module for known vulnerabilities (stdlib + | |
| # deps) on every PR and push. This is a customer-installed binary — | |
| # 6 reachable CVEs shipped in v0.8.0 before this gate existed (#276). | |
| # Pinned version, same rationale as the lint tools above; keep in | |
| # lockstep with GOVULNCHECK_VERSION in the Makefile and the copy of | |
| # this job in vulncheck.yml (the weekly cron that catches CVEs | |
| # published between PRs). Bump deliberately. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| - name: govulncheck ./... | |
| run: | | |
| go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 | |
| govulncheck ./... | |
| build: | |
| timeout-minutes: 20 | |
| name: Build (${{ matrix.os }}/${{ matrix.arch }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| # Don't fail-fast — we want the matrix to surface ALL broken | |
| # platforms in one run, not stop at the first. | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: linux | |
| arch: amd64 | |
| - os: linux | |
| arch: arm64 | |
| - os: linux | |
| arch: '386' | |
| - os: linux | |
| arch: arm | |
| goarm: '6' # keep in lock-step with release.yml's matrix | |
| - os: darwin | |
| arch: amd64 | |
| - os: darwin | |
| arch: arm64 | |
| - os: windows | |
| arch: amd64 | |
| ext: .exe | |
| - os: windows | |
| arch: arm64 | |
| ext: .exe | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Set up Go | |
| uses: actions/setup-go@v7 | |
| with: | |
| go-version-file: go.mod | |
| cache: true | |
| - name: Build | |
| env: | |
| GOOS: ${{ matrix.os }} | |
| GOARCH: ${{ matrix.arch }} | |
| GOARM: ${{ matrix.goarm }} # only applies when GOARCH=arm | |
| CGO_ENABLED: "0" | |
| run: | | |
| mkdir -p dist | |
| go build \ | |
| -trimpath \ | |
| -ldflags "\ | |
| -s -w \ | |
| -X main.version=${{ github.ref_name }}-${GITHUB_SHA:0:7} \ | |
| -X main.gitSHA=${GITHUB_SHA:0:12} \ | |
| -X main.buildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ | |
| -o dist/tracebloc-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }} \ | |
| ./cmd/tracebloc | |
| - name: Smoke test (Linux amd64 only — host arch matches runner) | |
| if: matrix.os == 'linux' && matrix.arch == 'amd64' | |
| # Cross-built darwin/windows/arm64 binaries can't run on the | |
| # ubuntu runner, so only the native build gets exercised | |
| # post-compile. The other platforms get compile-time | |
| # validation only — which is still meaningful because | |
| # client-go and most k8s deps have OS-conditional code paths. | |
| run: | | |
| BIN=./dist/tracebloc-linux-amd64 | |
| "$BIN" version | |
| "$BIN" version --output-json | python3 -c "import json,sys; d=json.load(sys.stdin); assert d['version'], 'empty version'" | |
| # ingest validate exercises the embedded schema + validation | |
| # wiring on the real binary (no cluster needed): a valid spec | |
| # must pass, and an invalid one must be rejected with exit 2. | |
| "$BIN" ingest validate testdata/smoke/valid-image-classification.yaml | |
| if "$BIN" ingest validate testdata/smoke/invalid-missing-images.yaml; then | |
| echo "::error::ingest validate accepted an invalid spec (missing 'images')"; exit 1 | |
| fi | |
| # Command-tree wiring smoke for the dominant verb. | |
| "$BIN" dataset push --help >/dev/null | |
| - name: Upload binary as artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: tracebloc-${{ matrix.os }}-${{ matrix.arch }} | |
| path: dist/tracebloc-${{ matrix.os }}-${{ matrix.arch }}${{ matrix.ext }} | |
| retention-days: 7 | |
| if-no-files-found: error |