zeroclaw/.github/workflows/release.yml
Alex Gorevski 5c464b0243
ci(release): add hard binary size gate (#631)
Problem: The release workflow warns when binaries exceed 5MB but does
not block the build. Since small binary size is a stated project goal
(release profile uses opt-level="z", LTO, strip, panic=abort), size
regressions can silently ship to users without any enforcement.

Solution: Convert the binary size check to a tiered gate:
- >5MB: emits a GitHub Actions warning (soft target, informational)
- >15MB: emits a GitHub Actions error and fails the build (hard limit)
- Adds a step summary with per-target binary size metrics for
  visibility in the Actions UI.

The 15MB hard limit provides headroom for legitimate growth while
catching catastrophic regressions (e.g., debug symbols not stripped,
accidental fat dependency additions).

Testing: Validated YAML syntax. The shell script logic is
straightforward (stat + arithmetic comparison). The existing

unner.os != 'Windows' guard is preserved.

Ref: zeroclaw-labs/zeroclaw#618 (item 3 — Binary Size Gating)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-02-17 15:09:14 -05:00

130 lines
4.8 KiB
YAML

name: Release
on:
push:
tags: ["v*"]
concurrency:
group: release
cancel-in-progress: false
permissions:
contents: write
id-token: write # Required for cosign keyless signing via OIDC
env:
CARGO_TERM_COLOR: always
jobs:
build-release:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: zeroclaw
- os: macos-latest
target: x86_64-apple-darwin
artifact: zeroclaw
- os: macos-latest
target: aarch64-apple-darwin
artifact: zeroclaw
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: zeroclaw.exe
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
- name: Build release
run: cargo build --release --locked --target ${{ matrix.target }}
- name: Check binary size (Unix)
if: runner.os != 'Windows'
run: |
SIZE=$(stat -f%z target/${{ matrix.target }}/release/${{ matrix.artifact }} 2>/dev/null || stat -c%s target/${{ matrix.target }}/release/${{ matrix.artifact }})
SIZE_MB=$((SIZE / 1024 / 1024))
echo "Binary size: ${SIZE_MB}MB ($SIZE bytes)"
echo "### Binary Size: ${{ matrix.target }}" >> "$GITHUB_STEP_SUMMARY"
echo "- Size: ${SIZE_MB}MB ($SIZE bytes)" >> "$GITHUB_STEP_SUMMARY"
if [ "$SIZE" -gt 15728640 ]; then
echo "::error::Binary exceeds 15MB hard limit (${SIZE_MB}MB)"
exit 1
elif [ "$SIZE" -gt 5242880 ]; then
echo "::warning::Binary exceeds 5MB target (${SIZE_MB}MB)"
else
echo "Binary size within target."
fi
- name: Package (Unix)
if: runner.os != 'Windows'
run: |
cd target/${{ matrix.target }}/release
tar czf ../../../zeroclaw-${{ matrix.target }}.tar.gz ${{ matrix.artifact }}
- name: Package (Windows)
if: runner.os == 'Windows'
run: |
cd target/${{ matrix.target }}/release
7z a ../../../zeroclaw-${{ matrix.target }}.zip ${{ matrix.artifact }}
- name: Upload artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: zeroclaw-${{ matrix.target }}
path: zeroclaw-${{ matrix.target }}.*
retention-days: 7
publish:
name: Publish Release
needs: build-release
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 15
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Download all artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
path: artifacts
- name: Generate SHA256 checksums
run: |
cd artifacts
find . -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec sha256sum {} + | sed 's| \./[^/]*/| |' > SHA256SUMS
echo "Generated checksums:"
cat SHA256SUMS
- name: Install cosign
uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2
- name: Sign artifacts with cosign (keyless)
run: |
for file in artifacts/**/*; do
[ -f "$file" ] || continue
cosign sign-blob --yes \
--oidc-issuer=https://token.actions.githubusercontent.com \
--output-signature="${file}.sig" \
--output-certificate="${file}.pem" \
"$file"
done
- name: Create GitHub Release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
with:
generate_release_notes: true
files: |
artifacts/**/*
artifacts/SHA256SUMS
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}