mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-01-14 20:11:17 +01:00
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.4.2 to 2.5.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's releases</a>.</em></p> <blockquote> <h2>v2.5.0</h2> <!-- raw HTML omitted --> <h2>What's Changed</h2> <h3>Exciting New Features 🎉</h3> <ul> <li>feat: mark release as draft until all artifacts are uploaded by <a href="https://github.com/dumbmoron"><code>@dumbmoron</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/692">softprops/action-gh-release#692</a></li> </ul> <h3>Other Changes 🔄</h3> <ul> <li>chore(deps): bump the npm group across 1 directory with 5 updates by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/softprops/action-gh-release/pull/697">softprops/action-gh-release#697</a></li> <li>chore(deps): bump actions/checkout from 5.0.0 to 5.0.1 in the github-actions group by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/softprops/action-gh-release/pull/689">softprops/action-gh-release#689</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/dumbmoron"><code>@dumbmoron</code></a> made their first contribution in <a href="https://redirect.github.com/softprops/action-gh-release/pull/692">softprops/action-gh-release#692</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/softprops/action-gh-release/compare/v2.4.2...v2.5.0">https://github.com/softprops/action-gh-release/compare/v2.4.2...v2.5.0</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's changelog</a>.</em></p> <blockquote> <h2>2.5.0</h2> <h2>What's Changed</h2> <h3>Exciting New Features 🎉</h3> <ul> <li>feat: mark release as draft until all artifacts are uploaded by <a href="https://github.com/dumbmoron"><code>@dumbmoron</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/692">softprops/action-gh-release#692</a></li> </ul> <h3>Other Changes 🔄</h3> <ul> <li>dependency updates</li> </ul> <h2>2.4.2</h2> <h2>What's Changed</h2> <h3>Exciting New Features 🎉</h3> <ul> <li>feat: Ensure generated release notes cannot be over 125000 characters by <a href="https://github.com/BeryJu"><code>@BeryJu</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/684">softprops/action-gh-release#684</a></li> </ul> <h3>Other Changes 🔄</h3> <ul> <li>dependency updates</li> </ul> <h2>2.4.1</h2> <h2>What's Changed</h2> <h3>Other Changes 🔄</h3> <ul> <li>fix(util): support brace expansion globs containing commas in parseInputFiles by <a href="https://github.com/Copilot"><code>@Copilot</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/672">softprops/action-gh-release#672</a></li> <li>fix: gracefully fallback to body when body_path cannot be read by <a href="https://github.com/Copilot"><code>@Copilot</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/671">softprops/action-gh-release#671</a></li> </ul> <h2>2.4.0</h2> <h2>What's Changed</h2> <h3>Exciting New Features 🎉</h3> <ul> <li>feat(action): respect working_directory for files globs by <a href="https://github.com/stephenway"><code>@stephenway</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/667">softprops/action-gh-release#667</a></li> </ul> <h2>2.3.4</h2> <h2>What's Changed</h2> <h3>Bug fixes 🐛</h3> <ul> <li>fix(action): handle 422 already_exists race condition by <a href="https://github.com/stephenway"><code>@stephenway</code></a> in <a href="https://redirect.github.com/softprops/action-gh-release/pull/665">softprops/action-gh-release#665</a></li> </ul> <h3>Other Changes 🔄</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="a06a81a03e"><code>a06a81a</code></a> release 2.5.0</li> <li><a href="7da8983734"><code>7da8983</code></a> feat: mark release as draft until all artifacts are uploaded (<a href="https://redirect.github.com/softprops/action-gh-release/issues/692">#692</a>)</li> <li><a href="87973286a4"><code>8797328</code></a> chore(deps): bump actions/checkout in the github-actions group (<a href="https://redirect.github.com/softprops/action-gh-release/issues/689">#689</a>)</li> <li><a href="1bfc62a71b"><code>1bfc62a</code></a> chore(deps): bump the npm group across 1 directory with 5 updates (<a href="https://redirect.github.com/softprops/action-gh-release/issues/697">#697</a>)</li> <li>See full diff in <a href="5be0e66d93...a06a81a03e">compare view</a></li> </ul> </details> <br /> <details> <summary>Most Recent Ignore Conditions Applied to This Pull Request</summary> | Dependency Name | Ignore Conditions | | --- | --- | | softprops/action-gh-release | [>= 2.2.a, < 2.3] | </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
536 lines
23 KiB
YAML
536 lines
23 KiB
YAML
name: Release Artifacts
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
platform:
|
|
description: "Platform to build (windows, macos, linux, or all)"
|
|
required: true
|
|
default: "all"
|
|
type: choice
|
|
options:
|
|
- all
|
|
- windows
|
|
- macos
|
|
- linux
|
|
push:
|
|
branches: [main, V2, V2-demo]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
determine-matrix:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
version: ${{ steps.versionNumber.outputs.versionNumber }}
|
|
steps:
|
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
|
|
- name: Get version number
|
|
id: versionNumber
|
|
run: |
|
|
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
|
|
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
|
|
|
|
- name: Determine build matrix
|
|
id: set-matrix
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
case "${{ github.event.inputs.platform }}" in
|
|
"windows")
|
|
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64"}]}' >> $GITHUB_OUTPUT
|
|
;;
|
|
"macos")
|
|
echo 'matrix={"include":[{"platform":"macos-15","args":"--target aarch64-apple-darwin","name":"macos-aarch64"},{"platform":"macos-15-intel","args":"--target x86_64-apple-darwin","name":"macos-x86_64"}]}' >> $GITHUB_OUTPUT
|
|
;;
|
|
"linux")
|
|
echo 'matrix={"include":[{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64"}]}' >> $GITHUB_OUTPUT
|
|
;;
|
|
*)
|
|
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64"},{"platform":"macos-15","args":"--target aarch64-apple-darwin","name":"macos-aarch64"},{"platform":"macos-15-intel","args":"--target x86_64-apple-darwin","name":"macos-x86_64"},{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64"}]}' >> $GITHUB_OUTPUT
|
|
;;
|
|
esac
|
|
else
|
|
# For push events, build all platforms
|
|
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64"},{"platform":"macos-15","args":"--target aarch64-apple-darwin","name":"macos-aarch64"},{"platform":"macos-15-intel","args":"--target x86_64-apple-darwin","name":"macos-x86_64"},{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64"}]}' >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
build:
|
|
needs: determine-matrix
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJson(needs.determine-matrix.outputs.matrix) }}
|
|
runs-on: ${{ matrix.platform }}
|
|
env:
|
|
SM_API_KEY: ${{ secrets.SM_API_KEY }}
|
|
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Checkout repository
|
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
|
|
|
- name: Install dependencies (ubuntu only)
|
|
if: matrix.platform == 'ubuntu-22.04'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libjavascriptcoregtk-4.0-dev libsoup2.4-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: 'npm'
|
|
cache-dependency-path: frontend/package-lock.json
|
|
|
|
- name: Setup Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
toolchain: stable
|
|
targets: ${{ (matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
|
|
|
|
- name: Set up JDK 21
|
|
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
|
|
with:
|
|
java-version: "21"
|
|
distribution: "temurin"
|
|
|
|
- name: Build Java backend with JLink
|
|
working-directory: ./
|
|
shell: bash
|
|
run: |
|
|
chmod +x ./gradlew
|
|
echo "🔧 Building Stirling-PDF JAR..."
|
|
./gradlew clean build -x spotlessApply -x spotlessCheck -x test -x sonarqube
|
|
|
|
# Find the built JAR
|
|
STIRLING_JAR=$(ls app/core/build/libs/stirling-pdf-*.jar | head -n 1)
|
|
echo "✅ Built JAR: $STIRLING_JAR"
|
|
|
|
# Create Tauri directories
|
|
mkdir -p ./frontend/src-tauri/libs
|
|
mkdir -p ./frontend/src-tauri/runtime
|
|
|
|
# Copy JAR to Tauri libs
|
|
cp "$STIRLING_JAR" ./frontend/src-tauri/libs/
|
|
echo "✅ JAR copied to Tauri libs"
|
|
|
|
# Analyze JAR dependencies for jlink modules
|
|
echo "🔍 Analyzing JAR dependencies..."
|
|
if command -v jdeps &> /dev/null; then
|
|
DETECTED_MODULES=$(jdeps --print-module-deps --ignore-missing-deps "$STIRLING_JAR" 2>/dev/null || echo "")
|
|
if [ -n "$DETECTED_MODULES" ]; then
|
|
echo "📋 jdeps detected modules: $DETECTED_MODULES"
|
|
MODULES="$DETECTED_MODULES,java.compiler,java.instrument,java.management,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.security.jgss,java.security.sasl,java.sql,java.transaction.xa,java.xml.crypto,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported"
|
|
else
|
|
echo "⚠️ jdeps analysis failed, using predefined modules"
|
|
MODULES="java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.security.jgss,java.security.sasl,java.sql,java.transaction.xa,java.xml,java.xml.crypto,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported"
|
|
fi
|
|
else
|
|
echo "⚠️ jdeps not available, using predefined modules"
|
|
MODULES="java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.security.jgss,java.security.sasl,java.sql,java.transaction.xa,java.xml,java.xml.crypto,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported"
|
|
fi
|
|
|
|
# Create custom JRE with jlink
|
|
echo "🔧 Creating custom JRE with jlink..."
|
|
echo "📋 Using modules: $MODULES"
|
|
|
|
# Remove any existing JRE
|
|
rm -rf ./frontend/src-tauri/runtime/jre
|
|
|
|
# Create the custom JRE
|
|
jlink \
|
|
--add-modules "$MODULES" \
|
|
--strip-debug \
|
|
--compress=2 \
|
|
--no-header-files \
|
|
--no-man-pages \
|
|
--output ./frontend/src-tauri/runtime/jre
|
|
|
|
if [ ! -d "./frontend/src-tauri/runtime/jre" ]; then
|
|
echo "❌ Failed to create JLink runtime"
|
|
exit 1
|
|
fi
|
|
|
|
# Test the bundled runtime
|
|
if [ -f "./frontend/src-tauri/runtime/jre/bin/java" ]; then
|
|
RUNTIME_VERSION=$(./frontend/src-tauri/runtime/jre/bin/java --version 2>&1 | head -n 1)
|
|
echo "✅ Custom JRE created successfully: $RUNTIME_VERSION"
|
|
else
|
|
echo "❌ Custom JRE executable not found"
|
|
exit 1
|
|
fi
|
|
|
|
# Calculate runtime size
|
|
RUNTIME_SIZE=$(du -sh ./frontend/src-tauri/runtime/jre | cut -f1)
|
|
echo "📊 Custom JRE size: $RUNTIME_SIZE"
|
|
env:
|
|
DISABLE_ADDITIONAL_FEATURES: true
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: ./frontend
|
|
run: npm install
|
|
|
|
# DigiCert KeyLocker Setup (Cloud HSM)
|
|
- name: Setup DigiCert KeyLocker
|
|
id: digicert-setup
|
|
if: ${{ matrix.platform == 'windows-latest' && env.SM_API_KEY != '' && github.ref == 'refs/heads/main' }}
|
|
uses: digicert/ssm-code-signing@v1.1.0
|
|
env:
|
|
SM_API_KEY: ${{ secrets.SM_API_KEY }}
|
|
SM_CLIENT_CERT_FILE_B64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }}
|
|
SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }}
|
|
SM_KEYPAIR_ALIAS: ${{ secrets.SM_KEYPAIR_ALIAS }}
|
|
SM_HOST: ${{ secrets.SM_HOST }}
|
|
|
|
- name: Setup DigiCert KeyLocker Certificate
|
|
if: ${{ matrix.platform == 'windows-latest' && env.SM_API_KEY != '' && github.ref == 'refs/heads/main' }}
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "Setting up DigiCert KeyLocker environment..."
|
|
|
|
# Decode client certificate
|
|
$certBytes = [Convert]::FromBase64String("${{ secrets.SM_CLIENT_CERT_FILE_B64 }}")
|
|
$certPath = "D:\Certificate_pkcs12.p12"
|
|
[IO.File]::WriteAllBytes($certPath, $certBytes)
|
|
|
|
# Set environment variables
|
|
echo "SM_CLIENT_CERT_FILE=D:\Certificate_pkcs12.p12" >> $env:GITHUB_ENV
|
|
echo "SM_HOST=${{ secrets.SM_HOST }}" >> $env:GITHUB_ENV
|
|
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> $env:GITHUB_ENV
|
|
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> $env:GITHUB_ENV
|
|
echo "SM_KEYPAIR_ALIAS=${{ secrets.SM_KEYPAIR_ALIAS }}" >> $env:GITHUB_ENV
|
|
|
|
# Get PKCS11 config path from DigiCert action
|
|
$pkcs11Config = $env:PKCS11_CONFIG
|
|
if ($pkcs11Config) {
|
|
Write-Host "Found PKCS11_CONFIG: $pkcs11Config"
|
|
echo "PKCS11_CONFIG=$pkcs11Config" >> $env:GITHUB_ENV
|
|
} else {
|
|
Write-Host "PKCS11_CONFIG not set by DigiCert action, using default path"
|
|
$defaultPath = "C:\Users\RUNNER~1\AppData\Local\Temp\smtools-windows-x64\pkcs11properties.cfg"
|
|
if (Test-Path $defaultPath) {
|
|
Write-Host "Found config at default path: $defaultPath"
|
|
echo "PKCS11_CONFIG=$defaultPath" >> $env:GITHUB_ENV
|
|
} else {
|
|
Write-Host "Warning: Could not find PKCS11 config file"
|
|
}
|
|
}
|
|
|
|
# Traditional PFX Certificate Import (fallback if KeyLocker not configured)
|
|
- name: Import Windows Code Signing Certificate
|
|
if: ${{ matrix.platform == 'windows-latest' && env.SM_API_KEY == '' && github.ref == 'refs/heads/main' }}
|
|
env:
|
|
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
|
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
|
shell: powershell
|
|
run: |
|
|
if ($env:WINDOWS_CERTIFICATE) {
|
|
Write-Host "Importing Windows Code Signing Certificate..."
|
|
|
|
# Decode base64 certificate and save to file
|
|
$certBytes = [Convert]::FromBase64String($env:WINDOWS_CERTIFICATE)
|
|
$certPath = Join-Path $env:RUNNER_TEMP "certificate.pfx"
|
|
[IO.File]::WriteAllBytes($certPath, $certBytes)
|
|
|
|
# Import certificate to CurrentUser\My store
|
|
$cert = Import-PfxCertificate -FilePath $certPath -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -AsPlainText -Force)
|
|
|
|
# Extract and set thumbprint as environment variable
|
|
$thumbprint = $cert.Thumbprint
|
|
Write-Host "Certificate imported with thumbprint: $thumbprint"
|
|
echo "WINDOWS_CERTIFICATE_THUMBPRINT=$thumbprint" >> $env:GITHUB_ENV
|
|
|
|
# Clean up certificate file
|
|
Remove-Item $certPath
|
|
|
|
Write-Host "Windows certificate import completed."
|
|
} else {
|
|
Write-Host "⚠️ WINDOWS_CERTIFICATE secret not set - building unsigned binary"
|
|
}
|
|
|
|
- name: Import Apple Developer Certificate
|
|
if: matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel'
|
|
env:
|
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
run: |
|
|
echo "Importing Apple Developer Certificate..."
|
|
echo $APPLE_CERTIFICATE | base64 --decode > certificate.p12
|
|
# Create temporary keychain
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
# Import certificate
|
|
security import certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
|
# Clean up
|
|
rm certificate.p12
|
|
|
|
- name: Verify Certificate
|
|
if: matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel'
|
|
run: |
|
|
echo "Verifying Apple Developer Certificate..."
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
CERT_INFO=$(security find-identity -v -p codesigning $KEYCHAIN_PATH | grep "Developer ID Application")
|
|
echo "Certificate Info: $CERT_INFO"
|
|
CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}')
|
|
echo "Certificate ID: $CERT_ID"
|
|
echo "APPLE_SIGNING_IDENTITY=$CERT_ID" >> $GITHUB_ENV
|
|
echo "Certificate imported successfully."
|
|
|
|
- name: Build Tauri app
|
|
uses: tauri-apps/tauri-action@v0
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
APPIMAGETOOL_SIGN_PASSPHRASE: ${{ secrets.APPIMAGETOOL_SIGN_PASSPHRASE }}
|
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
|
VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY: ${{ secrets.VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY }}
|
|
VITE_SAAS_SERVER_URL: ${{ secrets.VITE_SAAS_SERVER_URL }}
|
|
# Only enable Windows signing in Tauri when on main
|
|
SIGN: ${{ github.ref == 'refs/heads/main' && (env.SM_API_KEY == '' && env.WINDOWS_CERTIFICATE != '') && '1' || '0' }}
|
|
CI: true
|
|
with:
|
|
projectPath: ./frontend
|
|
tauriScript: npx tauri
|
|
args: ${{ matrix.args }}
|
|
|
|
# Sign with DigiCert KeyLocker (post-build)
|
|
- name: Sign Windows binaries with DigiCert KeyLocker
|
|
if: ${{ matrix.platform == 'windows-latest' && env.SM_API_KEY != '' && github.ref == 'refs/heads/main' }}
|
|
shell: pwsh
|
|
run: |
|
|
Write-Host "=== DigiCert KeyLocker Signing ==="
|
|
|
|
# Test smctl connectivity first
|
|
Write-Host "Testing smctl connection..."
|
|
$healthCheck = & smctl healthcheck 2>&1
|
|
if ($LASTEXITCODE -eq 0) {
|
|
Write-Host "[SUCCESS] Connected to DigiCert KeyLocker"
|
|
} else {
|
|
Write-Host "[ERROR] Failed to connect to DigiCert KeyLocker"
|
|
Write-Host $healthCheck
|
|
exit 1
|
|
}
|
|
Write-Host ""
|
|
|
|
# Sync certificates to Windows certificate store
|
|
Write-Host "Syncing certificates to Windows certificate store..."
|
|
$syncOutput = & smctl windows certsync 2>&1
|
|
Write-Host "Cert sync result: $syncOutput"
|
|
Write-Host ""
|
|
|
|
# Find only the files we need to sign (not build scripts)
|
|
$filesToSign = @()
|
|
|
|
# Main application executable
|
|
$mainExe = Get-ChildItem -Path "./frontend/src-tauri/target/x86_64-pc-windows-msvc/release" -Filter "stirling-pdf.exe" -File -ErrorAction SilentlyContinue
|
|
if ($mainExe) { $filesToSign += $mainExe }
|
|
|
|
# MSI installer
|
|
$msiFiles = Get-ChildItem -Path "./frontend/src-tauri/target" -Filter "*.msi" -Recurse -File
|
|
$filesToSign += $msiFiles
|
|
|
|
if ($filesToSign.Count -eq 0) {
|
|
Write-Host "[ERROR] No files found to sign"
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "Found $($filesToSign.Count) files to sign:"
|
|
foreach ($f in $filesToSign) { Write-Host " - $($f.Name)" }
|
|
Write-Host ""
|
|
|
|
$signedCount = 0
|
|
foreach ($file in $filesToSign) {
|
|
Write-Host "Signing: $($file.Name)"
|
|
|
|
# Get PKCS11 config file path (set by DigiCert action)
|
|
$pkcs11Config = $env:PKCS11_CONFIG
|
|
if (-not $pkcs11Config) {
|
|
Write-Host "[ERROR] PKCS11_CONFIG environment variable not set"
|
|
Write-Host "DigiCert KeyLocker action may not have run correctly"
|
|
exit 1
|
|
}
|
|
|
|
Write-Host "Using PKCS11 config: $pkcs11Config"
|
|
|
|
# Try signing with certificate fingerprint first (if available)
|
|
$fingerprint = "${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}"
|
|
if ($fingerprint -and $fingerprint -ne "") {
|
|
Write-Host "Attempting to sign with certificate fingerprint..."
|
|
$output = & smctl sign --fingerprint "$fingerprint" --input "$($file.FullName)" --config-file "$pkcs11Config" --verbose 2>&1
|
|
$exitCode = $LASTEXITCODE
|
|
} else {
|
|
Write-Host "No fingerprint provided, using keypair alias..."
|
|
# Use smctl to sign with keypair alias
|
|
$output = & smctl sign --keypair-alias "${{ secrets.SM_KEYPAIR_ALIAS }}" --input "$($file.FullName)" --config-file "$pkcs11Config" --verbose 2>&1
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
|
|
Write-Host "Exit code: $exitCode"
|
|
Write-Host "Output: $output"
|
|
|
|
# Check if output contains "FAILED" even with exit code 0
|
|
if ($output -match "FAILED" -or $output -match "error" -or $output -match "Error") {
|
|
Write-Host ""
|
|
Write-Host "[ERROR] Signing failed for $($file.Name)"
|
|
Write-Host "[ERROR] smctl returned success but output indicates failure"
|
|
exit 1
|
|
}
|
|
|
|
if ($exitCode -ne 0) {
|
|
Write-Host "[ERROR] Failed to sign $($file.Name)"
|
|
Write-Host "Full error output:"
|
|
Write-Host $output
|
|
exit 1
|
|
}
|
|
|
|
$signedCount++
|
|
Write-Host "[SUCCESS] Signed: $($file.Name)"
|
|
Write-Host ""
|
|
}
|
|
|
|
Write-Host "=== Summary ==="
|
|
Write-Host "[SUCCESS] Signed $signedCount/$($filesToSign.Count) files successfully"
|
|
|
|
- name: Rename artifacts
|
|
shell: bash
|
|
run: |
|
|
mkdir -p ./dist
|
|
cd ./frontend/src-tauri/target
|
|
|
|
# Find and rename artifacts based on platform
|
|
if [ "${{ matrix.platform }}" = "windows-latest" ]; then
|
|
find . -name "*.exe" -exec cp {} "../../../dist/Stirling-PDF-${{ matrix.name }}.exe" \;
|
|
find . -name "*.msi" -exec cp {} "../../../dist/Stirling-PDF-${{ matrix.name }}.msi" \;
|
|
elif [ "${{ matrix.platform }}" = "macos-15" ] || [ "${{ matrix.platform }}" = "macos-15-intel" ]; then
|
|
find . -name "*.dmg" -exec cp {} "../../../dist/Stirling-PDF-${{ matrix.name }}.dmg" \;
|
|
find . -name "*.app" -exec cp -r {} "../../../dist/Stirling-PDF-${{ matrix.name }}.app" \;
|
|
else
|
|
find . -name "*.deb" -exec cp {} "../../../dist/Stirling-PDF-${{ matrix.name }}.deb" \;
|
|
find . -name "*.AppImage" -exec cp {} "../../../dist/Stirling-PDF-${{ matrix.name }}.AppImage" \;
|
|
fi
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: Stirling-PDF-${{ matrix.name }}
|
|
path: ./dist/*
|
|
retention-days: 30
|
|
|
|
sign_verify:
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
if: success()
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
name: [windows-x86_64, macos-aarch64, macos-x86_64, linux-x86_64]
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Download build artifacts
|
|
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
with:
|
|
name: Stirling-PDF-${{ matrix.name }}
|
|
|
|
- name: Display structure of downloaded files
|
|
run: ls -R
|
|
|
|
- name: Install Cosign
|
|
uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.0
|
|
|
|
- name: Generate key pair
|
|
run: cosign generate-key-pair
|
|
|
|
- name: Sign and generate attestations
|
|
shell: bash
|
|
run: |
|
|
# Sign all artifacts for this platform
|
|
for file in *; do
|
|
if [ -f "$file" ] && [[ ! "$file" =~ \.(sig|intoto\.jsonl)$ ]]; then
|
|
echo "Signing: $file"
|
|
|
|
# Sign the artifact
|
|
cosign sign-blob \
|
|
--key ./cosign.key \
|
|
--yes \
|
|
--output-signature "${file}.sig" \
|
|
"$file"
|
|
|
|
# Generate attestation
|
|
cosign attest-blob \
|
|
--predicate - \
|
|
--key ./cosign.key \
|
|
--yes \
|
|
--output-attestation "${file}.intoto.jsonl" \
|
|
"$file"
|
|
|
|
# Verify the signature
|
|
cosign verify-blob \
|
|
--key ./cosign.pub \
|
|
--signature "${file}.sig" \
|
|
"$file"
|
|
|
|
echo "✅ Signed and verified: $file"
|
|
fi
|
|
done
|
|
|
|
- name: Upload signed artifacts
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
with:
|
|
name: Stirling-PDF-${{ matrix.name }}-signed
|
|
path: |
|
|
*
|
|
!cosign.key
|
|
!cosign.pub
|
|
retention-days: 30
|
|
|
|
release:
|
|
needs: [determine-matrix, build, sign_verify]
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name == 'workflow_dispatch' || github.ref == 'refs/heads/main'
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Harden Runner
|
|
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
|
|
with:
|
|
egress-policy: audit
|
|
|
|
- name: Download all signed artifacts
|
|
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
with:
|
|
pattern: Stirling-PDF-*-signed
|
|
path: ./artifacts
|
|
|
|
- name: Display structure of downloaded files
|
|
run: ls -R ./artifacts
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
|
with:
|
|
tag_name: v${{ needs.determine-matrix.outputs.version }}
|
|
generate_release_notes: true
|
|
files: ./artifacts/**/*
|
|
draft: false
|
|
prerelease: false
|