Repository navigation
fix: deliver the fixture and process overrides on InitRequest (#686) #1653
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: Go CLI | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| quality: | |
| name: ${{ matrix.gate }} | |
| runs-on: ubuntu-latest | |
| # The race and coverage gates take 4-5 minutes on a warm cache with ±40s of | |
| # runner variance, so a 5-minute budget cancels borderline-healthy runs. | |
| # 8 minutes keeps a hang from burning a full runner-hour while leaving the | |
| # suite real headroom. | |
| timeout-minutes: 8 | |
| # `conformance_rows` is the set of docs/supported-matrix.md rows this gate | |
| # claims to prove. A claimed row's tests can no longer skip themselves when | |
| # the backend is missing, and the always-run receipt check below fails if a | |
| # claimed row never ran. | |
| env: | |
| CODEFLY_CONFORMANCE_REQUIRED: ${{ matrix.conformance_rows }} | |
| CODEFLY_CONFORMANCE_RECEIPTS: ${{ github.workspace }}/conformance-receipts | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| include: | |
| - gate: bootstrap-audit | |
| - gate: control-integration | |
| conformance_rows: linux-amd64-nix-run | |
| - gate: coverage | |
| conformance_rows: linux-amd64-source,linux-amd64-native-npm | |
| - gate: race | |
| conformance_rows: linux-amd64-source,linux-amd64-native-npm | |
| steps: | |
| - name: checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Go | |
| if: matrix.gate == 'coverage' || matrix.gate == 'race' | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version-file: go.mod | |
| cache: false | |
| # The production source-workspace regression runs the released Python | |
| # plugin on a fresh Linux host. Provision its declared uv runtime in the | |
| # ordinary test lanes so the proof exercises real tests instead of an | |
| # environment-blocked agent response. | |
| - name: Set up uv | |
| if: matrix.gate == 'coverage' || matrix.gate == 'race' | |
| uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 | |
| # pkg/librarystore's npm backend shells out to the real npm CLI (npm pack, | |
| # npm publish) against an httptest registry rather than mocking the store; | |
| # those tests need node/npm on the runner. | |
| - name: Set up Node | |
| if: matrix.gate == 'coverage' || matrix.gate == 'race' | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| # Restore before the bootstrap action: that action compiles the CLI, so | |
| # restoring afterward would make its cache permanently ineffective. | |
| # Cache only compiled artifacts. Caching GOMODCACHE alongside a Go | |
| # toolchain directive can race setup-go's toolchain install and produce | |
| # tar restore conflicts. | |
| - name: Restore Go build cache | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 | |
| with: | |
| path: ~/.cache/go-build | |
| key: cli-go-build-v3-${{ matrix.gate }}-${{ runner.os }}-${{ hashFiles('go.sum') }} | |
| restore-keys: | | |
| cli-go-build-v3-${{ matrix.gate }}-${{ runner.os }}- | |
| # This is both the canonical bootstrap and the cross-repository action | |
| # contract consumed by Codefly products. Dogfood the local action so a | |
| # release cannot publish an installer that CI never exercised. | |
| - name: install Codefly | |
| if: matrix.gate == 'bootstrap-audit' || matrix.gate == 'control-integration' | |
| uses: ./.github/actions/install | |
| - name: Install Dependencies | |
| run: go mod download | |
| - name: Verify the composed-module command is packaged | |
| if: matrix.gate == 'bootstrap-audit' | |
| run: codefly sync module --help | |
| # govulncheck gate via the CLI (replaces scripts/govulncheck.sh): | |
| # suppressions + staleness from .govulncheck.yaml, fails only on | |
| # actionable (upstream-fixed) findings. | |
| - name: govulncheck audit | |
| if: matrix.gate == 'bootstrap-audit' | |
| run: | | |
| go install golang.org/x/vuln/cmd/govulncheck@v1.8.0 | |
| codefly audit go --dir . | |
| - name: Test with coverage | |
| if: matrix.gate == 'coverage' | |
| run: go test -failfast ./... -coverprofile=cover.out -covermode=atomic -coverpkg=./... | |
| - name: Check test coverage | |
| if: matrix.gate == 'coverage' | |
| id: coverage | |
| uses: vladopajic/go-test-coverage@f94bcf0d6b9fa5fb8b783830b22648f6c17475e2 # v2 | |
| with: | |
| config: ./.testcoverage.yaml | |
| # The CGO-free companion/self-cross build (`-tags codefly_nosemantic`, | |
| # CGO_ENABLED=0) selects pkg/engine/source_nosemantic.go. `codefly | |
| # companion publish` exercises it only in companions.yaml, which needs | |
| # Docker; verify here, unconditionally, that the variant both links | |
| # statically and runs its base source behavior. Without this a regression | |
| # in the analyzer-free variant would surface only at publish time. | |
| - name: Verify CGO-free (companion) build variant | |
| if: matrix.gate == 'coverage' | |
| env: | |
| CGO_ENABLED: "0" | |
| run: | | |
| go build -tags codefly_nosemantic -ldflags '-s -w -extldflags "-static"' -o /dev/null . | |
| go test -tags codefly_nosemantic ./pkg/engine/ -run '^TestNewSourceExecutesLanguageNeutralOperation$' -count=1 | |
| - name: Test with race detection | |
| if: matrix.gate == 'race' | |
| run: go test -failfast -race ./... -v | |
| # The cross-process control-ownership proof drives the CLI built by the | |
| # install action above as a real subprocess against real sockets. It runs | |
| # here rather than in the default lanes because those would have to link | |
| # a CLI binary of their own; it needs neither Nix nor an agent, so it runs | |
| # before both and fails fast. | |
| - name: Run the cross-process control-ownership proof | |
| if: matrix.gate == 'control-integration' | |
| run: go test -tags=integration -run '^TestRunRefusesAControlAddressAnotherProcessOwns$|^TestConcurrentDisposableRunsClaimDistinctIdentities$' ./cmd/run -v | |
| # The pinned Redis agent resolves a Nix runtime during runtime-init, so the | |
| # proof needs Nix on the runner or the agent fails with "nix is not | |
| # installed" instead of exercising the real dependency. Mirrors core's CI. | |
| - name: Install Nix | |
| # Strict — nix is core to the platform; if it doesn't install, | |
| # CI must fail loud rather than silently skipping nix tests. | |
| # DeterminateSystems' installer is the de-facto standard for | |
| # GH Actions: deterministic, no daemon issues on ephemeral runners. | |
| # | |
| # This used to follow @main. It is now pinned to a release, like every | |
| # other action here, so the comment records the tag at the pinned commit | |
| # (v23) rather than the branch it was reached through — Dependabot | |
| # resolves the version from the tag at the SHA, so a `# main` comment | |
| # would be silently rewritten to a version on the first bump. | |
| if: matrix.gate == 'control-integration' | |
| uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23 | |
| - name: Allow unprivileged user namespaces (for bwrap) | |
| # Ubuntu 24.04 ships with kernel.apparmor_restrict_unprivileged_userns=1 | |
| # which blocks bubblewrap's user-namespace setup ("bwrap: setting up uid | |
| # map: Permission denied"). Disabling the restriction is the standard CI | |
| # workaround — bwrap then works in unprivileged mode, which is what the | |
| # nix runtime's sandbox expects. | |
| if: matrix.gate == 'control-integration' | |
| run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 | |
| - name: Install the pinned Redis agent | |
| if: matrix.gate == 'control-integration' | |
| run: codefly agent install codefly.dev/redis:0.0.74 | |
| - name: Run the in-process run-profile proof | |
| if: matrix.gate == 'control-integration' | |
| run: go test -tags=integration -run '^TestRunProfilesStartRealDependencyShapesInProcess$' ./pkg/control -v | |
| # Pull separately from the proof below so a cold-cache image fetch is | |
| # attributed to its own step instead of inflating the test's wall time — | |
| # this gate shares one 8-minute job budget with the Nix install above. | |
| # Keep the tag in step with teardownPostgresImage in | |
| # pkg/orchestration/teardown_postgres_integration_test.go. | |
| - name: Pull the ordered-teardown proof's database image | |
| if: matrix.gate == 'control-integration' | |
| run: docker pull postgres:16-alpine | |
| # Ordered teardown (F09): the consumer holds its drain open and commits a | |
| # final transaction to a disposable Postgres; the database must not begin | |
| # stopping until that commit returned. Needs Docker, which the runner has. | |
| # It claims no conformance row: the ordering contract is backend-neutral, | |
| # so it proves nothing about a docs/supported-matrix.md row. | |
| - name: Run the ordered-teardown acceptance proof | |
| if: matrix.gate == 'control-integration' | |
| run: go test -tags=integration -run '^TestFlowStopHoldsPostgresUntilItsConsumerCommits$' ./pkg/orchestration -v | |
| - name: Verify CI image prerequisite ordering | |
| if: matrix.gate == 'control-integration' | |
| run: go test -tags=integration -run '^TestCIBuildOrdersRealImagePrerequisites$' ./cmd/ci -v | |
| # Keep the tag in step with qualificationImage in | |
| # cmd/generate/container_recovery_docker_test.go. | |
| - name: Pull the interrupted-generate proof's image | |
| if: matrix.gate == 'control-integration' | |
| run: docker pull alpine:3.22 | |
| # `codefly generate` builds its containers in the CLI process rather than | |
| # through an agent, so no fleet rebuild can make them recoverable and no | |
| # unit test can prove they are: the labels and the sweep that reads them | |
| # only exist against a real daemon. This is the only container-recovery | |
| # dimension the CLI can qualify without a rebuilt, published agent — | |
| # cli#658 carries the rest. | |
| - name: Run the interrupted-generate container-recovery proof | |
| if: matrix.gate == 'control-integration' | |
| run: go test -tags=integration -run '^TestAnInterruptedGenerateLeavesARecoverableContainer$' ./cmd/generate -v | |
| # The source-workspace pin is promoted by hand through `codefly agent | |
| # promote-source`, which qualifies a candidate only through `codefly test | |
| # source`. This drives the pin the binary actually embeds against the | |
| # contracts that gate never reaches — Builder.SBOM, Builder.Package, and a | |
| # go.work-governed checkout — so a promotion cannot land on a release that | |
| # regressed one of them. It downloads the pinned agent, so it needs | |
| # network but no Docker. It claims no conformance row: a roster pin is not | |
| # a docs/supported-matrix.md row. | |
| - name: Qualify the embedded source-workspace pin | |
| if: matrix.gate == 'control-integration' | |
| env: | |
| CODEFLY_SOURCE_PIN_QUALIFY: "1" | |
| run: go test -tags=integration -run '^TestPinnedGoAgentAnswersSourceContractsForAGoWorkCheckout$' ./pkg/sourceworkspace -v | |
| # Always-run so a failed or filtered-out test still has to account for | |
| # the rows its job claimed. Keep these last: they audit every step above. | |
| - name: Verify conformance receipts | |
| if: always() && matrix.conformance_rows != '' | |
| run: ./scripts/verify-conformance-receipts.sh | |
| - name: Upload conformance receipts | |
| if: always() && matrix.conformance_rows != '' | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: conformance-receipts-${{ matrix.gate }} | |
| path: conformance-receipts/ | |
| if-no-files-found: warn | |
| # golangci-lint runs as its own job, not a quality gate, for two reasons: | |
| # only-new-issues has a well-defined baseline only against a pull-request base | |
| # branch (on push there is no diff to gate against), and a cold-cache | |
| # whole-repository analysis needs more headroom than the 5-minute quality | |
| # budget. Pinned to match the version documented in the Makefile (`make | |
| # lint`). only-new-issues gates the PR on newly introduced findings so the | |
| # pre-existing backlog does not block work while the standard is enforced. | |
| lint: | |
| name: lint | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| timeout-minutes: 10 | |
| steps: | |
| - name: checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Go | |
| uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 | |
| with: | |
| go-version-file: go.mod | |
| cache: false | |
| - name: golangci-lint | |
| uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0 | |
| with: | |
| # v2.13.1 bundles staticcheck (honnef.co/go/tools) v0.8.0, the first | |
| # release that understands Go 1.27 stdlib source; v2.12.2's v0.7.0 | |
| # panics in its IR builder analyzing 1.27 packages. Keep in sync with | |
| # GOLANGCI_LINT_VERSION in the Makefile. | |
| version: v2.13.1 | |
| # Build the linter from source under the module's Go toolchain | |
| # (1.27) instead of downloading the prebuilt binary, which is built | |
| # with an older Go and refuses to lint a module targeting a newer | |
| # one ("the Go language version used to build golangci-lint is lower | |
| # than the targeted Go version"). Matches `make lint`. | |
| install-mode: goinstall | |
| only-new-issues: true | |
| # pkg/web/go-grpc/out is a committed, generated artifact: web/dashboard builds | |
| # into it and go:embed ships it inside the CLI binary (see the Makefile's | |
| # `dashboard` target, which is the only other place it is produced). | |
| # | |
| # Nothing else in CI runs npm, so without this job a dependency bump under | |
| # web/dashboard changes package.json and package-lock.json, leaves out/ | |
| # untouched, and passes every Go gate — TestHandlerServesDashboard included, | |
| # because that test asserts against the committed bundle and so cannot notice | |
| # that the bundle no longer corresponds to the declared dependencies. The | |
| # binary would ship a dashboard built from the old dependency tree while the | |
| # lockfile claimed the new one, and the drift would surface at the next manual | |
| # `make dashboard`, several merges downstream of the bump that caused it. | |
| # | |
| # The build is byte-reproducible from the lockfile, so a clean tree is a fair | |
| # gate rather than a flaky one. | |
| dashboard: | |
| name: dashboard | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Set up Node | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| with: | |
| # Pinned rather than left to the runner default: this job's whole | |
| # value is that a dirty out/ means the dependencies moved, so the | |
| # toolchain producing out/ must not drift underneath it. | |
| node-version: '24' | |
| cache: npm | |
| cache-dependency-path: web/dashboard/package-lock.json | |
| # npm ci, not npm install: it fails closed on a package.json that has | |
| # drifted from the lockfile instead of silently resolving something else. | |
| - name: Rebuild the embedded dashboard | |
| run: | | |
| set -euo pipefail | |
| cd web/dashboard | |
| npm ci | |
| npm run build | |
| # --intent-to-add so a newly emitted asset (an untracked file) is visible | |
| # to `git diff`; without it the check would only catch modifications and | |
| # deletions, and a build that added a chunk would pass while out/ was | |
| # missing it. | |
| - name: Fail if the committed bundle is stale | |
| run: | | |
| set -euo pipefail | |
| git add --intent-to-add -- pkg/web/go-grpc/out | |
| if ! git diff --exit-code -- pkg/web/go-grpc/out; then | |
| echo "::error::pkg/web/go-grpc/out does not match a build of web/dashboard. Run 'make dashboard' and commit the result." | |
| exit 1 | |
| fi |