mirror of
https://github.com/davidkaya/aryx.git
synced 2026-07-24 21:48:36 +02:00
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
268 lines
8.5 KiB
YAML
268 lines
8.5 KiB
YAML
name: CI and release
|
|
|
|
on:
|
|
pull_request:
|
|
push:
|
|
branches:
|
|
- '**'
|
|
tags:
|
|
- '*'
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
validate:
|
|
name: Validate (${{ matrix.label }})
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: windows-latest
|
|
label: Windows
|
|
- os: macos-15-intel
|
|
label: macOS (x64)
|
|
- os: macos-15
|
|
label: macOS (arm64)
|
|
- os: ubuntu-latest
|
|
label: Linux
|
|
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Bun
|
|
uses: oven-sh/setup-bun@v2
|
|
with:
|
|
bun-version: 1.3.6
|
|
|
|
- name: Set up .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: 9.0.x
|
|
|
|
- name: Install Linux native dependencies
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libsecret-1-dev
|
|
|
|
- name: Install dependencies
|
|
run: bun install --frozen-lockfile
|
|
|
|
- name: Run web tests
|
|
run: bun run test
|
|
|
|
- name: Run sidecar tests
|
|
run: bun run sidecar:test
|
|
|
|
- name: Build the application
|
|
run: bun run build
|
|
|
|
create-release:
|
|
name: Create GitHub release
|
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
needs: validate
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Create release if needed
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
if gh release view "$TAG_NAME" >/dev/null 2>&1; then
|
|
echo "Release $TAG_NAME already exists."
|
|
else
|
|
gh release create "$TAG_NAME" --title "$TAG_NAME" --generate-notes
|
|
fi
|
|
|
|
publish-release-assets:
|
|
name: Publish release asset (${{ matrix.label }})
|
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
|
needs: create-release
|
|
runs-on: ${{ matrix.os }}
|
|
permissions:
|
|
contents: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: windows-latest
|
|
label: Windows
|
|
- os: macos-15-intel
|
|
label: macOS (x64)
|
|
- os: macos-15
|
|
label: macOS (arm64)
|
|
- os: ubuntu-latest
|
|
label: Linux
|
|
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Bun
|
|
uses: oven-sh/setup-bun@v2
|
|
with:
|
|
bun-version: 1.3.6
|
|
|
|
- name: Set up .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: 9.0.x
|
|
|
|
- name: Install Linux native dependencies
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libsecret-1-dev
|
|
|
|
- name: Install dependencies
|
|
run: bun install --frozen-lockfile
|
|
|
|
- name: Prepare Apple signing assets
|
|
if: runner.os == 'macOS'
|
|
shell: bash
|
|
env:
|
|
APPLE_CERT_P12_BASE64: ${{ secrets.APPLE_CERT_P12_BASE64 }}
|
|
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
|
|
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
|
|
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
|
|
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
write_github_env() {
|
|
local name="$1"
|
|
local value="$2"
|
|
local delimiter
|
|
delimiter="ARYX_ENV_$(uuidgen | tr '[:lower:]' '[:upper:]')"
|
|
{
|
|
printf '%s<<%s\n' "$name" "$delimiter"
|
|
printf '%s\n' "$value"
|
|
printf '%s\n' "$delimiter"
|
|
} >> "$GITHUB_ENV"
|
|
}
|
|
|
|
if [[ -z "$APPLE_CERT_P12_BASE64" ]]; then
|
|
echo "Missing required secret: APPLE_CERT_P12_BASE64" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$APPLE_CERT_PASSWORD" ]]; then
|
|
echo "Missing required secret: APPLE_CERT_PASSWORD" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$APPLE_API_KEY_P8" ]]; then
|
|
echo "Missing required secret: APPLE_API_KEY_P8" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$APPLE_API_KEY_ID" ]]; then
|
|
echo "Missing required secret: APPLE_API_KEY_ID" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$APPLE_API_ISSUER" ]]; then
|
|
echo "Missing required secret: APPLE_API_ISSUER" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$APPLE_TEAM_ID" ]]; then
|
|
echo "Missing required secret: APPLE_TEAM_ID" >&2
|
|
exit 1
|
|
fi
|
|
|
|
SOURCE_CERT_PATH="$RUNNER_TEMP/apple-signing-source.p12"
|
|
CERT_PATH="$RUNNER_TEMP/apple-signing.p12"
|
|
PEM_PATH="$RUNNER_TEMP/apple-signing.pem"
|
|
PRECHECK_KEYCHAIN_PATH="$RUNNER_TEMP/apple-signing-preflight.keychain-db"
|
|
PRECHECK_KEYCHAIN_PASSWORD="$(uuidgen)"
|
|
API_KEY_PATH="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY_ID}.p8"
|
|
|
|
cleanup_precheck_keychain() {
|
|
security delete-keychain "$PRECHECK_KEYCHAIN_PATH" >/dev/null 2>&1 || true
|
|
}
|
|
|
|
trap cleanup_precheck_keychain EXIT
|
|
|
|
CERT_PATH="$SOURCE_CERT_PATH" python3 - <<'PY'
|
|
import base64
|
|
import binascii
|
|
import os
|
|
from pathlib import Path
|
|
|
|
raw_value = os.environ["APPLE_CERT_P12_BASE64"]
|
|
normalized_value = "".join(raw_value.split())
|
|
if not normalized_value:
|
|
raise SystemExit("APPLE_CERT_P12_BASE64 is empty after whitespace normalization")
|
|
|
|
try:
|
|
decoded = base64.b64decode(normalized_value, validate=True)
|
|
except binascii.Error:
|
|
raise SystemExit("APPLE_CERT_P12_BASE64 is not valid base64")
|
|
|
|
if not decoded:
|
|
raise SystemExit("Decoded Apple signing certificate is empty")
|
|
|
|
Path(os.environ["CERT_PATH"]).write_bytes(decoded)
|
|
PY
|
|
printf '%s' "$APPLE_API_KEY_P8" > "$API_KEY_PATH"
|
|
|
|
if [[ ! -s "$SOURCE_CERT_PATH" ]]; then
|
|
echo "Decoded Apple signing certificate file is empty." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! openssl pkcs12 -in "$SOURCE_CERT_PATH" -noout -passin env:APPLE_CERT_PASSWORD >/dev/null 2>&1; then
|
|
echo "Decoded Apple signing certificate could not be opened with APPLE_CERT_PASSWORD." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! openssl pkcs12 -in "$SOURCE_CERT_PATH" -passin env:APPLE_CERT_PASSWORD -nodes -out "$PEM_PATH" >/dev/null 2>&1; then
|
|
echo "Decoded Apple signing certificate could not be converted to PEM." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! openssl pkcs12 -export -out "$CERT_PATH" -in "$PEM_PATH" -passout env:APPLE_CERT_PASSWORD -macalg sha1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES >/dev/null 2>&1; then
|
|
echo "Apple signing certificate could not be re-exported into a macOS-compatible PKCS#12." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -s "$CERT_PATH" ]]; then
|
|
echo "Normalized Apple signing certificate file is empty." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! security create-keychain -p "$PRECHECK_KEYCHAIN_PASSWORD" "$PRECHECK_KEYCHAIN_PATH" >/dev/null 2>&1; then
|
|
echo "Unable to create the macOS signing precheck keychain." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! security unlock-keychain -p "$PRECHECK_KEYCHAIN_PASSWORD" "$PRECHECK_KEYCHAIN_PATH" >/dev/null 2>&1; then
|
|
echo "Unable to unlock the macOS signing precheck keychain." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! security import "$CERT_PATH" -k "$PRECHECK_KEYCHAIN_PATH" -P "$APPLE_CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign >/dev/null 2>&1; then
|
|
echo "Normalized Apple signing certificate is still not importable by macOS security." >&2
|
|
exit 1
|
|
fi
|
|
|
|
rm -f "$SOURCE_CERT_PATH" "$PEM_PATH"
|
|
cleanup_precheck_keychain
|
|
trap - EXIT
|
|
|
|
write_github_env "CSC_LINK" "$CERT_PATH"
|
|
write_github_env "CSC_KEY_PASSWORD" "$APPLE_CERT_PASSWORD"
|
|
write_github_env "APPLE_API_KEY" "$API_KEY_PATH"
|
|
write_github_env "APPLE_API_KEY_ID" "$APPLE_API_KEY_ID"
|
|
write_github_env "APPLE_API_ISSUER" "$APPLE_API_ISSUER"
|
|
write_github_env "APPLE_TEAM_ID" "$APPLE_TEAM_ID"
|
|
|
|
- name: Build and publish release artifacts
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: bun run publish-release
|