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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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, '-') }} |