Skip to content

docs(rfc): state qualified identifiers in the RFC headers #878

docs(rfc): state qualified identifiers in the RFC headers

docs(rfc): state qualified identifiers in the RFC headers #878

Workflow file for this run

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