Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 89 additions & 5 deletions .github/workflows/release-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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: |
Expand Down Expand Up @@ -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" \
Expand Down
13 changes: 13 additions & 0 deletions PolyPilot/Platforms/MacCatalyst/Entitlements.Helper.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Minimal entitlements for helper executables (e.g., bundled copilot CLI).
app-sandbox is required by Apple for ALL executables in App Store builds.
inherit means the helper inherits the parent app's sandbox permissions. -->
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
</dict>
</plist>
4 changes: 2 additions & 2 deletions PolyPilot/Platforms/MacCatalyst/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

<!-- Specify the category for your app here. -->
<!-- Please consult https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype -->
<!-- <key>LSApplicationCategoryType</key> -->
<!-- <string>public.app-category.YOUR-CATEGORY-HERE</string> -->
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>UIDeviceFamily</key>
<array>
<integer>2</integer>
Expand Down