mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
Validated release workflow inputs, signing boundaries, full SHA pins, and exact-head required CI checks. v8 enforces artifact digest mismatches as errors; no workflow input migration required. AI-assisted dependency review and validation by Codex.
154 lines
7.2 KiB
YAML
154 lines
7.2 KiB
YAML
name: release-engine
|
|
# Builds the engine binary for every supported target and publishes them, with
|
|
# sha256 sidecars, as the GitHub Release `engine-v<X>` 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"
|