From b11b62607d3e399d808ff8a00e406011a9feb2ff Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 22:25:43 -0700 Subject: [PATCH 1/8] ci: cross-platform build matrix, release tooling, README badges Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 82 +++++++++++++++--- .typos.toml | 1 + README.md | 7 ++ RELEASE.md | 91 ++++++++++++++++++++ scripts/release.sh | 140 +++++++++++++++++++++++++++++++ 5 files changed, 310 insertions(+), 11 deletions(-) create mode 100644 RELEASE.md create mode 100755 scripts/release.sh diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 66a0213..f3edcf9 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -1,6 +1,12 @@ # Reusable: invoked by .github/workflows/ci.yml. Builds and tests -# across a Go-version matrix; SQLCipher's cgo build needs gcc and -# OpenSSL development headers, both already on ubuntu-latest runners. +# across an OS × Go matrix. SQLCipher's cgo build needs only a C +# compiler and standard libs (no external OpenSSL — we use the +# vendored libtomcrypt crypto backend). +# +# Layout: Unix and Windows are separate jobs because Windows requires +# the MSYS2/MinGW toolchain (the Go-shipped gcc detection on Windows +# is brittle; MSYS2 is the upstream-recommended pattern, mirrored from +# mattn/go-sqlite3's own CI). name: build-test on: @@ -11,19 +17,21 @@ permissions: contents: read jobs: - go: - name: go ${{ matrix.go }} - runs-on: ubuntu-latest - timeout-minutes: 15 + unix: + name: ${{ matrix.os }} / go ${{ matrix.go }} + runs-on: ${{ matrix.os }} + timeout-minutes: 20 strategy: fail-fast: false matrix: + # ubuntu-latest is x86_64. ubuntu-24.04-arm is the GitHub-hosted + # ARM64 runner (GA in private repos as of 2026-01). macos-latest + # is Apple Silicon (arm64). All three have cgo + race-detector + # support out of the box. + os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest] # `oldstable` and `stable` are setup-go aliases that always - # resolve to Go's two officially supported releases. As Go - # ships a new minor, the matrix tracks it without manual - # maintenance. The go directive in go.mod sets the actual - # minimum (currently 1.24). - go: ['oldstable', 'stable'] + # resolve to Go's two officially supported releases. + go: [oldstable, stable] steps: - name: Harden Runner uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 @@ -41,10 +49,62 @@ jobs: go-version: ${{ matrix.go }} - name: Build + env: + CGO_ENABLED: "1" run: go build -trimpath ./... - name: Vet run: go vet ./... - name: Test + env: + CGO_ENABLED: "1" + run: go test -race -count=1 ./... + + windows: + name: windows-latest / go ${{ matrix.go }} + runs-on: windows-latest + timeout-minutes: 30 + defaults: + run: + shell: 'msys2 {0}' + strategy: + fail-fast: false + matrix: + go: [oldstable, stable] + steps: + - name: Harden Runner + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Set up MSYS2 + MinGW-w64 + uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1 + with: + msystem: MINGW64 + update: true + install: mingw-w64-x86_64-toolchain + path-type: inherit + + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + with: + go-version: ${{ matrix.go }} + + - name: Build + env: + CGO_ENABLED: "1" + run: go build -trimpath ./... + + - name: Vet + run: go vet ./... + + - name: Test + env: + CGO_ENABLED: "1" run: go test -race -count=1 ./... diff --git a/.typos.toml b/.typos.toml index a7889d7..f0e3595 100644 --- a/.typos.toml +++ b/.typos.toml @@ -35,6 +35,7 @@ xeodou = "xeodou" libtomcrypt = "libtomcrypt" zetetic = "zetetic" Zetetic = "Zetetic" +intoto = "intoto" # Real names of contributors — not typos. Linz = "Linz" diff --git a/README.md b/README.md index 07f6181..b231e18 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,19 @@ > Self-contained Go driver for [SQLCipher](https://www.zetetic.net/sqlcipher/) — encrypted SQLite, audited, easy.

+ Latest release License Go Reference OpenSSF Scorecard Security policy

+

+ CI status + Tested platforms + Go versions +

+ Maintained by [@alanwiss](https://github.com/alanwiss), who picked up maintenance of this driver in 2026 after the upstream had been dormant since 2020. See [`CONTRIBUTORS.md`](CONTRIBUTORS.md) for the full chain diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..73519f7 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,91 @@ +# Release process + +This project ships a tagged release whenever there is enough accumulated +work to be worth a version bump. The default cadence is roughly +**quarterly** (matching SQLCipher upstream), with patch releases in +between for security or correctness fixes. + +## Release flow + +```sh +./scripts/release.sh v4.15.1 +``` + +The script enforces every safety check that a manual `git tag` could +forget: + +1. The version argument matches `vX.Y.Z[-pre]`. +2. You are on `main` with a clean working tree. +3. The tag does not already exist locally or on `origin`. +4. `CHANGELOG.md` has an entry for the new version (or a non-empty + `[Unreleased]` section to promote). +5. The latest CI run on `main` is green. + +After the dry-run summary, you confirm `y` and the script: + +- Creates a signed annotated tag (`git tag -s`) on the current commit. +- Pushes the tag to `origin`. + +The `sigstore-sign.yml` workflow takes over and produces: + +- Source tarball (`go-sqlcipher-vX.Y.Z.tar.gz`) +- SBOM (`go-sqlcipher.spdx.json`) +- cosign signature (`go-sqlcipher-vX.Y.Z.sigstore.json`) +- SLSA provenance (`*.intoto.jsonl` via slsa-github-generator) + +All four are uploaded to the GitHub Release page. + +## Choosing the version bump + +SemVer 2.0: + +| Change kind | Bump | +|---|---| +| Bug fix, no public API change (Tier 1/2 lint cleanup, security patch) | PATCH (`v4.15.0` → `v4.15.1`) | +| New public API, backwards-compatible (e.g. new helper func) | MINOR (`v4.15.0` → `v4.16.0`) | +| Breaking public API change (rare for a fork) | MAJOR (`v4.x.y` → `v5.0.0`) | +| SQLCipher upstream bump (e.g. 4.15 → 4.16) | MINOR by default | + +The `Conventional Commits` types in commit subjects map roughly to: + +- `fix:` → PATCH +- `feat:` → MINOR +- `feat!:` or `BREAKING CHANGE:` footer → MAJOR +- `chore:` / `docs:` / `test:` / `refactor:` → no bump on their own + +## CHANGELOG editing + +`CHANGELOG.md` follows [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/). +The `[Unreleased]` section accumulates entries between releases. When +tagging, manually rename `## [Unreleased]` to `## [X.Y.Z] — YYYY-MM-DD` +and start a new empty `## [Unreleased]` block above it. + +The release script does **not** modify `CHANGELOG.md` — keeping that +edit explicit makes the audit trail clear. + +## After tagging + +1. The Release page appears within ~5 minutes at + `https://github.com/WissCore/go-sqlcipher/releases/tag/vX.Y.Z`. +2. pkg.go.dev usually picks up the new version within ~15-30 minutes. + Force the fetch with: + + ```sh + GOPROXY=https://proxy.golang.org go list -m -versions github.com/WissCore/go-sqlcipher/v4 + ``` + +3. Update downstream `go.mod` files that pin to a specific version. + +## Branch protection + +`main` is protected: + +- Requires the single composite check `ci-success` (which depends on the + full matrix of build-test jobs across Linux x86_64, Linux ARM64, macOS, + and Windows; plus security scans, DCO, etc.). +- Requires PRs (no direct pushes). +- Requires conventional-commits PR titles. +- Requires DCO sign-off on every commit. + +Tags are only pushed by maintainers via the release script; we do not +auto-tag on merge. diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..6007c4f --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +# Release helper for WissCore/go-sqlcipher. +# +# Manual release flow with safety guards. Run from repo root with the +# new version tag as the only argument: +# +# ./scripts/release.sh v4.15.1 +# +# What it does: +# 1. Verifies argument is a valid semver-shaped tag (vX.Y.Z[-pre]). +# 2. Verifies branch is `main` and clean. +# 3. Verifies tag does not already exist (locally or on origin). +# 4. Verifies CHANGELOG.md has an entry for the new version (or that +# [Unreleased] has content to promote). +# 5. Verifies CI on main is green for the current HEAD. +# 6. Prints a dry-run summary and asks for explicit yes/no. +# 7. On confirmation: creates a signed annotated tag and pushes it. +# +# After push, the sigstore-sign workflow takes over: it produces a +# source tarball, SBOM, cosign signature, and SLSA provenance, and +# uploads them to the GitHub Release page. + +set -euo pipefail + +VERSION="${1:-}" +REPO_ROOT="$(git rev-parse --show-toplevel)" +cd "${REPO_ROOT}" + +# 1. Argument shape +if [[ -z "${VERSION}" ]]; then + cat <&2 +Usage: $0 vX.Y.Z[-pre] + +Example: $0 v4.15.1 +EOF + exit 1 +fi +if ! [[ "${VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then + echo "ERROR: version must match vX.Y.Z[-pre] (got: ${VERSION})" >&2 + exit 1 +fi + +# 2. Branch + working tree +BRANCH=$(git rev-parse --abbrev-ref HEAD) +if [[ "${BRANCH}" != "main" ]]; then + echo "ERROR: must release from main (current: ${BRANCH})" >&2 + exit 1 +fi +if ! git diff --quiet || ! git diff --cached --quiet; then + echo "ERROR: working tree has uncommitted changes" >&2 + git status --short >&2 + exit 1 +fi + +# 3. Tag uniqueness +if git rev-parse "refs/tags/${VERSION}" >/dev/null 2>&1; then + echo "ERROR: tag ${VERSION} already exists locally" >&2 + exit 1 +fi +if git ls-remote --exit-code --tags origin "refs/tags/${VERSION}" >/dev/null 2>&1; then + echo "ERROR: tag ${VERSION} already exists on origin" >&2 + exit 1 +fi + +# 4. CHANGELOG +if ! grep -qE "^## \[?${VERSION#v}\]?" CHANGELOG.md; then + if ! grep -qE '^## \[Unreleased\]' CHANGELOG.md; then + echo "ERROR: CHANGELOG.md has neither a ${VERSION} section nor an [Unreleased] section" >&2 + exit 1 + fi + # Check that [Unreleased] is not empty (has at least one bullet) + awk '/^## \[Unreleased\]/{found=1; next} found && /^## /{exit} found && /^- /{print; exit}' CHANGELOG.md | + grep -q . || { + echo "ERROR: CHANGELOG.md [Unreleased] section is empty — nothing to release" >&2 + exit 1 + } + echo "INFO: CHANGELOG.md will keep [Unreleased] heading; you should manually rename it to [${VERSION#v}] before tagging." + echo " (This script does NOT modify CHANGELOG.md to keep the audit trail explicit.)" +fi + +# 5. CI status (best effort: gh required) +if command -v gh >/dev/null 2>&1; then + HEAD_SHA=$(git rev-parse HEAD) + STATUS=$(gh run list --branch main --commit "${HEAD_SHA}" --limit 1 --json conclusion --jq '.[0].conclusion // "missing"' 2>/dev/null || echo "missing") + case "${STATUS}" in + success) echo "INFO: latest CI on main HEAD is green" ;; + missing) echo "WARN: no CI run found for main HEAD ${HEAD_SHA:0:7}" ;; + *) + echo "ERROR: latest CI on main HEAD is '${STATUS}', not 'success'" >&2 + exit 1 + ;; + esac +else + echo "WARN: gh CLI not installed — skipping CI status check" +fi + +# 6. Dry-run summary + confirmation +COMMIT=$(git rev-parse --short HEAD) +SUBJECT=$(git log -1 --pretty=%s) +cat < Date: Fri, 1 May 2026 22:46:45 -0700 Subject: [PATCH 2/8] ci(build-test): use human-readable matrix labels Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index f3edcf9..81b46e0 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,20 +18,26 @@ permissions: jobs: unix: - name: ${{ matrix.os }} / go ${{ matrix.go }} + name: ${{ matrix.label }} / go ${{ matrix.go }} runs-on: ${{ matrix.os }} timeout-minutes: 20 strategy: fail-fast: false matrix: - # ubuntu-latest is x86_64. ubuntu-24.04-arm is the GitHub-hosted - # ARM64 runner (GA in private repos as of 2026-01). macos-latest - # is Apple Silicon (arm64). All three have cgo + race-detector - # support out of the box. - os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest] - # `oldstable` and `stable` are setup-go aliases that always - # resolve to Go's two officially supported releases. - go: [oldstable, stable] + # Each include row pairs a runner label with a human-readable + # name that shows up in the PR checks UI. ubuntu-latest is + # x86_64; ubuntu-24.04-arm is the GitHub-hosted ARM64 runner + # (GA in private repos as of 2026-01); macos-latest is Apple + # Silicon (arm64). All have cgo + race-detector support. + # `oldstable` and `stable` track Go's two officially supported + # releases via setup-go aliases. + include: + - {os: ubuntu-latest, label: "Linux x86_64", go: oldstable} + - {os: ubuntu-latest, label: "Linux x86_64", go: stable} + - {os: ubuntu-24.04-arm, label: "Linux ARM64", go: oldstable} + - {os: ubuntu-24.04-arm, label: "Linux ARM64", go: stable} + - {os: macos-latest, label: "macOS Apple Silicon", go: oldstable} + - {os: macos-latest, label: "macOS Apple Silicon", go: stable} steps: - name: Harden Runner uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 @@ -62,7 +68,7 @@ jobs: run: go test -race -count=1 ./... windows: - name: windows-latest / go ${{ matrix.go }} + name: Windows x86_64 / go ${{ matrix.go }} runs-on: windows-latest timeout-minutes: 30 defaults: From d498818eaff66a232b06e44e4aa737a2defffaa1 Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 22:48:48 -0700 Subject: [PATCH 3/8] test: add cross-platform sanity tests (paths, locking, drive letters) Signed-off-by: Alan Wiss --- cross_platform_test.go | 158 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 cross_platform_test.go diff --git a/cross_platform_test.go b/cross_platform_test.go new file mode 100644 index 0000000..e64b683 --- /dev/null +++ b/cross_platform_test.go @@ -0,0 +1,158 @@ +// Cross-platform sanity tests. These run on every OS in the CI matrix +// and exercise real platform-native code paths (path separators, +// filename encoding, file-system locking semantics) that the inherited +// tests cover only implicitly through `t.TempDir`. +// +// Each test is intentionally fast (sub-second) so the full matrix +// stays under five minutes on the slowest runner. + +package sqlite3_test + +import ( + "crypto/rand" + "database/sql" + "encoding/hex" + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "sync" + "testing" + + _ "github.com/WissCore/go-sqlcipher/v4" + "github.com/stretchr/testify/require" +) + +// openEncryptedAt is a small helper that opens an encrypted DB at the +// given absolute path with a random 256-bit key, closes it, then +// reopens it and verifies a read-back. Used by the platform tests +// below to confirm that whatever path the OS hands us survives a full +// open/close/reopen round-trip. +func openEncryptedAt(t *testing.T, dbPath string) { + t.Helper() + var key [32]byte + _, err := io.ReadFull(rand.Reader, key[:]) + require.NoError(t, err) + dsn := fmt.Sprintf("%s?_pragma_key=x'%s'", dbPath, hex.EncodeToString(key[:])) + + db, err := sql.Open("sqlite3", dsn) + require.NoError(t, err) + require.NoError(t, db.Ping()) + _, err = db.Exec(`CREATE TABLE t(x INTEGER); INSERT INTO t VALUES (42);`) + require.NoError(t, err) + require.NoError(t, db.Close()) + + db2, err := sql.Open("sqlite3", dsn) + require.NoError(t, err) + defer db2.Close() + var got int + require.NoError(t, db2.QueryRow("SELECT x FROM t LIMIT 1;").Scan(&got)) + require.Equal(t, 42, got) +} + +// TestNativePathFilenameVariants opens an encrypted DB at filenames +// that exercise OS-native path handling: spaces, unicode, multiple +// dots, very long names. Different filesystems (NTFS, APFS, ext4) +// historically differ on what they accept; this test fails loudly if +// our DSN parser, the cgo bridge, or SQLite's file layer mishandle a +// path on the runner's OS. +func TestNativePathFilenameVariants(t *testing.T) { + t.Parallel() + cases := []struct { + name string + filename string + }{ + {"simple", "simple.db"}, + {"with_spaces", "name with spaces.db"}, + {"with_dashes", "name-with-dashes.db"}, + {"many_dots", "many.dots.in.the.name.db"}, + {"unicode", "юникод-名前.db"}, + {"very_long", "a_very_long_filename_that_pushes_path_length_to_test_filesystem_limits_on_each_os_runner.db"}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + openEncryptedAt(t, filepath.Join(t.TempDir(), tc.filename)) + }) + } +} + +// TestPlatformInfo emits the OS/arch/Go combo into the test log so +// CI artifacts and failure reports show exactly which runner exposed +// any subsequent failure. No assertions — pure breadcrumb. +func TestPlatformInfo(t *testing.T) { + t.Logf("runtime: GOOS=%s GOARCH=%s NumCPU=%d", runtime.GOOS, runtime.GOARCH, runtime.NumCPU()) +} + +// TestConcurrentOpenSameDB verifies that two database handles opened +// against the same encrypted file from the same process can both read +// without stepping on each other. SQLite's per-platform file-locking +// implementation differs (fcntl on Linux, BSD locks on macOS, LockFile +// on Windows); this test exercises the platform's actual locking path +// rather than mocking it. +func TestConcurrentOpenSameDB(t *testing.T) { + t.Parallel() + dbPath := filepath.Join(t.TempDir(), "shared.sqlite") + var key [32]byte + _, err := io.ReadFull(rand.Reader, key[:]) + require.NoError(t, err) + dsn := fmt.Sprintf("%s?_pragma_key=x'%s'&_journal_mode=WAL", dbPath, hex.EncodeToString(key[:])) + + // Seed. + seed, err := sql.Open("sqlite3", dsn) + require.NoError(t, err) + _, err = seed.Exec(`CREATE TABLE t(id INTEGER PRIMARY KEY); INSERT INTO t (id) VALUES (1);`) + require.NoError(t, err) + require.NoError(t, seed.Close()) + + // Two independent reader handles, each in its own goroutine, both + // hitting the same on-disk DB through the platform's lock manager. + const readers = 4 + var wg sync.WaitGroup + wg.Add(readers) + errCh := make(chan error, readers) + for i := 0; i < readers; i++ { + go func() { + defer wg.Done() + db, oerr := sql.Open("sqlite3", dsn) + if oerr != nil { + errCh <- fmt.Errorf("open: %w", oerr) + return + } + defer db.Close() + var got int + if serr := db.QueryRow("SELECT id FROM t LIMIT 1;").Scan(&got); serr != nil { + errCh <- fmt.Errorf("scan: %w", serr) + return + } + if got != 1 { + errCh <- fmt.Errorf("got %d, want 1", got) + } + }() + } + wg.Wait() + close(errCh) + for e := range errCh { + t.Error(e) + } +} + +// TestEnvHandlesAbsoluteAndRelativePath proves that both an absolute +// path (the t.TempDir default) and a relative path resolved from the +// process CWD work. Some Windows code paths historically misparsed +// drive-letter prefixes; this is the regression guard. +func TestEnvHandlesAbsoluteAndRelativePath(t *testing.T) { + t.Parallel() + tmpdir := t.TempDir() + + // Absolute first. + openEncryptedAt(t, filepath.Join(tmpdir, "absolute.sqlite")) + + // Relative — chdir into tmpdir, open by basename. + cwd, err := os.Getwd() + require.NoError(t, err) + require.NoError(t, os.Chdir(tmpdir)) + t.Cleanup(func() { _ = os.Chdir(cwd) }) + openEncryptedAt(t, "relative.sqlite") +} From 9ece92bef329b5183a98070a114e37e659775e66 Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 22:58:49 -0700 Subject: [PATCH 4/8] ci(build-test): expose platform as matrix axis for sidebar display Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 33 +++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 81b46e0..eef1686 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,26 +18,29 @@ permissions: jobs: unix: - name: ${{ matrix.label }} / go ${{ matrix.go }} - runs-on: ${{ matrix.os }} + name: ${{ matrix.platform }} / go ${{ matrix.go }} + runs-on: ${{ matrix.runner }} timeout-minutes: 20 strategy: fail-fast: false matrix: - # Each include row pairs a runner label with a human-readable - # name that shows up in the PR checks UI. ubuntu-latest is - # x86_64; ubuntu-24.04-arm is the GitHub-hosted ARM64 runner - # (GA in private repos as of 2026-01); macos-latest is Apple - # Silicon (arm64). All have cgo + race-detector support. - # `oldstable` and `stable` track Go's two officially supported - # releases via setup-go aliases. + # Two real axes (platform, go) so GitHub Actions' left-sidebar + # job list renders both — with include-only matrices the UI + # collapses to the differentiating axis and platform names + # disappear from the navigation. The include block then maps + # each platform to its concrete GitHub-hosted runner label. + platform: + - Linux-x86_64 + - Linux-ARM64 + - macOS-Apple-Silicon + go: [oldstable, stable] include: - - {os: ubuntu-latest, label: "Linux x86_64", go: oldstable} - - {os: ubuntu-latest, label: "Linux x86_64", go: stable} - - {os: ubuntu-24.04-arm, label: "Linux ARM64", go: oldstable} - - {os: ubuntu-24.04-arm, label: "Linux ARM64", go: stable} - - {os: macos-latest, label: "macOS Apple Silicon", go: oldstable} - - {os: macos-latest, label: "macOS Apple Silicon", go: stable} + - platform: Linux-x86_64 + runner: ubuntu-latest + - platform: Linux-ARM64 + runner: ubuntu-24.04-arm + - platform: macOS-Apple-Silicon + runner: macos-latest steps: - name: Harden Runner uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 From 875a56fc4a487919bb2b6c57b5b136401e626760 Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 23:07:00 -0700 Subject: [PATCH 5/8] ci(build-test): collapse to single object axis so sidebar shows platform Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index eef1686..cb163f6 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -18,29 +18,29 @@ permissions: jobs: unix: - name: ${{ matrix.platform }} / go ${{ matrix.go }} - runs-on: ${{ matrix.runner }} + name: ${{ matrix.target.platform }} / go ${{ matrix.go }} + runs-on: ${{ matrix.target.runner }} timeout-minutes: 20 strategy: fail-fast: false matrix: - # Two real axes (platform, go) so GitHub Actions' left-sidebar - # job list renders both — with include-only matrices the UI - # collapses to the differentiating axis and platform names - # disappear from the navigation. The include block then maps - # each platform to its concrete GitHub-hosted runner label. - platform: - - Linux-x86_64 - - Linux-ARM64 - - macOS-Apple-Silicon - go: [oldstable, stable] - include: + # Single object axis pattern: GitHub's left-sidebar label + # generator drops axes that come only from `include:`, but a + # top-level axis whose values are objects keeps the sidebar + # template fully resolvable. Each `target` row pairs the + # human-readable platform name with its GitHub-hosted runner + # label; the `name:` template above expands at job-start time + # and overrides the auto label in both the PR checks panel and + # the workflow run-page sidebar (community Discussions #9918, + # #49880). + target: - platform: Linux-x86_64 runner: ubuntu-latest - platform: Linux-ARM64 runner: ubuntu-24.04-arm - platform: macOS-Apple-Silicon runner: macos-latest + go: [oldstable, stable] steps: - name: Harden Runner uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 From 80d7bc15f7260de062fcc46b2eb932909ea041f8 Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 23:13:58 -0700 Subject: [PATCH 6/8] ci(build-test): split into one explicit job per OS for sidebar clarity Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 106 +++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index cb163f6..5776da0 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -1,12 +1,13 @@ # Reusable: invoked by .github/workflows/ci.yml. Builds and tests -# across an OS × Go matrix. SQLCipher's cgo build needs only a C +# across OSes and Go versions. SQLCipher's cgo build needs only a C # compiler and standard libs (no external OpenSSL — we use the # vendored libtomcrypt crypto backend). # -# Layout: Unix and Windows are separate jobs because Windows requires -# the MSYS2/MinGW toolchain (the Go-shipped gcc detection on Windows -# is brittle; MSYS2 is the upstream-recommended pattern, mirrored from -# mattn/go-sqlite3's own CI). +# Layout: one explicit job per OS rather than one matrix-on-OS job. +# GitHub Actions' run-page sidebar truncates per-matrix-instance names +# when the OS lives only in a matrix axis or include block; explicit +# top-level jobs each get their own sidebar entry with the full +# human-readable name. Pattern lifted from mattn/go-sqlite3's CI. name: build-test on: @@ -17,60 +18,103 @@ permissions: contents: read jobs: - unix: - name: ${{ matrix.target.platform }} / go ${{ matrix.go }} - runs-on: ${{ matrix.target.runner }} + linux-x86_64: + name: Linux x86_64 / go ${{ matrix.go }} + runs-on: ubuntu-latest timeout-minutes: 20 strategy: fail-fast: false matrix: - # Single object axis pattern: GitHub's left-sidebar label - # generator drops axes that come only from `include:`, but a - # top-level axis whose values are objects keeps the sidebar - # template fully resolvable. Each `target` row pairs the - # human-readable platform name with its GitHub-hosted runner - # label; the `name:` template above expands at job-start time - # and overrides the auto label in both the PR checks panel and - # the workflow run-page sidebar (community Discussions #9918, - # #49880). - target: - - platform: Linux-x86_64 - runner: ubuntu-latest - - platform: Linux-ARM64 - runner: ubuntu-24.04-arm - - platform: macOS-Apple-Silicon - runner: macos-latest go: [oldstable, stable] steps: - name: Harden Runner uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 with: egress-policy: audit - - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - name: Set up Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version: ${{ matrix.go }} - - name: Build env: CGO_ENABLED: "1" run: go build -trimpath ./... + - name: Vet + run: go vet ./... + - name: Test + env: + CGO_ENABLED: "1" + run: go test -race -count=1 ./... + linux-arm64: + name: Linux ARM64 / go ${{ matrix.go }} + runs-on: ubuntu-24.04-arm + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + go: [oldstable, stable] + steps: + - name: Harden Runner + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + with: + go-version: ${{ matrix.go }} + - name: Build + env: + CGO_ENABLED: "1" + run: go build -trimpath ./... - name: Vet run: go vet ./... + - name: Test + env: + CGO_ENABLED: "1" + run: go test -race -count=1 ./... + macos-apple-silicon: + name: macOS Apple Silicon / go ${{ matrix.go }} + runs-on: macos-latest + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + go: [oldstable, stable] + steps: + - name: Harden Runner + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 + with: + egress-policy: audit + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - name: Set up Go + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + with: + go-version: ${{ matrix.go }} + - name: Build + env: + CGO_ENABLED: "1" + run: go build -trimpath ./... + - name: Vet + run: go vet ./... - name: Test env: CGO_ENABLED: "1" run: go test -race -count=1 ./... - windows: + windows-x86_64: name: Windows x86_64 / go ${{ matrix.go }} runs-on: windows-latest timeout-minutes: 30 @@ -86,12 +130,10 @@ jobs: uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2 with: egress-policy: audit - - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - name: Set up MSYS2 + MinGW-w64 uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c # v2.31.1 with: @@ -99,20 +141,16 @@ jobs: update: true install: mingw-w64-x86_64-toolchain path-type: inherit - - name: Set up Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version: ${{ matrix.go }} - - name: Build env: CGO_ENABLED: "1" run: go build -trimpath ./... - - name: Vet run: go vet ./... - - name: Test env: CGO_ENABLED: "1" From 4e3f6429a3df91e0289376e4e2d80e7fb47d04f1 Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 23:33:49 -0700 Subject: [PATCH 7/8] ci(build-test): replace slash with em-dash in job names so OS shows in sidebar Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 5776da0..5824060 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -19,7 +19,7 @@ permissions: jobs: linux-x86_64: - name: Linux x86_64 / go ${{ matrix.go }} + name: Linux x86_64 — go ${{ matrix.go }} runs-on: ubuntu-latest timeout-minutes: 20 strategy: @@ -51,7 +51,7 @@ jobs: run: go test -race -count=1 ./... linux-arm64: - name: Linux ARM64 / go ${{ matrix.go }} + name: Linux ARM64 — go ${{ matrix.go }} runs-on: ubuntu-24.04-arm timeout-minutes: 20 strategy: @@ -83,7 +83,7 @@ jobs: run: go test -race -count=1 ./... macos-apple-silicon: - name: macOS Apple Silicon / go ${{ matrix.go }} + name: macOS Apple Silicon — go ${{ matrix.go }} runs-on: macos-latest timeout-minutes: 20 strategy: @@ -115,7 +115,7 @@ jobs: run: go test -race -count=1 ./... windows-x86_64: - name: Windows x86_64 / go ${{ matrix.go }} + name: Windows x86_64 — go ${{ matrix.go }} runs-on: windows-latest timeout-minutes: 30 defaults: From 87c544d09e290360890acf9a2d7fdbbc4531662e Mon Sep 17 00:00:00 2001 From: Alan Wiss Date: Fri, 1 May 2026 23:38:34 -0700 Subject: [PATCH 8/8] ci(build-test): use parenthesized format for Go version in job name Signed-off-by: Alan Wiss --- .github/workflows/build-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 5824060..31e2456 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -19,7 +19,7 @@ permissions: jobs: linux-x86_64: - name: Linux x86_64 — go ${{ matrix.go }} + name: Linux x86_64 (go ${{ matrix.go }}) runs-on: ubuntu-latest timeout-minutes: 20 strategy: @@ -51,7 +51,7 @@ jobs: run: go test -race -count=1 ./... linux-arm64: - name: Linux ARM64 — go ${{ matrix.go }} + name: Linux ARM64 (go ${{ matrix.go }}) runs-on: ubuntu-24.04-arm timeout-minutes: 20 strategy: @@ -83,7 +83,7 @@ jobs: run: go test -race -count=1 ./... macos-apple-silicon: - name: macOS Apple Silicon — go ${{ matrix.go }} + name: macOS Apple Silicon (go ${{ matrix.go }}) runs-on: macos-latest timeout-minutes: 20 strategy: @@ -115,7 +115,7 @@ jobs: run: go test -race -count=1 ./... windows-x86_64: - name: Windows x86_64 — go ${{ matrix.go }} + name: Windows x86_64 (go ${{ matrix.go }}) runs-on: windows-latest timeout-minutes: 30 defaults: