nyx/.github/workflows/release-build.yml

281 lines
8.3 KiB
YAML

name: Release build & publish
on:
release:
types: [created]
workflow_dispatch:
inputs:
tag:
description: "Existing release tag to (re)build and publish (e.g. v0.5.0)"
required: true
type: string
permissions:
contents: write
env:
BIN_NAME: nyx
RELEASE_TAG: ${{ github.event.release.tag_name || inputs.tag }}
jobs:
frontend:
name: build-frontend
runs-on: ubuntu-latest
steps:
- name: Check out sources
uses: actions/checkout@v6
with:
ref: ${{ env.RELEASE_TAG }}
- uses: actions/setup-node@v6
with:
node-version: 20
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
working-directory: frontend
run: npm ci
- name: Build frontend
working-directory: frontend
run: npm run build
- name: Upload frontend dist
uses: actions/upload-artifact@v7
with:
name: frontend-dist
path: src/server/assets/dist/
if-no-files-found: error
retention-days: 1
build:
needs: frontend
strategy:
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
- target: x86_64-pc-windows-msvc
os: windows-latest
- target: x86_64-apple-darwin
os: macos-14
- target: aarch64-apple-darwin
os: macos-14
runs-on: ${{ matrix.os }}
steps:
- name: Check out sources
uses: actions/checkout@v6
with:
ref: ${{ env.RELEASE_TAG }}
- name: Download prebuilt frontend dist
uses: actions/download-artifact@v8
with:
name: frontend-dist
path: src/server/assets/dist/
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
target: ${{ matrix.target }}
cache: true
- name: Install cross-compilation tools (ARM Linux)
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
echo '[target.aarch64-unknown-linux-gnu]' >> ~/.cargo/config.toml
echo 'linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config.toml
- name: Install target
run: rustup target add ${{ matrix.target }}
- name: Build
run: cargo build --release --bin ${{ env.BIN_NAME }} --target ${{ matrix.target }}
- name: Package (Linux & macOS)
if: runner.os != 'Windows'
shell: bash
run: |
set -euo pipefail
BIN=${{ env.BIN_NAME }}
TARGET=${{ matrix.target }}
EXT=$([[ "$TARGET" == *windows* ]] && echo ".exe" || echo "")
BIN_PATH=target/$TARGET/release/$BIN$EXT
mkdir -p dist
ARCHIVE=$BIN-$TARGET.zip
zip -9 "dist/$ARCHIVE" "$BIN_PATH" THIRDPARTY-LICENSES.html LICENSE* COPYING*
echo "ASSET=$ARCHIVE" >> "$GITHUB_ENV"
- name: Package (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$Bin = '${{ env.BIN_NAME }}'
$Target = '${{ matrix.target }}'
$Ext = '.exe'
$BinPath = "target/$Target/release/$Bin$Ext"
New-Item -ItemType Directory -Path dist -Force | Out-Null
$Archive = "$Bin-$Target.zip"
Compress-Archive `
-Path $BinPath, 'THIRDPARTY-LICENSES.html', 'LICENSE*', 'COPYING*' `
-DestinationPath "dist/$Archive" `
-CompressionLevel Optimal
Add-Content -Path $env:GITHUB_ENV -Value "ASSET=$Archive"
- name: Upload build artifact
uses: actions/upload-artifact@v7
with:
name: release-${{ matrix.target }}
path: dist/${{ env.ASSET }}
if-no-files-found: error
retention-days: 1
reproducibility:
name: reproducibility-check
needs: frontend
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Check out sources
uses: actions/checkout@v6
with:
ref: ${{ env.RELEASE_TAG }}
- name: Download prebuilt frontend dist
uses: actions/download-artifact@v8
with:
name: frontend-dist
path: src/server/assets/dist/
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
target: x86_64-unknown-linux-gnu
cache: true
- name: Build twice and diff hashes
shell: bash
env:
RUSTFLAGS: "--remap-path-prefix=${{ github.workspace }}=/build"
run: |
set -euo pipefail
TARGET=x86_64-unknown-linux-gnu
BIN=${{ env.BIN_NAME }}
BIN_PATH="target/$TARGET/release/$BIN"
SOURCE_DATE_EPOCH=$(git log -1 --format=%ct HEAD)
export SOURCE_DATE_EPOCH
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
cargo build --release --bin "$BIN" --target "$TARGET"
HASH1=$(sha256sum "$BIN_PATH" | awk '{print $1}')
echo "first build: $HASH1"
cargo clean --release --target "$TARGET"
cargo build --release --bin "$BIN" --target "$TARGET"
HASH2=$(sha256sum "$BIN_PATH" | awk '{print $1}')
echo "second build: $HASH2"
if [ "$HASH1" != "$HASH2" ]; then
echo "::error::Reproducibility check failed: builds are not bit-identical"
echo " first: $HASH1"
echo " second: $HASH2"
exit 1
fi
echo "::notice::Reproducible build verified (sha256=$HASH1)"
publish:
name: publish-release
runs-on: ubuntu-latest
needs: [build]
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Check out sources
uses: actions/checkout@v6
with:
ref: ${{ env.RELEASE_TAG }}
- name: Generate CycloneDX SBOM
uses: anchore/sbom-action@v0
with:
path: .
format: cyclonedx-json
output-file: nyx-${{ env.RELEASE_TAG }}.cdx.json
upload-artifact: false
upload-release-assets: false
- name: Download all build artifacts
uses: actions/download-artifact@v8
with:
path: release-artifacts
pattern: release-*
merge-multiple: true
- name: Generate SHA256SUMS
run: |
set -euo pipefail
cd release-artifacts
ls -lh
sha256sum *.zip > SHA256SUMS
cat SHA256SUMS
# Sigstore keyless signing. Verify with:
# cosign verify-blob --bundle <file>.bundle \
# --certificate-identity-regexp 'https://github.com/elicpeter/nyx/.*' \
# --certificate-oidc-issuer https://token.actions.githubusercontent.com \
# <file>
- name: Install cosign
uses: sigstore/cosign-installer@v4.1.1
- name: Cosign keyless sign release artifacts
shell: bash
run: |
set -euo pipefail
SBOM="nyx-${{ env.RELEASE_TAG }}.cdx.json"
(
cd release-artifacts
for f in *.zip SHA256SUMS; do
cosign sign-blob --yes \
--bundle "$f.bundle" \
"$f"
done
)
cosign sign-blob --yes \
--bundle "$SBOM.bundle" \
"$SBOM"
# SLSA v1 provenance. Verify with `gh attestation verify <file> --repo <repo>`.
- name: Generate SLSA build provenance
uses: actions/attest-build-provenance@v4
with:
subject-path: |
release-artifacts/*.zip
release-artifacts/SHA256SUMS
nyx-${{ env.RELEASE_TAG }}.cdx.json
- name: Upload to the release
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ env.RELEASE_TAG }}
files: |
release-artifacts/*.zip
release-artifacts/*.zip.bundle
release-artifacts/SHA256SUMS
release-artifacts/SHA256SUMS.bundle
nyx-${{ env.RELEASE_TAG }}.cdx.json
nyx-${{ env.RELEASE_TAG }}.cdx.json.bundle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}