diff --git a/.github/workflows/release-apps.yml b/.github/workflows/release-apps.yml
index 2d44b2830..a4acee284 100644
--- a/.github/workflows/release-apps.yml
+++ b/.github/workflows/release-apps.yml
@@ -217,7 +217,7 @@ jobs:
cp "$RUNNER_TEMP/maccatalyst.provisionprofile" "$PP_PATH/$PROFILE_UUID.provisionprofile"
echo "Installed Mac Catalyst profile with UUID: $PROFILE_UUID"
- - name: Publish Mac Catalyst PKG
+ - name: Publish Mac Catalyst App
run: |
dotnet publish ${{ env.MAUI_PROJECT_PATH }} \
-f net10.0-maccatalyst \
@@ -226,13 +226,97 @@ jobs:
-p:CodesignKey="${{ secrets.IOS_CODESIGN_KEY }}" \
-p:CodesignProvision="${{ secrets.MACCATALYST_PROVISIONING_PROFILE_NAME }}" \
-p:CodesignEntitlements=Platforms/MacCatalyst/Entitlements.AppStore.plist \
- -p:CreatePackage=true \
+ -p:CreatePackage=false \
-p:EnableCodeSigning=true \
- -p:EnablePackageSigning=true \
- -p:PackageSigningKey="${{ secrets.MACCATALYST_INSTALLER_SIGNING_KEY }}" \
-p:ApplicationDisplayVersion='${{ env.APP_VERSION }}' \
-p:ApplicationVersion='${{ steps.build.outputs.number }}'
+ - name: Patch bundle identifier for App Store
+ run: |
+ APP_PATH=$(find PolyPilot/bin/Release/net10.0-maccatalyst -name "PolyPilot.app" -type d | head -1)
+ echo "App path: $APP_PATH"
+
+ # MAUI builds with maccatalyst.nl.versluis.polypilot to match the provisioning
+ # profile, but App Store Connect expects the base bundle ID without the prefix.
+ # Apple's tooling understands the maccatalyst. prefix convention in profiles,
+ # but the binary's CFBundleIdentifier must be the base ID.
+ PLIST="$APP_PATH/Contents/Info.plist"
+ CURRENT_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$PLIST")
+ echo "Current CFBundleIdentifier: $CURRENT_ID"
+
+ if [[ "$CURRENT_ID" == maccatalyst.* ]]; then
+ BASE_ID="${CURRENT_ID#maccatalyst.}"
+ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $BASE_ID" "$PLIST"
+ echo "Patched CFBundleIdentifier to: $BASE_ID"
+ else
+ echo "CFBundleIdentifier already uses base ID: $CURRENT_ID"
+ fi
+
+ - name: Re-sign app bundle (inside-out)
+ env:
+ CODESIGN_KEY: ${{ secrets.IOS_CODESIGN_KEY }}
+ run: |
+ APP_PATH=$(find PolyPilot/bin/Release/net10.0-maccatalyst -name "PolyPilot.app" -type d | head -1)
+ echo "App path: $APP_PATH"
+
+ # Sign the copilot CLI binary with minimal helper entitlements (sandbox + inherit)
+ COPILOT_BIN="$APP_PATH/Contents/MonoBundle/copilot"
+ if [ -f "$COPILOT_BIN" ]; then
+ echo "Signing bundled copilot binary..."
+ codesign --force --sign "$CODESIGN_KEY" \
+ --entitlements PolyPilot/Platforms/MacCatalyst/Entitlements.Helper.plist \
+ --options runtime --timestamp \
+ "$COPILOT_BIN"
+ else
+ echo "Warning: copilot binary not found at $COPILOT_BIN"
+ fi
+
+ # Re-sign all dylibs (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 "$CODESIGN_KEY" "$f"
+ done
+
+ # Re-sign frameworks
+ find "$APP_PATH" -type d -name "*.framework" | while read f; do
+ echo " Signing: $f"
+ codesign --force --options runtime --timestamp \
+ --sign "$CODESIGN_KEY" "$f"
+ done
+
+ # Re-sign the top-level app bundle with full app entitlements
+ codesign --force --sign "$CODESIGN_KEY" \
+ --entitlements PolyPilot/Platforms/MacCatalyst/Entitlements.AppStore.plist \
+ --options runtime --timestamp \
+ "$APP_PATH"
+
+ echo "=== Verify signature ==="
+ codesign --verify --deep --strict "$APP_PATH" 2>&1
+ echo "=== Signature details ==="
+ codesign -dvv "$APP_PATH" 2>&1 | head -20
+ echo "=== Verify copilot binary ==="
+ codesign -dvv "$COPILOT_BIN" 2>&1 | head -10
+
+ - name: Create and sign PKG
+ env:
+ PKG_SIGN_KEY: ${{ secrets.MACCATALYST_INSTALLER_SIGNING_KEY }}
+ run: |
+ APP_PATH=$(find PolyPilot/bin/Release/net10.0-maccatalyst -name "PolyPilot.app" -type d | head -1)
+ PKG_DIR="PolyPilot/bin/Release/net10.0-maccatalyst"
+
+ # Create component package
+ productbuild --component "$APP_PATH" /Applications \
+ "$PKG_DIR/PolyPilot-unsigned.pkg"
+
+ # Sign the package with Mac Installer certificate
+ productsign --sign "$PKG_SIGN_KEY" \
+ "$PKG_DIR/PolyPilot-unsigned.pkg" \
+ "$PKG_DIR/PolyPilot-${{ env.APP_VERSION }}.pkg"
+
+ rm "$PKG_DIR/PolyPilot-unsigned.pkg"
+ echo "Created signed PKG"
+
- name: Find PKG file
id: find_pkg
run: |
@@ -288,7 +372,7 @@ jobs:
xcrun altool --upload-package "$PKG_PATH" \
-t macos \
--apple-id "6759370598" \
- --bundle-id "maccatalyst.nl.versluis.polypilot" \
+ --bundle-id "nl.versluis.polypilot" \
--bundle-version "$BUILD_NUMBER" \
--bundle-short-version-string "$APP_VERSION" \
--apiKey "$APPSTORE_KEY_ID" \
diff --git a/PolyPilot/Platforms/MacCatalyst/Entitlements.Helper.plist b/PolyPilot/Platforms/MacCatalyst/Entitlements.Helper.plist
new file mode 100644
index 000000000..0bbc9f170
--- /dev/null
+++ b/PolyPilot/Platforms/MacCatalyst/Entitlements.Helper.plist
@@ -0,0 +1,13 @@
+
+
+
+
+
+ com.apple.security.app-sandbox
+
+ com.apple.security.inherit
+
+
+
diff --git a/PolyPilot/Platforms/MacCatalyst/Info.plist b/PolyPilot/Platforms/MacCatalyst/Info.plist
index ecac4e986..325cf53eb 100644
--- a/PolyPilot/Platforms/MacCatalyst/Info.plist
+++ b/PolyPilot/Platforms/MacCatalyst/Info.plist
@@ -9,8 +9,8 @@
-
-
+ LSApplicationCategoryType
+ public.app-category.developer-tools
UIDeviceFamily
2