From b20f93d0de486a2d2f533430d03ef6ead9e34416 Mon Sep 17 00:00:00 2001 From: RNT56 Date: Sun, 12 Jul 2026 04:59:50 +0200 Subject: [PATCH] fix: stamp release binary versions Validate version tags, inject them into every release binary, and execute the native matrix asset in CI so a dev-identified binary cannot be published under a versioned release. --- .github/workflows/release.yml | 17 ++++++++++++++++- CHANGELOG.md | 2 ++ test/release-assets-e2e.sh | 26 ++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 35b3174..48e821f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,9 +30,24 @@ jobs: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} CGO_ENABLED: "0" + RELEASE_VERSION: ${{ github.ref_type == 'tag' && github.ref_name || 'dev' }} run: | out="nilcore-${GOOS}-${GOARCH}" - go build -trimpath -ldflags "-s -w" -o "dist/${out}" ./cmd/nilcore + ldflags="-s -w" + if [[ "${RELEASE_VERSION}" != "dev" ]]; then + if [[ ! "${RELEASE_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+([.-][0-9A-Za-z]+)*)?$ ]]; then + echo "refusing invalid release version: ${RELEASE_VERSION}" >&2 + exit 1 + fi + ldflags="${ldflags} -X main.version=${RELEASE_VERSION}" + fi + go build -trimpath -ldflags "${ldflags}" -o "dist/${out}" ./cmd/nilcore + # The Linux amd64 matrix leg is runnable on the hosted builder. Prove the + # release tag reached the binary, rather than publishing a `dev ()` + # build whose filename and release page claim a different version. + if [[ "${RELEASE_VERSION}" != "dev" && "${GOOS}/${GOARCH}" == "linux/amd64" ]]; then + test "$("dist/${out}" version)" = "nilcore ${RELEASE_VERSION}" + fi # Publish a per-binary SHA-256 so the curl|sh installer can verify integrity # before running the downloaded binary. The file holds " " so a # consumer can `sha256sum -c` it directly. diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f0af5..2df5741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ On a release, the maintainer moves the accumulated `[Unreleased]` entries into a ## [Unreleased] +- **release-version-stamp** — Stamp validated version tags into every release binary, execute the native matrix asset to prove `nilcore version` matches the tag, and refuse malformed release refs before publication; the release E2E now verifies identity as well as checksums and completeness. _Owns:_ `.github/workflows/release.yml`, `test/release-assets-e2e.sh`, `CHANGELOG.md`. _(release hardening)_ + - **P15-completion-docs** — Reconcile the canonical task, provider-roadmap, and architecture docs after P15-T13: Phase 15 is complete, the hermetic golden eval is shipped, and the documented I7 boundary now matches the implemented native drop-on-decode plus client-side untrusted-data fence. _Owns:_ `docs/{TASKS,ROADMAP-PROVIDERS,ARCHITECTURE}.md`, `CHANGELOG.md`. _(Phase 15 documentation)_ - **P15-T13** — Add a hermetic, golden-transcript provider compatibility evaluation covering custom OpenAI-compatible endpoints, reasoning token caps, strict JSON Schema output, OpenRouter routing/extras/attribution, native search rendering and drop-on-decode containment, plus injection-flagged and untrusted-data-fenced client search fallback. _Owns:_ `eval/provider-compat/`, `CHANGELOG.md`. _(Phase 15)_ diff --git a/test/release-assets-e2e.sh b/test/release-assets-e2e.sh index 8b54f54..6967fb0 100755 --- a/test/release-assets-e2e.sh +++ b/test/release-assets-e2e.sh @@ -8,13 +8,19 @@ tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT dist="$tmp/dist" mkdir -p "$dist" +release_version="${NILCORE_RELEASE_VERSION:-v0.0.0-e2e}" +if [[ ! "$release_version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+([.-][0-9A-Za-z]+)*)?$ ]]; then + echo "invalid test release version: $release_version" >&2 + exit 1 +fi +ldflags="-s -w -X main.version=${release_version}" for os in darwin linux; do for arch in amd64 arm64; do asset="nilcore-${os}-${arch}" ( cd "$repo_root" - CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -trimpath -ldflags "-s -w" -o "$dist/$asset" ./cmd/nilcore + CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -trimpath -ldflags "$ldflags" -o "$dist/$asset" ./cmd/nilcore ) if command -v sha256sum >/dev/null 2>&1; then ( cd "$dist" && sha256sum "$asset" > "$asset.sha256" ) @@ -24,6 +30,22 @@ for os in darwin linux; do done done +# Run the native member of the release matrix and pin the operator-visible version. +# The supported matrix contains the CI runner and both supported developer hosts; +# fail explicitly on an unsupported host instead of silently skipping the proof. +host_os="$(go env GOOS)" +host_arch="$(go env GOARCH)" +host_asset="$dist/nilcore-${host_os}-${host_arch}" +if [[ ! -x "$host_asset" ]]; then + echo "release version E2E has no runnable matrix asset for ${host_os}/${host_arch}" >&2 + exit 1 +fi +actual_version="$("$host_asset" version)" +if [[ "$actual_version" != "nilcore ${release_version}" ]]; then + echo "release binary version mismatch: got '$actual_version', want 'nilcore ${release_version}'" >&2 + exit 1 +fi + "$repo_root/scripts/verify-release-assets.sh" "$dist" test "$(wc -l < "$dist/SHA256SUMS" | tr -d ' ')" = "4" @@ -34,4 +56,4 @@ if "$repo_root/scripts/verify-release-assets.sh" "$dist" >"$tmp/missing.out" 2>& fi grep -q "missing checksum nilcore-linux-arm64.sha256" "$tmp/missing.out" -echo "release assets E2E: four targets verified; partial release refused" +echo "release assets E2E: version stamped; four targets verified; partial release refused"