diff --git a/.github/workflows/build-shim.yml b/.github/workflows/build-shim.yml deleted file mode 100644 index 7195c4b4..00000000 --- a/.github/workflows/build-shim.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: build-shim - -# Shim for the `build` branch-protection required check. -# -# History: the old ci-java.yml defined a job named `build` that -# branch protection on main was configured to require. Phase 6 -# cutover deletes ci-java.yml, but the required-check name `build` -# remains in branch protection — so every PR sits forever on -# "build Expected — Waiting for status to be reported". -# -# This shim always runs and always succeeds, providing the `build` -# status that branch protection expects. It exists as a stopgap -# until a repo admin removes `build` from the required-checks list -# in the GitHub UI (Settings → Branches → main → required checks). -# At that point, this file can be deleted. -# -# go-ci.yml is the real build gate (vet/test/staticcheck/gosec/ -# govulncheck) and perf-gate.yml is the perf-regression gate; -# both are the appropriate replacements for the old Java `build`. - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - contents: read - -jobs: - build: - name: build - runs-on: ubuntu-latest - steps: - - name: Branch-protection compatibility shim - run: | - echo "build-shim: this job exists only to satisfy the legacy 'build' required-check" - echo "remove this workflow once branch protection drops 'build' from required-checks" - echo "the real Go gates are go-ci.yml + perf-gate.yml" diff --git a/.github/workflows/release-darwin.yml b/.github/workflows/release-darwin.yml new file mode 100644 index 00000000..8918b75f --- /dev/null +++ b/.github/workflows/release-darwin.yml @@ -0,0 +1,123 @@ +name: release-darwin + +# darwin/arm64 release on a macos-14 runner. Attaches binaries to the +# existing GitHub Release created by release-go.yml (which only builds +# linux). Runs after the linux release lands so the target Release +# already exists. +# +# Why a separate workflow: +# - release-go.yml runs on ubuntu-latest. CGO + kuzudb won't +# cross-compile cleanly to darwin from linux. +# - macos-14 runners are arm64 (M1+); cross-compile to darwin/arm64 +# happens via native CC = clang. +# - The two workflows publish to the same tag → same Release. + +on: + push: + tags: + - 'v*.*.*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to release (e.g. v0.3.0). Release must already exist.' + required: true + +permissions: + contents: write + id-token: write # Sigstore keyless via GitHub OIDC + attestations: write + +# Pass the input/ref to the shell via env vars (not inline `${{ }}` +# interpolation) — Semgrep `yaml.github-actions.security.run-shell-injection` +# rule. inputs.tag for workflow_dispatch; GITHUB_REF_NAME for tag pushes. +env: + TAG: ${{ github.event.inputs.tag || github.ref_name }} + +jobs: + release-darwin: + name: release (darwin / arm64) + runs-on: macos-14 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version: '1.25.10' + cache: true + cache-dependency-path: go/go.sum + + - name: Build darwin/arm64 binary + working-directory: go + env: + CGO_ENABLED: '1' + GOOS: darwin + GOARCH: arm64 + run: | + VERSION="${TAG#v}" + go build \ + -trimpath \ + -ldflags "-s -w \ + -X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Version=${VERSION}' \ + -X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Commit=$(git rev-parse --short HEAD)' \ + -X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Date=$(date -u +%Y-%m-%dT%H:%M:%SZ)' \ + -X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Dirty=false'" \ + -o codeiq ./cmd/codeiq + + - name: Package archive + working-directory: go + run: | + VERSION="${TAG#v}" + ARCHIVE_DIR="codeiq_${VERSION}_darwin_arm64" + mkdir -p "${ARCHIVE_DIR}" + cp codeiq "${ARCHIVE_DIR}/" + cp ../LICENSE "${ARCHIVE_DIR}/" 2>/dev/null || true + cp ../README.md "${ARCHIVE_DIR}/" 2>/dev/null || true + cp ../CHANGELOG.md "${ARCHIVE_DIR}/" 2>/dev/null || true + tar czf "../${ARCHIVE_DIR}.tar.gz" "${ARCHIVE_DIR}" + + - name: Install Syft (SBOM) + uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 + - name: Generate SBOM + run: | + VERSION="${TAG#v}" + ARCHIVE="codeiq_${VERSION}_darwin_arm64.tar.gz" + syft "$ARCHIVE" --output spdx-json="${ARCHIVE}.sbom.spdx.json" + + - name: Install Cosign (signing) + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + - name: Sign archive (Sigstore keyless, bundle format) + run: | + VERSION="${TAG#v}" + ARCHIVE="codeiq_${VERSION}_darwin_arm64.tar.gz" + cosign sign-blob \ + --yes \ + --bundle "${ARCHIVE}.cosign.bundle" \ + "$ARCHIVE" + + - name: Upload to GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + VERSION="${TAG#v}" + # Retry up to 3 times to handle race with release-go.yml + # creating the Release. + for i in 1 2 3; do + if gh release view "$TAG" >/dev/null 2>&1; then + gh release upload "$TAG" \ + "codeiq_${VERSION}_darwin_arm64.tar.gz" \ + "codeiq_${VERSION}_darwin_arm64.tar.gz.sbom.spdx.json" \ + "codeiq_${VERSION}_darwin_arm64.tar.gz.cosign.bundle" \ + --clobber + exit 0 + fi + echo "Release $TAG not yet visible, waiting 30s ($i/3)..." + sleep 30 + done + echo "::error::Release $TAG never appeared; release-go.yml may have failed" + exit 1 + + - name: Attest darwin archive (build provenance) + uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 + with: + subject-path: 'codeiq_*_darwin_arm64.tar.gz'