name: release-engine # Builds the engine binary for every supported target and publishes them, with # sha256 sidecars, as the GitHub Release `engine-v` on this repo. That # release is what the launcher (skill/scripts/impeccable), the npm shim # (cli/bin/cli.js), `impeccable install`, and `bun run fetch:engine` download. # # Trigger: `bun run release:engine` (scripts/release.mjs) verifies # ENGINE_VERSION, the npm platform-package pins, and a clean tree, then # pushes the tag. Third-party actions are pinned to commit SHAs so a # moved tag cannot swap the code this workflow runs. on: push: tags: ['engine-v*'] # Same-run artifact transfers use ACTIONS_RUNTIME_TOKEN, not GITHUB_TOKEN; # they do not require actions: read/write. Keep downloads scoped to this run. permissions: contents: read jobs: build: strategy: fail-fast: false matrix: include: - { os: macos-14, target: aarch64-apple-darwin, short: darwin-arm64 } # No Intel runner: GitHub retired macos-13. Apple's toolchain builds # x86_64 on an arm64 host natively once the target is installed. - { os: macos-14, target: x86_64-apple-darwin, short: darwin-x64 } - { os: ubuntu-latest, target: x86_64-unknown-linux-musl, short: linux-x64 } - { os: ubuntu-latest, target: aarch64-unknown-linux-musl, short: linux-arm64, cross: true } - { os: windows-latest, target: x86_64-pc-windows-msvc, short: windows-x64 } runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Check the tag matches ENGINE_VERSION shell: bash run: | set -e want="engine-v$(tr -d '[:space:]' < ENGINE_VERSION)" [ "$GITHUB_REF_NAME" = "$want" ] || { echo "tag $GITHUB_REF_NAME != $want"; exit 1; } # rust-toolchain.toml names the channel; `rustup show` installs it. # Never override the toolchain here. - name: Install the pinned toolchain shell: bash run: rustup show && rustup target add ${{ matrix.target }} - if: matrix.os == 'ubuntu-latest' run: sudo apt-get update && sudo apt-get install -y musl-tools - if: matrix.cross run: cargo install cross --locked - name: Build shell: bash run: ${{ matrix.cross && 'cross' || 'cargo' }} build --release -p impeccable --target ${{ matrix.target }} - name: Smoke the binary if: ${{ !matrix.cross }} shell: bash run: target/${{ matrix.target }}/release/impeccable${{ runner.os == 'Windows' && '.exe' || '' }} engine-probe - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: # Keep unsigned Windows output outside the publish job's pattern. name: ${{ matrix.short == 'windows-x64' && 'unsigned-windows-x64' || format('impeccable-{0}', matrix.short) }} path: target/${{ matrix.target }}/release/impeccable${{ runner.os == 'Windows' && '.exe' || '' }} if-no-files-found: error sign-windows: needs: build runs-on: windows-latest timeout-minutes: 15 environment: windows-signing permissions: contents: read id-token: write steps: # A fresh runner signs only this run's engine. It does not check out or # execute repository code with the Azure identity available. - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: unsigned-windows-x64 path: unsigned - name: Azure login (OIDC) uses: azure/login@7ddb5af1ef8758cf1353cf3b42f940aee27ba21c # v3 with: client-id: ${{ vars.AZURE_CLIENT_ID }} tenant-id: ${{ vars.AZURE_TENANT_ID }} subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} - name: Sign Windows engine uses: azure/artifact-signing-action@c7ab2a863ab5f9a846ddb8265964877ef296ee82 # v2 with: endpoint: https://eus.codesigning.azure.net/ signing-account-name: impeccable-signing certificate-profile-name: impeccable-windows files: ${{ github.workspace }}\unsigned\impeccable.exe file-digest: SHA256 timestamp-rfc3161: http://timestamp.acs.microsoft.com timestamp-digest: SHA256 description: Impeccable engine description-url: https://impeccable.style exclude-environment-credential: true # Only the preceding OIDC Azure CLI login is used. Other credential # types are excluded by this pinned action's defaults. exclude-azure-cli-credential: false cache-dependencies: false - name: Verify signed engine shell: pwsh run: | $ErrorActionPreference = 'Stop' $signature = Get-AuthenticodeSignature -LiteralPath 'unsigned/impeccable.exe' if ($signature.Status -ne 'Valid') { throw "Invalid Windows signature: $($signature.Status) — $($signature.StatusMessage)" } $publisher = $signature.SignerCertificate.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::SimpleName, $false) if ($publisher -cne 'Renaissance Geek, Inc.') { throw "Unexpected Windows publisher: $publisher" } if ($null -eq $signature.TimeStamperCertificate) { throw 'The Windows signature has no timestamp.' } Write-Output "Verified publisher: $publisher; certificate: $($signature.SignerCertificate.Thumbprint)" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: impeccable-windows-x64 path: unsigned/impeccable.exe if-no-files-found: error publish: needs: [build, sign-windows] runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: impeccable-* path: artifacts - name: Lay out release assets with checksums run: | set -e mkdir -p out for d in artifacts/impeccable-*; do short=$(basename "$d" | sed 's/^impeccable-//') f=$(ls "$d" | head -1) case "$short" in windows-*) dest="out/impeccable-$short.exe" ;; *) dest="out/impeccable-$short" ;; esac cp "$d/$f" "$dest" (cd out && sha256sum "$(basename "$dest")" > "$(basename "$dest").sha256") done ls -la out - name: Publish the GitHub Release env: { GH_TOKEN: "${{ github.token }}" } # No --clobber: a published asset is immutable. A re-run against an # existing release fails on the first existing asset instead of # silently replacing a binary and its sidecar hash. run: | set -e tag="${GITHUB_REF_NAME}" gh release create "$tag" --repo "$GITHUB_REPOSITORY" --title "impeccable engine $tag" \ --notes "Prebuilt impeccable engine binaries ($tag). The launcher, the npm shim and impeccable install download these on first run. Docs: https://impeccable.style" out/* || \ gh release upload "$tag" out/* --repo "$GITHUB_REPOSITORY"