Skip to content
This repository was archived by the owner on May 24, 2026. It is now read-only.

Pin reset and chat_history.db path fix (#72) #54

Pin reset and chat_history.db path fix (#72)

Pin reset and chat_history.db path fix (#72) #54

Workflow file for this run

name: Build & Release
on:
push:
branches: [ main, develop ]
tags: [ 'v*' ]
pull_request:
branches: [ main ]
workflow_dispatch:
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
build-test:
name: Build & Test
runs-on: macos-26
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Select Xcode
run: |
if [ -d "/Applications/Xcode_26.2.app" ]; then
XCODE_PATH="/Applications/Xcode_26.2.app"
elif [ -d "/Applications/Xcode_26.2.0.app" ]; then
XCODE_PATH="/Applications/Xcode_26.2.0.app"
else
XCODE_PATH=$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -rV | head -1)
fi
echo "Selected Xcode: $XCODE_PATH"
sudo xcode-select -s "$XCODE_PATH"
xcodebuild -version
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
dotnet-quality: 'preview'
- name: Install MAUI workload
run: dotnet workload install maui
- name: Build tests
run: dotnet build PolyPilot.Tests --configuration Release
- name: Run tests
run: |
dotnet test PolyPilot.Tests \
--configuration Release \
--no-build \
--verbosity normal \
--logger "trx;LogFileName=test-results.trx"
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: '**/TestResults/*.trx'
retention-days: 7
publish-maccatalyst:
name: Publish Mac Catalyst App
runs-on: macos-26
needs: build-test
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
permissions:
statuses: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Select Xcode
run: |
ls -d /Applications/Xcode*.app 2>/dev/null
if [ -d "/Applications/Xcode_26.2.app" ]; then
XCODE_PATH="/Applications/Xcode_26.2.app"
elif [ -d "/Applications/Xcode_26.2.0.app" ]; then
XCODE_PATH="/Applications/Xcode_26.2.0.app"
else
XCODE_PATH=$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -rV | head -1)
fi
echo "Selected Xcode: $XCODE_PATH"
sudo xcode-select -s "$XCODE_PATH"
sudo xcodebuild -license accept 2>/dev/null || true
xcodebuild -version
echo "MD_APPLE_SDK_ROOT=$XCODE_PATH" >> $GITHUB_ENV
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
dotnet-quality: 'preview'
- name: Install MAUI workload
run: dotnet workload install maui
- name: Import signing certificate and provisioning profile
if: env.APPLE_CERTIFICATE_P12 != ''
env:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_PROVISIONING_PROFILE: ${{ secrets.APPLE_PROVISIONING_PROFILE }}
run: |
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
# Install provisioning profile (.provisionprofile for Mac Catalyst/macOS)
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
printenv APPLE_PROVISIONING_PROFILE | openssl base64 -d -A > $RUNNER_TEMP/profile.provisionprofile
PROFILE_UUID=$(/usr/libexec/PlistBuddy -c "Print UUID" /dev/stdin <<< $(security cms -D -i $RUNNER_TEMP/profile.provisionprofile))
cp $RUNNER_TEMP/profile.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/$PROFILE_UUID.provisionprofile
echo "Installed profile with UUID: $PROFILE_UUID"
# Create keychain and import certificate
printenv APPLE_CERTIFICATE_P12 | openssl base64 -d -A > $RUNNER_TEMP/certificate.p12
if [ ! -s $RUNNER_TEMP/certificate.p12 ]; then
echo "::error::Failed to decode APPLE_CERTIFICATE_P12 — check that the secret is valid base64"
exit 1
fi
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security import $RUNNER_TEMP/certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
echo "Certificate and profile setup complete."
- name: Determine version
id: version
run: |
SHA="${GITHUB_SHA::8}"
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
VER="${GITHUB_REF#refs/tags/v}"
else
VER="1.0"
fi
echo "app_version=$VER" >> $GITHUB_OUTPUT
echo "commit_sha=$SHA" >> $GITHUB_OUTPUT
echo "Version: $VER+$SHA"
- name: Publish Mac Catalyst App (Signed)
if: env.APPLE_CERTIFICATE_P12 != ''
env:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
APPLE_PROVISIONING_PROFILE_NAME: ${{ secrets.APPLE_PROVISIONING_PROFILE_NAME }}
run: |
dotnet publish PolyPilot/PolyPilot.csproj \
-f net10.0-maccatalyst \
-c Release \
-p:CreatePackage=false \
-p:EnableCodeSigning=true \
-p:CodesignKey="$APPLE_CODESIGN_IDENTITY" \
-p:CodesignProvision="$APPLE_PROVISIONING_PROFILE_NAME" \
-p:ApplicationDisplayVersion=${{ steps.version.outputs.app_version }}
mkdir -p ./artifacts/maccatalyst
cp -R PolyPilot/bin/Release/net10.0-maccatalyst/PolyPilot.app ./artifacts/maccatalyst/
- name: Re-sign with Hardened Runtime
if: env.APPLE_CERTIFICATE_P12 != ''
env:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
run: |
APP_PATH=$(find ./artifacts/maccatalyst -name "*.app" -type d | head -1)
if [ -n "$APP_PATH" ]; then
echo "Re-signing with hardened runtime: $APP_PATH"
# Sign all nested dylibs/frameworks first (inside-out)
find "$APP_PATH" -type f \( -name "*.dylib" -o -name "*.so" \) | while read f; do
echo " Signing: $f"
codesign --force --options runtime --timestamp \
--sign "$APPLE_CODESIGN_IDENTITY" "$f"
done
find "$APP_PATH" -type d -name "*.framework" | while read f; do
echo " Signing: $f"
codesign --force --options runtime --timestamp \
--sign "$APPLE_CODESIGN_IDENTITY" "$f"
done
# Sign the top-level app bundle
codesign --force --options runtime --timestamp \
--entitlements PolyPilot/Platforms/MacCatalyst/Entitlements.plist \
--sign "$APPLE_CODESIGN_IDENTITY" \
"$APP_PATH"
fi
- name: Publish Mac Catalyst App (Unsigned)
if: env.APPLE_CERTIFICATE_P12 == ''
env:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
run: |
dotnet publish PolyPilot/PolyPilot.csproj \
-f net10.0-maccatalyst \
-c Release \
-p:CreatePackage=false \
-p:EnableCodeSigning=false \
-p:ApplicationDisplayVersion=${{ steps.version.outputs.app_version }}
mkdir -p ./artifacts/maccatalyst
cp -R PolyPilot/bin/Release/net10.0-maccatalyst/PolyPilot.app ./artifacts/maccatalyst/
- name: Verify code signature
if: env.APPLE_CERTIFICATE_P12 != ''
env:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
run: |
APP_PATH=$(find ./artifacts/maccatalyst -name "*.app" -type d | head -1)
if [ -n "$APP_PATH" ]; then
echo "Verifying signature for: $APP_PATH"
codesign -dvv "$APP_PATH" 2>&1 | tee /tmp/codesign-output.txt
if grep -q "flags=0x10000(runtime)" /tmp/codesign-output.txt; then
echo "✅ Hardened Runtime is enabled"
else
echo "::error::Hardened Runtime is NOT enabled — notarization will fail"
exit 1
fi
fi
- name: Create ZIP archive
run: |
APP_PATH=$(find ./artifacts/maccatalyst -name "*.app" -type d | head -1)
if [ -n "$APP_PATH" ]; then
ditto -c -k --keepParent "$APP_PATH" ./artifacts/PolyPilot.zip
echo "Created archive: ./artifacts/PolyPilot.zip"
ls -lh ./artifacts/PolyPilot.zip
else
echo "No .app bundle found, creating archive of all artifacts"
cd ./artifacts/maccatalyst && zip -r ../PolyPilot.zip .
fi
- name: Upload Mac Catalyst App
uses: actions/upload-artifact@v4
with:
name: PolyPilot.app
path: ./artifacts/PolyPilot.zip
retention-days: 30
- name: Set commit status with artifact link
if: always()
env:
GH_TOKEN: ${{ github.token }}
run: |
ARTIFACT_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
if [ -f "./artifacts/PolyPilot.zip" ]; then
STATE="success"
DESC="PolyPilot.app built successfully"
else
STATE="failure"
DESC="PolyPilot.app build failed"
fi
gh api repos/${{ github.repository }}/statuses/${{ github.sha }} \
-f state="$STATE" \
-f target_url="$ARTIFACT_URL" \
-f description="$DESC" \
-f context="PolyPilot / Download App"
- name: Cleanup keychain
if: always()
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true
rm -f $RUNNER_TEMP/certificate.p12 $RUNNER_TEMP/profile.provisionprofile || true
notarize-maccatalyst:
name: Notarize Mac Catalyst App
runs-on: macos-26
needs: publish-maccatalyst
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Download Mac Catalyst artifact
uses: actions/download-artifact@v4
with:
name: PolyPilot.app
path: ./artifacts
- name: Notarize with retry
env:
APPLE_NOTARIZATION_APPLE_ID: ${{ secrets.APPLE_NOTARIZATION_APPLE_ID }}
APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
APPLE_NOTARIZATION_TEAM_ID: ${{ secrets.APPLE_NOTARIZATION_TEAM_ID }}
run: |
mkdir -p ./artifacts/maccatalyst
ditto -x -k ./artifacts/PolyPilot.zip ./artifacts/maccatalyst
APP_PATH=$(find ./artifacts/maccatalyst -name "*.app" -type d | head -1)
if [ -z "$APP_PATH" ]; then
echo "::error::No .app bundle found in artifact"
exit 1
fi
ditto -c -k --keepParent "$APP_PATH" ./artifacts/notarize.zip
MAX_RETRIES=3
RETRY_DELAY=30
for i in $(seq 1 $MAX_RETRIES); do
echo "Notarization attempt $i of $MAX_RETRIES..."
if xcrun notarytool submit ./artifacts/notarize.zip \
--apple-id "$APPLE_NOTARIZATION_APPLE_ID" \
--password "$APPLE_NOTARIZATION_PASSWORD" \
--team-id "$APPLE_NOTARIZATION_TEAM_ID" \
--wait; then
echo "Notarization succeeded on attempt $i"
break
fi
if [ $i -lt $MAX_RETRIES ]; then
echo "Attempt $i failed, retrying in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
RETRY_DELAY=$((RETRY_DELAY * 2))
else
echo "::error::Notarization failed after $MAX_RETRIES attempts"
exit 1
fi
done
rm ./artifacts/notarize.zip
xcrun stapler staple "$APP_PATH"
rm ./artifacts/PolyPilot.zip
ditto -c -k --keepParent "$APP_PATH" ./artifacts/PolyPilot.zip
echo "Created notarized archive"
ls -lh ./artifacts/PolyPilot.zip
- name: Upload notarized Mac Catalyst App
uses: actions/upload-artifact@v4
with:
name: PolyPilot.app
path: ./artifacts/PolyPilot.zip
overwrite: true
retention-days: 30
create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [notarize-maccatalyst]
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- name: Download Mac Catalyst artifact
uses: actions/download-artifact@v4
with:
name: PolyPilot.app
path: ./release
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
./release/PolyPilot.zip
generate_release_notes: false
draft: false
prerelease: ${{ contains(github.ref, '-') }}