SMOL 4. Binsuite #719
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: SMOL 4. Binsuite | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: 'Dry run (build only, no release)' | |
| type: boolean | |
| default: true | |
| force: | |
| description: 'Force rebuild (ignore cache)' | |
| type: boolean | |
| default: false | |
| build_mode: | |
| description: 'Build mode' | |
| type: choice | |
| options: | |
| - prod | |
| - dev | |
| default: prod | |
| tools: | |
| description: 'Tools to build (comma-separated: binpress,binflate,binject or "all")' | |
| type: string | |
| default: 'all' | |
| debug: | |
| description: 'Debug (0|1|namespace[,...])' | |
| required: false | |
| default: '0' | |
| type: string | |
| workflow_call: | |
| inputs: | |
| dry_run: | |
| type: boolean | |
| default: true | |
| force: | |
| type: boolean | |
| default: false | |
| build_mode: | |
| type: string | |
| default: prod | |
| tools: | |
| type: string | |
| default: 'all' | |
| debug: | |
| type: string | |
| default: '0' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| # Job group 1: binpress | |
| binpress: | |
| permissions: | |
| contents: read | |
| id-token: write # OIDC authentication for Depot builds | |
| name: binpress / ${{ matrix.platform == 'win32' && 'win' || matrix.platform }}-${{ matrix.arch }}${{ matrix.libc == 'musl' && '-musl' || '' }} | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| if: inputs.tools == 'all' || contains(inputs.tools, 'binpress') | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # macOS builds | |
| # Use Depot runner for both darwin architectures: 8 vCPU M2, 24GB RAM | |
| # Cross-compile x64 from ARM64 since Depot only offers ARM64 macOS | |
| - runner: depot-macos-15 | |
| platform: darwin | |
| arch: arm64 | |
| os: macos | |
| - runner: depot-macos-15 | |
| platform: darwin | |
| arch: x64 | |
| os: macos | |
| cross_compile: true | |
| # Linux glibc builds | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| os: linux | |
| libc: glibc | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| os: linux | |
| libc: glibc | |
| # Linux musl builds (Alpine) | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| os: linux | |
| libc: musl | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| os: linux | |
| libc: musl | |
| # Windows builds | |
| - runner: windows-2022 | |
| platform: win32 | |
| arch: x64 | |
| os: windows | |
| # Windows ARM64: Cross-compile on x64 runner (no ARM64 hosted runners available) | |
| - runner: windows-2022 | |
| platform: win32 | |
| arch: arm64 | |
| os: windows | |
| cross_compile: true | |
| steps: | |
| - uses: SocketDev/socket-registry/.github/actions/setup-and-install@ea1986b8019fedee5fb38b485690b13ad8e0217f # main | |
| - name: Check if tool should be built | |
| id: build-enabled | |
| shell: bash | |
| env: | |
| TOOLS_INPUT: ${{ inputs.tools || 'all' }} | |
| run: | | |
| TOOL="binpress" | |
| if [ "$TOOLS_INPUT" = "all" ]; then | |
| echo "build=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Building $TOOL (all tools selected)" | |
| elif echo ",$TOOLS_INPUT," | grep -q ",$TOOL,"; then | |
| echo "build=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Building $TOOL (explicitly selected)" | |
| else | |
| echo "build=false" >> $GITHUB_OUTPUT | |
| echo "⏭ Skipping $TOOL (not selected)" | |
| fi | |
| - name: Setup checkpoint caching | |
| if: steps.build-enabled.outputs.build == 'true' | |
| id: setup-checkpoints | |
| uses: ./.github/actions/setup-checkpoints | |
| with: | |
| package-name: binpress | |
| build-mode: ${{ inputs.build_mode || 'prod' }} | |
| platform: ${{ matrix.platform }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc || '' }} | |
| # Only create a signing keychain / install Depot CLI when a build is | |
| # actually about to run. On cache-hit rounds the tarball already | |
| # contains the signed binary, so spinning up an ephemeral keychain | |
| # or fetching the Depot CLI just burns CI time. | |
| - name: Setup macOS code signing | |
| if: matrix.os == 'macos' && steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/setup-macos-keychain | |
| - name: Setup Depot CLI | |
| if: matrix.os == 'linux' && steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.7.1 | |
| with: | |
| oidc: true | |
| - name: Set platform-arch (binpress) | |
| id: platform-arch | |
| uses: ./.github/actions/set-platform-arch | |
| with: | |
| platform: ${{ matrix.platform }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc }} | |
| - name: Validate checkpoint binary exists | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'false' | |
| id: validate-checkpoint | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # All platforms (Linux Depot / macOS / Windows native) export to | |
| # build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/. A prior version | |
| # of this step had a separate Linux branch without PLATFORM_ARCH | |
| # based on a misread of the Dockerfile — the binary would never | |
| # be found on Linux cache-hit and force-rebuild kept firing, | |
| # defeating the entire checkpoint cache for this matrix. | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress" | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="${BINARY}.exe" | |
| fi | |
| if [ ! -f "$BINARY" ]; then | |
| echo "⚠️ Checkpoint restored but binary missing at: $BINARY" | |
| echo "force-rebuild=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "✅ Binary exists: $BINARY" | |
| echo "force-rebuild=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Setup build environment | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/setup-build-env | |
| with: | |
| os: ${{ matrix.os }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc || '' }} | |
| cross-compile: ${{ matrix.cross_compile || 'false' }} | |
| - name: Debug build decision | |
| if: steps.build-enabled.outputs.build == 'true' | |
| shell: bash | |
| env: | |
| BUILD_REQUIRED: ${{ steps.setup-checkpoints.outputs.build-required }} | |
| CACHE_HIT: ${{ steps.setup-checkpoints.outputs.cache-hit }} | |
| run: | | |
| if [ "${BUILD_REQUIRED}" = "true" ]; then | |
| echo "✅ Build will run (cache-hit: ${CACHE_HIT})" | |
| else | |
| echo "⏭️ Skipping build (checkpoint restored)" | |
| fi | |
| - name: Load cache version (binpress) | |
| id: cache-version | |
| shell: bash | |
| run: | | |
| # jq -r emits the literal string "null" on missing key with | |
| # exit 0 — without a guard, that string would silently poison | |
| # downstream Depot build-args (LIEF_CACHE_VERSION=null) and | |
| # collide every matrix arm + every branch into one shared | |
| # stale cache entry. Fail fast instead. | |
| load_version() { | |
| local key="$1" | |
| local val | |
| val=$(jq -r ".versions[\"$key\"]" .github/cache-versions.json) | |
| if [ -z "$val" ] || [ "$val" = "null" ]; then | |
| echo "error: cache-versions.json missing key: $key" >&2 | |
| exit 1 | |
| fi | |
| echo "$val" | |
| } | |
| echo "version=$(load_version binpress)" >> $GITHUB_OUTPUT | |
| echo "lief_version=$(load_version lief)" >> $GITHUB_OUTPUT | |
| echo "stubs_version=$(load_version stubs)" >> $GITHUB_OUTPUT | |
| - name: Initialize submodules before Docker build (Linux) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| uses: ./.github/actions/init-submodules | |
| with: | |
| # binpress links zstd (via bin-infra/make/zstd.mk) but does | |
| # NOT use libdeflate — that's binject-only. Previously inited | |
| # both, wasting ~10-30s of CI time per Linux matrix entry. | |
| submodules: packages/bin-infra/upstream/zstd | |
| - name: Clean LIEF before Docker build (Linux) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| run: rm -rf packages/lief-builder/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/lief/ | |
| - name: Stage registry tool-checksums for Docker build context | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| run: | | |
| # Socket-registry's setup action exports SOCKET_TOOL_CHECKSUMS_FILE | |
| # pointing at a stable on-runner copy of external-tools.json. | |
| # Dockerfiles `COPY .build-context/registry-tools.json …` to | |
| # resolve pnpm version + per-platform asset + sha256 at build | |
| # time without duplicating per-Dockerfile constants. | |
| mkdir -p .build-context | |
| cp "$SOCKET_TOOL_CHECKSUMS_FILE" .build-context/registry-tools.json | |
| - name: Build binpress with Depot (Linux - offloads compute) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.17.0 | |
| with: | |
| project: 8fpj9495vw | |
| platforms: linux/${{ matrix.arch == 'x64' && 'amd64' || matrix.arch }} | |
| build-args: | | |
| BUILD_MODE=${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH=${{ steps.platform-arch.outputs.platform_arch }} | |
| CACHE_VERSION=${{ steps.cache-version.outputs.version }} | |
| LIEF_CACHE_VERSION=${{ steps.cache-version.outputs.lief_version }} | |
| STUBS_CACHE_VERSION=${{ steps.cache-version.outputs.stubs_version }} | |
| # GH_TOKEN via BuildKit secret, not build-args. Passing it as | |
| # ARG+ENV bakes the token into image-layer metadata visible | |
| # through `docker history` and persisted across Depot cache | |
| # tenants. | |
| secrets: | | |
| gh_token=${{ github.token }} | |
| no-cache: ${{ inputs.force == true }} | |
| file: packages/binpress/docker/Dockerfile.${{ matrix.libc == 'musl' && 'musl' || 'glibc' }} | |
| target: export | |
| outputs: type=local,dest=.docker-export | |
| context: . | |
| - name: Move Docker export to correct locations (binpress) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| run: | | |
| mv .docker-export/binpress-build packages/binpress/build | |
| mkdir -p packages/lief-builder/build | |
| mv .docker-export/lief-builder-downloaded packages/lief-builder/build/downloaded | |
| rm -rf .docker-export | |
| - name: Verify Depot build output (binpress) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| run: | | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress" | |
| [ -f "$BINARY" ] || { echo "× Binary not found: $BINARY"; exit 1; } | |
| echo "✅ $(file "$BINARY")" | |
| - name: Validate Depot checkpoints (binpress) | |
| if: | | |
| matrix.os == 'linux' && | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/validate-depot-checkpoints | |
| with: | |
| package-path: packages/binpress | |
| build-mode: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| package-name: binpress | |
| platform-arch: ${{ steps.platform-arch.outputs.platform_arch }} | |
| - name: Build binpress native (macOS/Windows) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| (steps.setup-checkpoints.outputs.build-required == 'true' || steps.validate-checkpoint.outputs.force-rebuild == 'true') && | |
| matrix.os != 'linux' | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| GH_TOKEN: ${{ github.token }} | |
| PLATFORM: ${{ matrix.platform }} | |
| ARCH: ${{ matrix.arch }} | |
| TARGET_ARCH: ${{ matrix.arch }} | |
| DEBUG: ${{ inputs.debug != '0' && inputs.debug || '' }} | |
| run: | | |
| echo "🔨 Building binpress for ${PLATFORM}-${ARCH} (${BUILD_MODE} mode)" | |
| # Use build script with --force to bypass checkpoint check | |
| # (checkpoint restoration is handled by setup-checkpoints action) | |
| pnpm run build -- --force | |
| echo "✅ Build complete" | |
| # Construct PLATFORM_ARCH for build output path. | |
| if [ "${PLATFORM}" = "win32" ]; then | |
| RELEASE_PLATFORM="win" | |
| else | |
| RELEASE_PLATFORM="${PLATFORM}" | |
| fi | |
| PLATFORM_ARCH="${RELEASE_PLATFORM}-${ARCH}" | |
| ls -lh build/${BUILD_MODE}/${PLATFORM_ARCH}/out/ | |
| - name: Verify binary | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'false' | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # All platforms (Linux Depot / macOS / Windows native) export to | |
| # build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/. Matches the | |
| # validate-checkpoint step above. | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress" | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="${BINARY}.exe" | |
| fi | |
| if [ ! -f "$BINARY" ]; then | |
| echo "× Binary not found: $BINARY" | |
| exit 1 | |
| fi | |
| echo "✅ Binary exists: $BINARY" | |
| # Show binary info | |
| if [ "${OS_TYPE}" = "macos" ]; then | |
| file "$BINARY" | |
| otool -L "$BINARY" || true | |
| elif [ "${OS_TYPE}" = "linux" ]; then | |
| file "$BINARY" | |
| ldd "$BINARY" || true | |
| elif [ "${OS_TYPE}" = "windows" ]; then | |
| file "$BINARY" || true | |
| fi | |
| - name: Debug compression test | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' && matrix.arch == 'x64' && matrix.libc != 'musl' && runner.os == 'Windows' | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| run: | | |
| # Run debug compression test to diagnose issues | |
| echo "Running debug compression test..." | |
| bash test/debug-compress.sh || true | |
| - name: Test binary (functional test) | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' && matrix.arch == 'x64' && matrix.libc != 'musl' && matrix.os != 'linux' | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TARGET_ARCH: ${{ matrix.arch }} | |
| run: | | |
| # Run full functional tests on native x64 platforms (non-Linux). | |
| # Linux glibc tests run inside Docker to avoid LTO bytecode incompatibility. | |
| echo "Running functional tests for binpress..." | |
| pnpm run test | |
| - name: Smoke test binary | |
| if: steps.build-enabled.outputs.build == 'true' | |
| shell: bash | |
| working-directory: packages/binpress | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| ARCH: ${{ matrix.arch }} | |
| LIBC: ${{ matrix.libc }} | |
| run: | | |
| # Deterministic smoke test: native execution, Docker, QEMU, or static verification | |
| # All platforms now use PLATFORM_ARCH in build output path. | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress.exe" | |
| else | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress" | |
| fi | |
| # Prepare smoke test options | |
| SMOKE_TEST_ARGS="$BINARY" | |
| if [ "${ARCH}" = "arm64" ]; then | |
| SMOKE_TEST_ARGS="$SMOKE_TEST_ARGS --arch arm64" | |
| fi | |
| if [ "${LIBC}" = "musl" ]; then | |
| SMOKE_TEST_ARGS="$SMOKE_TEST_ARGS --musl" | |
| fi | |
| echo "Running smoke test: node ../../packages/build-infra/scripts/smoke-test-binary.mts $SMOKE_TEST_ARGS" | |
| node ../../packages/build-infra/scripts/smoke-test-binary.mts $SMOKE_TEST_ARGS | |
| - name: Set artifact name and path | |
| shell: bash | |
| env: | |
| PLATFORM: ${{ matrix.platform }} | |
| ARCH: ${{ matrix.arch }} | |
| LIBC: ${{ matrix.libc }} | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # Use platform-arch output (win32→win conversion already done). | |
| ARTIFACT_NAME="binpress-${PLATFORM_ARCH}" | |
| echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV | |
| # Construct binary path. | |
| # All platforms now use PLATFORM_ARCH in build output path. | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY_PATH="packages/binpress/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress.exe" | |
| else | |
| BINARY_PATH="packages/binpress/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binpress" | |
| fi | |
| echo "BINARY_PATH=${BINARY_PATH}" >> $GITHUB_ENV | |
| - name: Upload artifacts | |
| if: steps.build-enabled.outputs.build == 'true' | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.BINARY_PATH }} | |
| retention-days: 30 | |
| if-no-files-found: error | |
| compression-level: 0 # Already-compressed binary artifact | |
| # Job group 2: binflate | |
| binflate: | |
| permissions: | |
| contents: read | |
| id-token: write # OIDC authentication for Depot builds | |
| name: binflate / ${{ matrix.platform == 'win32' && 'win' || matrix.platform }}-${{ matrix.arch }}${{ matrix.libc == 'musl' && '-musl' || '' }} | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| if: inputs.tools == 'all' || contains(inputs.tools, 'binflate') | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # macOS builds | |
| # Use Depot runner for both darwin architectures: 8 vCPU M2, 24GB RAM | |
| # Cross-compile x64 from ARM64 since Depot only offers ARM64 macOS | |
| - runner: depot-macos-15 | |
| platform: darwin | |
| arch: arm64 | |
| os: macos | |
| - runner: depot-macos-15 | |
| platform: darwin | |
| arch: x64 | |
| os: macos | |
| cross_compile: true | |
| # Linux glibc builds | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| os: linux | |
| libc: glibc | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| os: linux | |
| libc: glibc | |
| # Linux musl builds (Alpine) | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| os: linux | |
| libc: musl | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| os: linux | |
| libc: musl | |
| # Windows builds | |
| - runner: windows-2022 | |
| platform: win32 | |
| arch: x64 | |
| os: windows | |
| # Windows ARM64: Cross-compile on x64 runner (no ARM64 hosted runners available) | |
| - runner: windows-2022 | |
| platform: win32 | |
| arch: arm64 | |
| os: windows | |
| cross_compile: true | |
| steps: | |
| - uses: SocketDev/socket-registry/.github/actions/setup-and-install@ea1986b8019fedee5fb38b485690b13ad8e0217f # main | |
| - name: Check if tool should be built | |
| id: build-enabled | |
| shell: bash | |
| env: | |
| TOOLS_INPUT: ${{ inputs.tools || 'all' }} | |
| run: | | |
| TOOL="binflate" | |
| if [ "$TOOLS_INPUT" = "all" ]; then | |
| echo "build=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Building $TOOL (all tools selected)" | |
| elif echo ",$TOOLS_INPUT," | grep -q ",$TOOL,"; then | |
| echo "build=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Building $TOOL (explicitly selected)" | |
| else | |
| echo "build=false" >> $GITHUB_OUTPUT | |
| echo "⏭ Skipping $TOOL (not selected)" | |
| fi | |
| - name: Setup checkpoint caching | |
| if: steps.build-enabled.outputs.build == 'true' | |
| id: setup-checkpoints | |
| uses: ./.github/actions/setup-checkpoints | |
| with: | |
| package-name: binflate | |
| build-mode: ${{ inputs.build_mode || 'prod' }} | |
| platform: ${{ matrix.platform }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc || '' }} | |
| # Only create a signing keychain / install Depot CLI when a build is | |
| # actually about to run. On cache-hit rounds the tarball already | |
| # contains the signed binary, so spinning up an ephemeral keychain | |
| # or fetching the Depot CLI just burns CI time. | |
| - name: Setup macOS code signing | |
| if: matrix.os == 'macos' && steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/setup-macos-keychain | |
| - name: Setup Depot CLI | |
| if: matrix.os == 'linux' && steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.7.1 | |
| with: | |
| oidc: true | |
| - name: Set platform-arch (binflate) | |
| id: platform-arch | |
| uses: ./.github/actions/set-platform-arch | |
| with: | |
| platform: ${{ matrix.platform }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc }} | |
| - name: Validate checkpoint binary exists | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'false' | |
| id: validate-checkpoint | |
| shell: bash | |
| working-directory: packages/binflate | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # All platforms (Linux Depot / macOS / Windows native) export to | |
| # build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/. A prior version | |
| # of this step had a separate Linux branch without PLATFORM_ARCH | |
| # based on a misread of the Dockerfile — the binary would never | |
| # be found on Linux cache-hit and force-rebuild kept firing, | |
| # defeating the entire checkpoint cache for this matrix. | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate" | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="${BINARY}.exe" | |
| fi | |
| if [ ! -f "$BINARY" ]; then | |
| echo "⚠️ Checkpoint restored but binary missing at: $BINARY" | |
| echo "force-rebuild=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "✅ Binary exists: $BINARY" | |
| echo "force-rebuild=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Setup build environment | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/setup-build-env | |
| with: | |
| os: ${{ matrix.os }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc || '' }} | |
| cross-compile: ${{ matrix.cross_compile || 'false' }} | |
| - name: Debug build decision | |
| if: steps.build-enabled.outputs.build == 'true' | |
| shell: bash | |
| env: | |
| BUILD_REQUIRED: ${{ steps.setup-checkpoints.outputs.build-required }} | |
| CACHE_HIT: ${{ steps.setup-checkpoints.outputs.cache-hit }} | |
| run: | | |
| if [ "${BUILD_REQUIRED}" = "true" ]; then | |
| echo "✅ Build will run (cache-hit: ${CACHE_HIT})" | |
| else | |
| echo "⏭️ Skipping build (checkpoint restored)" | |
| fi | |
| - name: Load cache version (binflate) | |
| id: cache-version | |
| shell: bash | |
| run: | | |
| load_version() { | |
| local key="$1" | |
| local val | |
| val=$(jq -r ".versions[\"$key\"]" .github/cache-versions.json) | |
| if [ -z "$val" ] || [ "$val" = "null" ]; then | |
| echo "error: cache-versions.json missing key: $key" >&2 | |
| exit 1 | |
| fi | |
| echo "$val" | |
| } | |
| echo "version=$(load_version binflate)" >> $GITHUB_OUTPUT | |
| echo "lief_version=$(load_version lief)" >> $GITHUB_OUTPUT | |
| echo "stubs_version=$(load_version stubs)" >> $GITHUB_OUTPUT | |
| - name: Initialize submodules before Docker build (Linux) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| uses: ./.github/actions/init-submodules | |
| with: | |
| # binflate links zstd only — libdeflate is binject-only. | |
| # Previously inited both, wasting ~10-30s per Linux matrix | |
| # entry on an unused clone. | |
| submodules: packages/bin-infra/upstream/zstd | |
| - name: Stage registry tool-checksums for Docker build context | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| run: | | |
| # Socket-registry's setup action exports SOCKET_TOOL_CHECKSUMS_FILE | |
| # pointing at a stable on-runner copy of external-tools.json. | |
| # Dockerfiles `COPY .build-context/registry-tools.json …` to | |
| # resolve pnpm version + per-platform asset + sha256 at build | |
| # time without duplicating per-Dockerfile constants. | |
| mkdir -p .build-context | |
| cp "$SOCKET_TOOL_CHECKSUMS_FILE" .build-context/registry-tools.json | |
| - name: Build binflate with Depot (Linux - offloads compute) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.17.0 | |
| with: | |
| project: 8fpj9495vw | |
| platforms: linux/${{ matrix.arch == 'x64' && 'amd64' || matrix.arch }} | |
| build-args: | | |
| BUILD_MODE=${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH=${{ steps.platform-arch.outputs.platform_arch }} | |
| CACHE_VERSION=${{ steps.cache-version.outputs.version }} | |
| LIEF_CACHE_VERSION=${{ steps.cache-version.outputs.lief_version }} | |
| STUBS_CACHE_VERSION=${{ steps.cache-version.outputs.stubs_version }} | |
| no-cache: ${{ inputs.force == true }} | |
| file: packages/binflate/docker/Dockerfile.${{ matrix.libc == 'musl' && 'musl' || 'glibc' }} | |
| target: export | |
| outputs: type=local,dest=packages/binflate/build | |
| context: . | |
| - name: Verify Depot build output (binflate) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| working-directory: packages/binflate | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| run: | | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate" | |
| [ -f "$BINARY" ] || { echo "× Binary not found: $BINARY"; exit 1; } | |
| echo "✅ $(file "$BINARY")" | |
| - name: Validate Depot checkpoints (binflate) | |
| if: | | |
| matrix.os == 'linux' && | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/validate-depot-checkpoints | |
| with: | |
| package-path: packages/binflate | |
| build-mode: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| package-name: binflate | |
| platform-arch: ${{ steps.platform-arch.outputs.platform_arch }} | |
| - name: Build binflate native (macOS/Windows) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| (steps.setup-checkpoints.outputs.build-required == 'true' || steps.validate-checkpoint.outputs.force-rebuild == 'true') && | |
| matrix.os != 'linux' | |
| shell: bash | |
| working-directory: packages/binflate | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| GH_TOKEN: ${{ github.token }} | |
| PLATFORM: ${{ matrix.platform }} | |
| ARCH: ${{ matrix.arch }} | |
| TARGET_ARCH: ${{ matrix.arch }} | |
| DEBUG: ${{ inputs.debug != '0' && inputs.debug || '' }} | |
| run: | | |
| echo "🔨 Building binflate for ${PLATFORM}-${ARCH} (${BUILD_MODE} mode)" | |
| # Use build script with --force to bypass checkpoint check | |
| # (checkpoint restoration is handled by setup-checkpoints action) | |
| pnpm run build -- --force | |
| echo "✅ Build complete" | |
| # Construct PLATFORM_ARCH for build output path. | |
| if [ "${PLATFORM}" = "win32" ]; then | |
| RELEASE_PLATFORM="win" | |
| else | |
| RELEASE_PLATFORM="${PLATFORM}" | |
| fi | |
| PLATFORM_ARCH="${RELEASE_PLATFORM}-${ARCH}" | |
| ls -lh build/${BUILD_MODE}/${PLATFORM_ARCH}/out/ | |
| - name: Verify binary | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'false' | |
| shell: bash | |
| working-directory: packages/binflate | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # All platforms (Linux Depot / macOS / Windows native) export to | |
| # build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/. Matches the | |
| # validate-checkpoint step above. | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate" | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="${BINARY}.exe" | |
| fi | |
| if [ ! -f "$BINARY" ]; then | |
| echo "× Binary not found: $BINARY" | |
| exit 1 | |
| fi | |
| echo "✅ Binary exists: $BINARY" | |
| # Show binary info | |
| if [ "${OS_TYPE}" = "macos" ]; then | |
| file "$BINARY" | |
| otool -L "$BINARY" || true | |
| elif [ "${OS_TYPE}" = "linux" ]; then | |
| file "$BINARY" | |
| ldd "$BINARY" || true | |
| elif [ "${OS_TYPE}" = "windows" ]; then | |
| file "$BINARY" || true | |
| fi | |
| - name: Test binary (functional test) | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' && matrix.arch == 'x64' && matrix.libc != 'musl' && matrix.os != 'linux' | |
| shell: bash | |
| working-directory: packages/binflate | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Run full functional tests on native x64 platforms (non-Linux). | |
| # Linux glibc tests run inside Docker to avoid LTO bytecode incompatibility. | |
| echo "Running functional tests for binflate..." | |
| pnpm run test | |
| - name: Smoke test binary | |
| if: steps.build-enabled.outputs.build == 'true' | |
| shell: bash | |
| working-directory: packages/binflate | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| ARCH: ${{ matrix.arch }} | |
| LIBC: ${{ matrix.libc }} | |
| run: | | |
| # Deterministic smoke test: native execution, Docker, QEMU, or static verification | |
| # All platforms now use PLATFORM_ARCH in build output path. | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate.exe" | |
| else | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate" | |
| fi | |
| # Prepare smoke test options | |
| SMOKE_TEST_ARGS="$BINARY" | |
| if [ "${ARCH}" = "arm64" ]; then | |
| SMOKE_TEST_ARGS="$SMOKE_TEST_ARGS --arch arm64" | |
| fi | |
| if [ "${LIBC}" = "musl" ]; then | |
| SMOKE_TEST_ARGS="$SMOKE_TEST_ARGS --musl" | |
| fi | |
| echo "Running smoke test: node ../../packages/build-infra/scripts/smoke-test-binary.mts $SMOKE_TEST_ARGS" | |
| node ../../packages/build-infra/scripts/smoke-test-binary.mts $SMOKE_TEST_ARGS | |
| - name: Set artifact name and path | |
| shell: bash | |
| env: | |
| PLATFORM: ${{ matrix.platform }} | |
| ARCH: ${{ matrix.arch }} | |
| LIBC: ${{ matrix.libc }} | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # Use platform-arch output (win32→win conversion already done). | |
| ARTIFACT_NAME="binflate-${PLATFORM_ARCH}" | |
| echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV | |
| # Construct binary path. | |
| # All platforms now use PLATFORM_ARCH in build output path. | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY_PATH="packages/binflate/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate.exe" | |
| else | |
| BINARY_PATH="packages/binflate/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binflate" | |
| fi | |
| echo "BINARY_PATH=${BINARY_PATH}" >> $GITHUB_ENV | |
| - name: Upload artifacts | |
| if: steps.build-enabled.outputs.build == 'true' | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.BINARY_PATH }} | |
| retention-days: 30 | |
| if-no-files-found: error | |
| compression-level: 0 # Already-compressed binary artifact | |
| # Job group 3: binject | |
| binject: | |
| permissions: | |
| contents: read | |
| id-token: write # OIDC authentication for Depot builds | |
| name: binject / ${{ matrix.platform == 'win32' && 'win' || matrix.platform }}-${{ matrix.arch }}${{ matrix.libc == 'musl' && '-musl' || '' }} | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| if: inputs.tools == 'all' || contains(inputs.tools, 'binject') | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # macOS builds | |
| # Use Depot runner for both darwin architectures: 8 vCPU M2, 24GB RAM | |
| # Cross-compile x64 from ARM64 since Depot only offers ARM64 macOS | |
| - runner: depot-macos-15 | |
| platform: darwin | |
| arch: arm64 | |
| os: macos | |
| - runner: depot-macos-15 | |
| platform: darwin | |
| arch: x64 | |
| os: macos | |
| cross_compile: true | |
| # Linux glibc builds | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| os: linux | |
| libc: glibc | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| os: linux | |
| libc: glibc | |
| # Linux musl builds (Alpine) | |
| - runner: ubuntu-24.04 | |
| platform: linux | |
| arch: x64 | |
| os: linux | |
| libc: musl | |
| - runner: ubuntu-24.04-arm | |
| platform: linux | |
| arch: arm64 | |
| os: linux | |
| libc: musl | |
| # Windows builds | |
| - runner: windows-2022 | |
| platform: win32 | |
| arch: x64 | |
| os: windows | |
| # Windows ARM64: Cross-compile on x64 runner (no ARM64 hosted runners available) | |
| - runner: windows-2022 | |
| platform: win32 | |
| arch: arm64 | |
| os: windows | |
| cross_compile: true | |
| steps: | |
| - uses: SocketDev/socket-registry/.github/actions/setup-and-install@ea1986b8019fedee5fb38b485690b13ad8e0217f # main | |
| - name: Check if tool should be built | |
| id: build-enabled | |
| shell: bash | |
| env: | |
| TOOLS_INPUT: ${{ inputs.tools || 'all' }} | |
| run: | | |
| TOOL="binject" | |
| if [ "$TOOLS_INPUT" = "all" ]; then | |
| echo "build=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Building $TOOL (all tools selected)" | |
| elif echo ",$TOOLS_INPUT," | grep -q ",$TOOL,"; then | |
| echo "build=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Building $TOOL (explicitly selected)" | |
| else | |
| echo "build=false" >> $GITHUB_OUTPUT | |
| echo "⏭ Skipping $TOOL (not selected)" | |
| fi | |
| - name: Setup checkpoint caching | |
| if: steps.build-enabled.outputs.build == 'true' | |
| id: setup-checkpoints | |
| uses: ./.github/actions/setup-checkpoints | |
| with: | |
| package-name: binject | |
| build-mode: ${{ inputs.build_mode || 'prod' }} | |
| platform: ${{ matrix.platform }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc || '' }} | |
| # Only create a signing keychain / install Depot CLI when a build is | |
| # actually about to run. On cache-hit rounds the tarball already | |
| # contains the signed binary, so spinning up an ephemeral keychain | |
| # or fetching the Depot CLI just burns CI time. | |
| - name: Setup macOS code signing | |
| if: matrix.os == 'macos' && steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/setup-macos-keychain | |
| - name: Setup Depot CLI | |
| if: matrix.os == 'linux' && steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: depot/setup-action@15c09a5f77a0840ad4bce955686522a257853461 # v1.7.1 | |
| with: | |
| oidc: true | |
| - name: Set platform-arch (binject) | |
| id: platform-arch | |
| uses: ./.github/actions/set-platform-arch | |
| with: | |
| platform: ${{ matrix.platform }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc }} | |
| - name: Validate checkpoint binary exists | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'false' | |
| id: validate-checkpoint | |
| shell: bash | |
| working-directory: packages/binject | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # All platforms (Linux Depot / macOS / Windows native) export to | |
| # build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/. A prior version | |
| # of this step had a separate Linux branch without PLATFORM_ARCH | |
| # based on a misread of the Dockerfile — the binary would never | |
| # be found on Linux cache-hit and force-rebuild kept firing, | |
| # defeating the entire checkpoint cache for this matrix. | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject" | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="${BINARY}.exe" | |
| fi | |
| if [ ! -f "$BINARY" ]; then | |
| echo "⚠️ Checkpoint restored but binary missing at: $BINARY" | |
| echo "force-rebuild=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "✅ Binary exists: $BINARY" | |
| echo "force-rebuild=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Setup build environment | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/setup-build-env | |
| with: | |
| os: ${{ matrix.os }} | |
| arch: ${{ matrix.arch }} | |
| libc: ${{ matrix.libc || '' }} | |
| cross-compile: ${{ matrix.cross_compile || 'false' }} | |
| - name: Install CMake (Windows) | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' && matrix.os == 'windows' | |
| shell: bash | |
| run: | | |
| echo "Installing CMake for LIEF build..." | |
| # Retry up to 3 times to handle transient Chocolatey CDN failures | |
| for i in 1 2 3; do | |
| if choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' -y; then | |
| break | |
| fi | |
| echo "Attempt $i failed, retrying in 10 seconds..." | |
| sleep 10 | |
| done | |
| echo "Refreshing PATH to include CMake..." | |
| export PATH="/c/Program Files/CMake/bin:$PATH" | |
| echo "Verifying CMake installation..." | |
| cmake --version | |
| - name: Debug build decision | |
| if: steps.build-enabled.outputs.build == 'true' | |
| shell: bash | |
| env: | |
| BUILD_REQUIRED: ${{ steps.setup-checkpoints.outputs.build-required }} | |
| CACHE_HIT: ${{ steps.setup-checkpoints.outputs.cache-hit }} | |
| run: | | |
| if [ "${BUILD_REQUIRED}" = "true" ]; then | |
| echo "✅ Build will run (cache-hit: ${CACHE_HIT})" | |
| else | |
| echo "⏭️ Skipping build (checkpoint restored)" | |
| fi | |
| - name: Load cache version (binject) | |
| id: cache-version | |
| shell: bash | |
| run: | | |
| load_version() { | |
| local key="$1" | |
| local val | |
| val=$(jq -r ".versions[\"$key\"]" .github/cache-versions.json) | |
| if [ -z "$val" ] || [ "$val" = "null" ]; then | |
| echo "error: cache-versions.json missing key: $key" >&2 | |
| exit 1 | |
| fi | |
| echo "$val" | |
| } | |
| echo "version=$(load_version binject)" >> $GITHUB_OUTPUT | |
| echo "lief_version=$(load_version lief)" >> $GITHUB_OUTPUT | |
| echo "stubs_version=$(load_version stubs)" >> $GITHUB_OUTPUT | |
| - name: Initialize submodules before Docker build (Linux) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| uses: ./.github/actions/init-submodules | |
| with: | |
| submodules: packages/bin-infra/upstream/zstd packages/binject/upstream/libdeflate packages/binject/upstream/cJSON | |
| - name: Get submodule SHAs for cache (binject) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| id: submodule-sha | |
| shell: bash | |
| run: | | |
| LIBDEFLATE_SHA=$(git -C packages/binject/upstream/libdeflate rev-parse --short=7 HEAD) | |
| CJSON_SHA=$(git -C packages/binject/upstream/cJSON rev-parse --short=7 HEAD) | |
| echo "libdeflate=${LIBDEFLATE_SHA}" >> $GITHUB_OUTPUT | |
| echo "cjson=${CJSON_SHA}" >> $GITHUB_OUTPUT | |
| echo "Submodule SHAs: libdeflate=${LIBDEFLATE_SHA}, cJSON=${CJSON_SHA}" | |
| - name: Clean LIEF before Docker build (Linux) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| run: rm -rf packages/lief-builder/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/lief/ | |
| - name: Stage registry tool-checksums for Docker build context | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| shell: bash | |
| run: | | |
| # Socket-registry's setup action exports SOCKET_TOOL_CHECKSUMS_FILE | |
| # pointing at a stable on-runner copy of external-tools.json. | |
| # Dockerfiles `COPY .build-context/registry-tools.json …` to | |
| # resolve pnpm version + per-platform asset + sha256 at build | |
| # time without duplicating per-Dockerfile constants. | |
| mkdir -p .build-context | |
| cp "$SOCKET_TOOL_CHECKSUMS_FILE" .build-context/registry-tools.json | |
| - name: Build binject with Depot (Linux - offloads compute) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' && | |
| matrix.os == 'linux' | |
| uses: depot/build-push-action@5f3b3c2e5a00f0093de47f657aeaefcedff27d18 # v1.17.0 | |
| with: | |
| project: 8fpj9495vw | |
| platforms: linux/${{ matrix.arch == 'x64' && 'amd64' || matrix.arch }} | |
| build-args: | | |
| BUILD_MODE=${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH=${{ steps.platform-arch.outputs.platform_arch }} | |
| CACHE_VERSION=${{ steps.cache-version.outputs.version }} | |
| LIEF_CACHE_VERSION=${{ steps.cache-version.outputs.lief_version }} | |
| LIBDEFLATE_CACHE_VERSION=${{ steps.submodule-sha.outputs.libdeflate }} | |
| CJSON_CACHE_VERSION=${{ steps.submodule-sha.outputs.cjson }} | |
| STUBS_CACHE_VERSION=${{ steps.cache-version.outputs.stubs_version }} | |
| # GH_TOKEN via BuildKit secret (see binpress build above). | |
| secrets: | | |
| gh_token=${{ github.token }} | |
| no-cache: ${{ inputs.force == true }} | |
| file: packages/binject/docker/Dockerfile.${{ matrix.libc == 'musl' && 'musl' || 'glibc' }} | |
| target: export | |
| outputs: type=local,dest=packages/binject/build | |
| context: . | |
| - name: Verify Depot build output (binject) | |
| if: | | |
| matrix.os == 'linux' && | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' | |
| shell: bash | |
| working-directory: packages/binject | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| run: | | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject" | |
| [ -f "$BINARY" ] || { echo "× Binary not found: $BINARY"; exit 1; } | |
| echo "✅ $(file "$BINARY")" | |
| - name: Validate Depot checkpoints (binject) | |
| if: | | |
| matrix.os == 'linux' && | |
| steps.build-enabled.outputs.build == 'true' && | |
| steps.setup-checkpoints.outputs.build-required == 'true' | |
| uses: ./.github/actions/validate-depot-checkpoints | |
| with: | |
| package-path: packages/binject | |
| build-mode: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| package-name: binject | |
| platform-arch: ${{ steps.platform-arch.outputs.platform_arch }} | |
| - name: Build binject native (macOS/Windows) | |
| if: | | |
| steps.build-enabled.outputs.build == 'true' && | |
| (steps.setup-checkpoints.outputs.build-required == 'true' || steps.validate-checkpoint.outputs.force-rebuild == 'true') && | |
| matrix.os != 'linux' | |
| shell: bash | |
| working-directory: packages/binject | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| GH_TOKEN: ${{ github.token }} | |
| PLATFORM: ${{ matrix.platform }} | |
| ARCH: ${{ matrix.arch }} | |
| TARGET_ARCH: ${{ matrix.arch }} | |
| DEBUG: ${{ inputs.debug != '0' && inputs.debug || '' }} | |
| run: | | |
| echo "🔨 Building binject for ${PLATFORM}-${ARCH} (${BUILD_MODE} mode)" | |
| # Use build script with --force to bypass checkpoint check. | |
| # (checkpoint restoration is handled by setup-checkpoints action). | |
| # Build script handles LIEF (macOS), platform detection, and Makefile selection. | |
| # TARGET_ARCH env var enables ARM64 cross-compilation with llvm-mingw. | |
| pnpm run build -- --force | |
| echo "✅ Build complete" | |
| # Construct PLATFORM_ARCH for build output path. | |
| if [ "${PLATFORM}" = "win32" ]; then | |
| RELEASE_PLATFORM="win" | |
| else | |
| RELEASE_PLATFORM="${PLATFORM}" | |
| fi | |
| PLATFORM_ARCH="${RELEASE_PLATFORM}-${ARCH}" | |
| ls -lh build/${BUILD_MODE}/${PLATFORM_ARCH}/out/ | |
| - name: Verify binary | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'false' | |
| shell: bash | |
| working-directory: packages/binject | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # All platforms (Linux Depot / macOS / Windows native) export to | |
| # build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/. Matches the | |
| # validate-checkpoint step above. | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject" | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="${BINARY}.exe" | |
| fi | |
| if [ ! -f "$BINARY" ]; then | |
| echo "× Binary not found: $BINARY" | |
| exit 1 | |
| fi | |
| echo "✅ Binary exists: $BINARY" | |
| # Show binary info | |
| if [ "${OS_TYPE}" = "macos" ]; then | |
| file "$BINARY" | |
| otool -L "$BINARY" || true | |
| elif [ "${OS_TYPE}" = "linux" ]; then | |
| file "$BINARY" | |
| ldd "$BINARY" || true | |
| elif [ "${OS_TYPE}" = "windows" ]; then | |
| file "$BINARY" || true | |
| fi | |
| - name: Test binary (functional test) | |
| if: steps.build-enabled.outputs.build == 'true' && steps.setup-checkpoints.outputs.build-required == 'true' && matrix.arch == 'x64' && matrix.libc != 'musl' && matrix.os != 'linux' | |
| shell: bash | |
| working-directory: packages/binject | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Run full functional tests on native x64 platforms (non-Linux). | |
| # Linux glibc tests run inside Docker to avoid LTO bytecode incompatibility. | |
| echo "Running functional tests for binject..." | |
| node scripts/test.mts | |
| - name: Smoke test binary | |
| if: steps.build-enabled.outputs.build == 'true' | |
| shell: bash | |
| working-directory: packages/binject | |
| env: | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| ARCH: ${{ matrix.arch }} | |
| LIBC: ${{ matrix.libc }} | |
| run: | | |
| # Deterministic smoke test: native execution, Docker, QEMU, or static verification | |
| # All platforms now use PLATFORM_ARCH in build output path. | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject.exe" | |
| else | |
| BINARY="build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject" | |
| fi | |
| # Prepare smoke test options | |
| SMOKE_TEST_ARGS="$BINARY" | |
| if [ "${ARCH}" = "arm64" ]; then | |
| SMOKE_TEST_ARGS="$SMOKE_TEST_ARGS --arch arm64" | |
| fi | |
| if [ "${LIBC}" = "musl" ]; then | |
| SMOKE_TEST_ARGS="$SMOKE_TEST_ARGS --musl" | |
| fi | |
| echo "Running smoke test: node ../../packages/build-infra/scripts/smoke-test-binary.mts $SMOKE_TEST_ARGS" | |
| node ../../packages/build-infra/scripts/smoke-test-binary.mts $SMOKE_TEST_ARGS | |
| - name: Set artifact name and path | |
| shell: bash | |
| env: | |
| PLATFORM: ${{ matrix.platform }} | |
| ARCH: ${{ matrix.arch }} | |
| LIBC: ${{ matrix.libc }} | |
| BUILD_MODE: ${{ steps.setup-checkpoints.outputs.build-mode }} | |
| PLATFORM_ARCH: ${{ steps.platform-arch.outputs.platform_arch }} | |
| OS_TYPE: ${{ matrix.os }} | |
| run: | | |
| # Use platform-arch output (win32→win conversion already done). | |
| ARTIFACT_NAME="binject-${PLATFORM_ARCH}" | |
| echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV | |
| # Construct binary path. | |
| # All platforms now use PLATFORM_ARCH in build output path. | |
| if [ "${OS_TYPE}" = "windows" ]; then | |
| BINARY_PATH="packages/binject/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject.exe" | |
| else | |
| BINARY_PATH="packages/binject/build/${BUILD_MODE}/${PLATFORM_ARCH}/out/Final/binject" | |
| fi | |
| echo "BINARY_PATH=${BINARY_PATH}" >> $GITHUB_ENV | |
| - name: Upload artifacts | |
| if: steps.build-enabled.outputs.build == 'true' | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: ${{ env.ARTIFACT_NAME }} | |
| path: ${{ env.BINARY_PATH }} | |
| retention-days: 30 | |
| if-no-files-found: error | |
| compression-level: 0 # Already-compressed binary artifact | |
| release: | |
| name: Release ${{ matrix.tool }} | |
| needs: [binpress, binflate, binject] | |
| # always() lets this job run when ANY of the three tool-build jobs | |
| # completed — otherwise selecting `tools=binpress` would skip binflate | |
| # and binject (their own job-level `if:` gates them off), and GitHub | |
| # treats skipped dependencies as unsatisfied, silently canceling the | |
| # entire release matrix. With always(), each release-matrix entry still | |
| # evaluates its own `Check if tool should be released` step and skips | |
| # the ones the user didn't ask for. | |
| if: | | |
| always() | |
| && (needs.binpress.result == 'success' | |
| || needs.binflate.result == 'success' | |
| || needs.binject.result == 'success') | |
| && github.event_name == 'workflow_dispatch' | |
| && !inputs.dry_run | |
| environment: release | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: write # Required to create GitHub releases | |
| strategy: | |
| matrix: | |
| tool: [binpress, binflate, binject] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| sparse-checkout: | | |
| .github/scripts/generate-version.sh | |
| sparse-checkout-cone-mode: false | |
| - name: Check if tool should be released | |
| id: should-release | |
| shell: bash | |
| env: | |
| TOOLS_INPUT: ${{ inputs.tools || 'all' }} | |
| TOOL: ${{ matrix.tool }} | |
| run: | | |
| if [ "$TOOLS_INPUT" = "all" ]; then | |
| echo "release=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Releasing $TOOL (all tools selected)" | |
| elif echo "$TOOLS_INPUT" | grep -q "$TOOL"; then | |
| echo "release=true" >> $GITHUB_OUTPUT | |
| echo "[OK] Releasing $TOOL (explicitly selected)" | |
| else | |
| echo "release=false" >> $GITHUB_OUTPUT | |
| echo "⏭ Skipping $TOOL release (not selected)" | |
| fi | |
| - name: Download all artifacts for ${{ matrix.tool }} | |
| if: steps.should-release.outputs.release == 'true' | |
| uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 | |
| with: | |
| path: artifacts/ | |
| pattern: ${{ matrix.tool }}-* | |
| - name: Organize release assets | |
| if: steps.should-release.outputs.release == 'true' | |
| env: | |
| TOOL: ${{ matrix.tool }} | |
| run: | | |
| mkdir -p dist/${TOOL} | |
| # Darwin ARM64 | |
| if [ -d "artifacts/${TOOL}-darwin-arm64" ]; then | |
| mv artifacts/${TOOL}-darwin-arm64/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-darwin-arm64 2>/dev/null || \ | |
| mv artifacts/${TOOL}-darwin-arm64/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-darwin-arm64.exe 2>/dev/null || true | |
| fi | |
| # Darwin x64 | |
| if [ -d "artifacts/${TOOL}-darwin-x64" ]; then | |
| mv artifacts/${TOOL}-darwin-x64/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-darwin-x64 2>/dev/null || \ | |
| mv artifacts/${TOOL}-darwin-x64/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-darwin-x64.exe 2>/dev/null || true | |
| fi | |
| # Linux glibc x64 | |
| if [ -d "artifacts/${TOOL}-linux-x64" ]; then | |
| mv artifacts/${TOOL}-linux-x64/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-linux-x64 2>/dev/null || \ | |
| mv artifacts/${TOOL}-linux-x64/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-linux-x64.exe 2>/dev/null || true | |
| fi | |
| # Linux glibc ARM64 | |
| if [ -d "artifacts/${TOOL}-linux-arm64" ]; then | |
| mv artifacts/${TOOL}-linux-arm64/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-linux-arm64 2>/dev/null || \ | |
| mv artifacts/${TOOL}-linux-arm64/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-linux-arm64.exe 2>/dev/null || true | |
| fi | |
| # Linux musl x64 | |
| if [ -d "artifacts/${TOOL}-linux-x64-musl" ]; then | |
| mv artifacts/${TOOL}-linux-x64-musl/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-linux-x64-musl 2>/dev/null || \ | |
| mv artifacts/${TOOL}-linux-x64-musl/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-linux-x64-musl.exe 2>/dev/null || true | |
| fi | |
| # Linux musl ARM64 | |
| if [ -d "artifacts/${TOOL}-linux-arm64-musl" ]; then | |
| mv artifacts/${TOOL}-linux-arm64-musl/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-linux-arm64-musl 2>/dev/null || \ | |
| mv artifacts/${TOOL}-linux-arm64-musl/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-linux-arm64-musl.exe 2>/dev/null || true | |
| fi | |
| # Windows x64 | |
| if [ -d "artifacts/${TOOL}-win-x64" ]; then | |
| mv artifacts/${TOOL}-win-x64/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-win-x64.exe 2>/dev/null || \ | |
| mv artifacts/${TOOL}-win-x64/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-win-x64 2>/dev/null || true | |
| fi | |
| # Windows ARM64 | |
| if [ -d "artifacts/${TOOL}-win-arm64" ]; then | |
| mv artifacts/${TOOL}-win-arm64/${TOOL}.exe \ | |
| dist/${TOOL}/${TOOL}-win-arm64.exe 2>/dev/null || \ | |
| mv artifacts/${TOOL}-win-arm64/${TOOL} \ | |
| dist/${TOOL}/${TOOL}-win-arm64 2>/dev/null || true | |
| fi | |
| # Make Unix binaries executable | |
| chmod +x dist/${TOOL}/${TOOL}-* 2>/dev/null || true | |
| ls -lh dist/${TOOL}/ | |
| - name: Generate version | |
| if: steps.should-release.outputs.release == 'true' | |
| id: version | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TOOL: ${{ matrix.tool }} | |
| run: | | |
| source .github/scripts/generate-version.sh | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Version: $VERSION" | |
| TAG="${TOOL}-${VERSION}" | |
| if gh release view "$TAG" &>/dev/null; then | |
| echo "Release $TAG already exists, skipping." | |
| echo "skip=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "skip=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Generate checksums | |
| if: steps.should-release.outputs.release == 'true' && steps.version.outputs.skip != 'true' | |
| shell: bash | |
| env: | |
| TOOL: ${{ matrix.tool }} | |
| run: | | |
| cd dist/${TOOL} | |
| if command -v shasum &> /dev/null; then | |
| shasum -a 256 ${TOOL}-* > checksums.txt | |
| elif command -v sha256sum &> /dev/null; then | |
| sha256sum ${TOOL}-* > checksums.txt | |
| else | |
| echo "Error: No SHA-256 command found" | |
| exit 1 | |
| fi | |
| # Validate checksums.txt is not empty | |
| if [ ! -s checksums.txt ]; then | |
| echo "Error: checksums.txt is empty" | |
| exit 1 | |
| fi | |
| cat checksums.txt | |
| - name: Create GitHub Release | |
| if: steps.should-release.outputs.release == 'true' && steps.version.outputs.skip != 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TOOL: ${{ matrix.tool }} | |
| VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| RELEASE_NAME="${TOOL}" | |
| TAG="${RELEASE_NAME}-${VERSION}" | |
| # Tool descriptions | |
| case "$RELEASE_NAME" in | |
| binpress) | |
| DESCRIPTION="Binary compression tool for Mach-O, ELF, and PE executables." | |
| ;; | |
| binflate) | |
| DESCRIPTION="Binary decompression tool for extracting compressed executables." | |
| ;; | |
| binject) | |
| DESCRIPTION="Binary resource injection tool for Mach-O, ELF, and PE executables." | |
| ;; | |
| esac | |
| echo "Creating new release $TAG..." | |
| gh release create "$TAG" \ | |
| --title "${TOOL} ${VERSION}" \ | |
| --notes "${DESCRIPTION} | |
| ## Platforms | |
| - darwin-arm64 | |
| - darwin-x64 | |
| - linux-arm64 | |
| - linux-x64 | |
| - linux-arm64-musl | |
| - linux-x64-musl | |
| - win-arm64 | |
| - win-x64 | |
| ## Files | |
| - \`${TOOL}-darwin-arm64\` - macOS Apple Silicon | |
| - \`${TOOL}-darwin-x64\` - macOS Intel | |
| - \`${TOOL}-linux-arm64\` - Linux ARM64 (glibc) | |
| - \`${TOOL}-linux-x64\` - Linux x64 (glibc) | |
| - \`${TOOL}-linux-arm64-musl\` - Linux ARM64 (musl/Alpine) | |
| - \`${TOOL}-linux-x64-musl\` - Linux x64 (musl/Alpine) | |
| - \`${TOOL}-win-arm64.exe\` - Windows ARM64 | |
| - \`${TOOL}-win-x64.exe\` - Windows x64 | |
| - \`checksums.txt\` - SHA256 checksums | |
| ## Usage | |
| Download the appropriate binary for your platform and run it: | |
| \`\`\`bash | |
| ./${TOOL}-darwin-arm64 --help | |
| \`\`\`" \ | |
| dist/${TOOL}/${TOOL}-* \ | |
| dist/${TOOL}/checksums.txt | |
| update-checksums: | |
| needs: release | |
| # always() + explicit success check: without always(), a skipped release | |
| # matrix entry (e.g. when the user selected tools=binpress and binflate/ | |
| # binject were filtered out) makes GitHub treat `needs.release` as | |
| # unsatisfied and silently cancels this job — so the checksum bump | |
| # never lands even though the published tool needs one. Same pattern | |
| # as the release job's R8 fix. | |
| if: | | |
| always() | |
| && needs.release.result == 'success' | |
| && github.event_name == 'workflow_dispatch' | |
| && !inputs.dry_run | |
| permissions: | |
| contents: write # release-assets.json commit after publishing GitHub release | |
| uses: ./.github/workflows/update-checksums.yml | |
| secrets: | |
| BOT_GPG_PRIVATE_KEY: ${{ secrets.BOT_GPG_PRIVATE_KEY }} |