Skip to content

release: v0.7.1

release: v0.7.1 #1734

Workflow file for this run

name: codefly core
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Cancel an in-progress run when a new push to the same ref lands.
# A commit that's been superseded doesn't need to finish CI — saves
# minutes and shortens the feedback loop. Group by workflow+ref so
# main-branch pushes only cancel each other (not, say, a PR run).
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
jobs:
# Separate from build deliberately. The gate needs full history and a network
# round trip to the BSR, and neither belongs in the job that runs the test
# suite: inside build, a buf.build hiccup would abort before `go test` ever
# ran and report as a schema break, and a red Build would say nothing about
# which half failed. Split, the two answer independently and in parallel.
proto:
name: Proto
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# buf reads the baseline out of this checkout's own .git, and the
# default depth-1 fetch populates no refs/remotes/origin/*, so there
# would be no main to diff against.
fetch-depth: 0
- name: set up buf
uses: bufbuild/buf-setup-action@a47c93e0b1648d5651a065437926377d060baa99 # v1.50.0
with:
# Must match the buf the proto companion bakes
# (companions/proto/Dockerfile); internal/ciguard's
# TestWorkflowBufMatchesTheCompanionImage fails when the two drift.
# Left unset, the action installs 1.50.0 — its own default, not the
# latest.
version: 1.73.0
github_token: ${{ github.token }}
- name: proto breaking-change guard
# proto/ is the schema source of truth for the whole ecosystem, and
# nothing in CI read it — a wire-breaking edit and its regenerated
# bindings were verified only on the contributor's machine.
#
# The script is the gate, and `make buf-breaking` runs the same one, so
# what CI checks and what a developer can run before pushing cannot
# drift into two programs. It owns the baseline (the merge base), the
# BSR retry, and the one way a reviewed schema deletion may land: a
# commit touching proto/ that declares the break in Conventional
# Commits. An undeclared break is still exit 100, and the findings are
# printed either way. internal/ciguard holds all three of those.
run: ./scripts/check_proto_breaking.sh
- name: proto lint guard
# proto/buf.yaml has selected BASIC + COMMENTS since the module landed
# and proto/README.md has always said to run `buf lint` before
# committing, but no workflow ran it. The obligation rotted into 363
# standing COMMENTS findings, which is what an undocumented field costs
# once the next real one is indistinguishable from them (#567).
#
# Exit 100 and the retry loop mean what they mean in the step above.
working-directory: proto
run: |
for attempt in 1 2 3; do
if buf lint; then
exit 0
else
code=$?
fi
if [ "$code" -eq 100 ]; then
exit 100
fi
echo "buf exited $code (attempt $attempt/3), not a rule violation; retrying in 15s" >&2
sleep 15
done
echo "buf lint could not complete after 3 attempts" >&2
exit 1
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Pull Alpine Image
run: docker pull alpine:latest
# We use it for tests
- name: set up
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.0"
- name: checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: agent contract release notes
run: python3 -m unittest discover -s scripts -p test_agent_contract_release.py
- name: version/tag drift guard
# version/info.codefly.yaml is embedded into the binary and gates every
# package install through composition's minimum-codefly-version check,
# but no test reads it — so it has silently rotted (0.3.8 while v0.3.18
# shipped; 0.3.20 while v0.3.24 shipped). Fail here instead of at a
# user's install. Reads tag names via ls-remote, so the shallow
# checkout above is fine.
run: ./scripts/check_version_tag.sh
- name: Cache Go Modules
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
continue-on-error: true
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go
- name: Install Dependencies
run: go mod tidy && go mod download
- name: CGO-free surface guard
# cgo-ness is a link-time property of the import graph: a new import can
# silently drag a cgo-only package (the tree-sitter grammars under
# code/semantic) into a surface that must stay CGO-free, and nothing
# fails until a downstream CGO_ENABLED=0 build (companion publish, an
# alpine image) tries to link — weeks later, one repo away. This builds
# every package except the documented cgo allowlist with CGO_ENABLED=0
# so creep fails HERE, at the PR that introduces it. See docs/cgo.md.
run: ./scripts/check_cgo_free.sh
- name: Darwin surface guard
# Every runner in this repository is ubuntu, so nothing in CI ever
# compiles the GOOS=darwin files: runners/base's process-identity and
# postgres-IPC implementations, plus the darwin-only tests under
# runners/ and toolbox/launch. A type error in one of them merges green
# and breaks only on a developer's machine. Type-check that surface from
# this runner so it fails HERE instead.
#
# Mirrors scripts/check_cgo_free.sh: the tree-sitter grammars under
# code/semantic cannot cross-compile without cgo, so they are excluded
# and the supported CGO-free constructor is selected with
# codefly_nosemantic. vet covers test files, which `go build` does not.
#
# This type-checks only. RUNNING the darwin tests still needs a macOS
# runner, which would add a required status check — see
# docs/runbooks/branch-protection.md.
run: |
set -euo pipefail
pkgs=()
while IFS= read -r line; do
pkgs+=("$line")
done < <(GOOS=darwin go list -f '{{if .GoFiles}}{{.ImportPath}}{{end}}' ./... \
| grep -vxF -e "github.com/codefly-dev/core/code/semantic")
echo "Type-checking the darwin surface: ${#pkgs[@]} packages"
CGO_ENABLED=0 GOOS=darwin go vet -tags codefly_nosemantic "${pkgs[@]}"
- name: Install apt deps (bubblewrap, ripgrep)
# bubblewrap → core/runners/sandbox tests (default + sandbox_e2e)
# ripgrep → core/code search tests (real-repo grep coverage)
# Both are part of the strict signal — codefly's security
# stack and code-search depend on them, so a broken install
# MUST fail CI. The retry loop handles transient mirror flakes
# (azure.archive.ubuntu.com periodically hiccups for ~5-10
# minutes); sustained outages still fail loud as intended.
run: |
for i in 1 2 3; do
sudo apt-get update && sudo apt-get install -y bubblewrap ripgrep && exit 0
echo "apt failed (attempt $i / 3); waiting 30s before retry"
sleep 30
done
echo "apt install failed after 3 attempts" >&2
exit 1
- name: Install uv
# Strict — uv drives core/runners/python's formula runner tests
# (formula_run_test.go), which exercise the REAL uv+python toolchain
# and fail-loud (requireUv never skips) when uv is absent. astral-sh's
# setup-uv is the de-facto standard installer for GH Actions: pinned,
# deterministic, adds uv to PATH. uv provisions its own Python on
# demand, so no separate python setup is needed.
uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
- name: Python agent contract SDK
env:
PYTHONPATH: generated/python/codefly-cli/codefly_cli
run: >-
uv run --no-project --with protobuf==7.36.1 --with grpcio==1.83.1
--with googleapis-common-protos==1.75.3
python -m unittest discover
-s generated/python/codefly-cli/codefly_cli/tests
-p test_effective_inputs_contract.py
- 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 ref tracked the `main` BRANCH before it was pinned. The pinned
# commit is also tagged v23, so Dependabot's github-actions updater can
# still move it (it bumps SHA pins to newer releases, and would have
# nothing to move an untagged branch commit to).
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 our sandbox layer expects.
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
#
# - name: golangci-lint
# uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
# with:
# version: v1.55
- name: govulncheck audit
# scripts/govulncheck.sh mirrors `codefly audit go` / `codefly
# agent build`'s audit logic: runs govulncheck, partitions
# findings against .govulncheck.yaml suppressions + staleness,
# fails only when an unsuppressed vuln has an upstream fix
# available (unpatched-upstream issues can't be cleared by a
# rebuild).
#
# This deliberately does NOT shell out to the codefly CLI:
# github.com/codefly-dev/cli is a PRIVATE module, and core's CI
# checks out core alone with no credentials for sibling repos, so
# `go install github.com/codefly-dev/cli@latest` fails with
# "could not read Username" / "Authentication failed". The script
# only needs govulncheck (public, go-installable) and is fully
# self-contained — no private-repo dependency.
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
./scripts/govulncheck.sh
- name: generate test generate coverage
# Single strict signal. -tags=sandbox_e2e,nix_required opts
# into the integration tests that depend on bubblewrap (the
# OS sandbox layer) and the nix binary. Both are installed
# strict above; if either install failed, CI already failed
# before reaching this step.
#
# NOT included: proto_companion_required. Those tests
# (grpc_test.go, openapi_test.go) need the ghcr.io/codefly-dev/proto
# Docker image which can't be built from core's CI alone
# (it cross-builds the codefly CLI from a sibling checkout).
# Run locally with `go test -tags=proto_companion_required`,
# OR — once codefly CLI is installable in CI — bring the
# image build into the workflow as `codefly companion build
# proto` and add the tag here.
run: go test ./... -tags=sandbox_e2e,nix_required -coverprofile=cover.out -covermode=atomic -coverpkg=./...
- name: check test coverage
id: coverage
uses: vladopajic/go-test-coverage@f94bcf0d6b9fa5fb8b783830b22648f6c17475e2 # v2.19.0
with:
config: ./.testcoverage.yaml
## when token is not specified (value '') this feature is turned off
## in this example badge is created and committed only for main branch
git-token: ${{ github.ref_name == 'main' && github.token || '' }}
## name of branch where badges are stored
## ideally this should be orphan branch (see below how to create this branch)
git-branch: badges
- name: test with race detection
# Strict, separate from coverage. Races are real bugs (we
# found a bytes.Buffer concurrent-write race in NativeProc
# that flaked Linux CI for months), so the race detector
# has to run alongside the regular suite — not as a
# commented-out optional. CLI already does this; bring
# core to parity.
#
# We skip sandbox_e2e + nix_required tags here: the race
# detector roughly doubles test runtime, and the integration
# suites also run in the regular step above with full
# coverage. Race-detector signal lands fastest by sticking
# to the unit + light-integration scope.
run: go test -race ./... -timeout 10m
- name: Notify Slack on Failure
# Push-only, and not merely to cut PR noise: a workflow run triggered by
# Dependabot (or a fork) is handled as though it came from a fork, so
# `secrets.*` resolves to the empty string. slack-github-action rejects
# an empty webhook outright -- `throw new Error('Need to provide at
# least one botToken or webhookUrl')` -- and core.setFailed turns the
# whole job red after build, test, race and coverage have all passed.
# These alerts are about main's health anyway, so gate them on push.
if: failure() && github.event_name == 'push'
uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
with:
# The action resolves the webhook URL from SLACK_WEBHOOK_URL below,
# but reads the type from this input alone -- there is no environment
# fallback for it -- and throws before sending when it is absent.
webhook-type: incoming-webhook
payload: |
{
"text": "Build Failed in ${{ github.repository }} on ${{ github.ref }}. See GitHub Actions for more details."
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify Slack on Success
# Push-only for the same reason as the failure notification above: on a
# Dependabot pull request this step would fire on every GREEN run and
# fail it. See the comment there.
if: success() && github.event_name == 'push'
uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
with:
# See the failure notification above.
webhook-type: incoming-webhook
payload: |
{
"text": "Build Succeeded in ${{ github.repository }} on ${{ github.ref }}. Great job!"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}