From 63f469e069f5d71f56865e04364315850304516a Mon Sep 17 00:00:00 2001 From: Chris Busillo Date: Fri, 15 May 2026 18:00:40 -0400 Subject: [PATCH 1/2] Accept App Store profile app group wildcards --- docs/release.md | 4 +- scripts/upload-testflight-macos-app.sh | 52 ++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/docs/release.md b/docs/release.md index 0482194..bb4d2b7 100644 --- a/docs/release.md +++ b/docs/release.md @@ -101,7 +101,9 @@ The app and refresh-agent App Store entitlements must keep the sandbox enabled with App Group, outbound network, read-only user-selected file access, and app-scope bookmark permissions. The widget should keep only the sandbox and App Group entitlements. The TestFlight upload script fails early when any supplied -provisioning profile is missing the Context Panel App Group. +provisioning profile does not authorize the Context Panel App Group; App Store +profiles may express that authorization as either the exact app group or a +same-team wildcard. ## Build The Native App And Widget diff --git a/scripts/upload-testflight-macos-app.sh b/scripts/upload-testflight-macos-app.sh index aec1202..eb1dfd6 100755 --- a/scripts/upload-testflight-macos-app.sh +++ b/scripts/upload-testflight-macos-app.sh @@ -135,16 +135,59 @@ profile_uuid() { rm -f "$plist" } +plist_array_contains_authorized_value() { + local plist="$1" + local key="$2" + local required_value="$3" + local values + local value + local wildcard_prefix + values="$(/usr/libexec/PlistBuddy -c "Print :$key" "$plist" 2>/dev/null || true)" + while IFS= read -r value; do + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + [[ -n "$value" && "$value" != "Array {" && "$value" != "}" ]] || continue + if [[ "$value" == "$required_value" ]]; then + return 0 + fi + if [[ "$value" == *'.*' ]]; then + wildcard_prefix="${value%\*}" + if [[ "$required_value" == "$wildcard_prefix"* ]]; then + return 0 + fi + fi + done <<<"$values" + return 1 +} + +assert_profile_bundle_id() { + local profile="$1" + local label="$2" + local bundle_id="$3" + local plist + local expected_app_id + local profile_app_id + plist="$(mktemp)" + security cms -D -i "$profile" -o "$plist" + expected_app_id="$team_id.$bundle_id" + profile_app_id="$(/usr/libexec/PlistBuddy -c 'Print :Entitlements:com.apple.application-identifier' "$plist" 2>/dev/null || true)" + rm -f "$plist" + if [[ "$profile_app_id" != "$expected_app_id" ]]; then + echo "$label provisioning profile has application identifier '$profile_app_id', expected '$expected_app_id'" >&2 + exit 1 + fi +} + assert_profile_app_group() { local profile="$1" local label="$2" + local app_group="$team_id.group.com.shinycomputers.contextpanel" local plist plist="$(mktemp)" security cms -D -i "$profile" -o "$plist" - if ! /usr/libexec/PlistBuddy -c 'Print :Entitlements:com.apple.security.application-groups' "$plist" 2>/dev/null | - grep -Fq 'MM5YXC7T6E.group.com.shinycomputers.contextpanel'; then + if ! plist_array_contains_authorized_value "$plist" 'Entitlements:com.apple.security.application-groups' "$app_group"; then rm -f "$plist" - echo "$label provisioning profile is missing app group: MM5YXC7T6E.group.com.shinycomputers.contextpanel" >&2 + echo "$label provisioning profile does not authorize app group: $app_group" >&2 exit 1 fi rm -f "$plist" @@ -200,6 +243,9 @@ fi app_profile_uuid="$(profile_uuid "$app_profile")" widget_profile_uuid="$(profile_uuid "$widget_profile")" refresh_agent_profile_uuid="$(profile_uuid "$refresh_agent_profile")" +assert_profile_bundle_id "$app_profile" "app" "com.shinycomputers.contextpanel" +assert_profile_bundle_id "$widget_profile" "widget" "com.shinycomputers.contextpanel.widget" +assert_profile_bundle_id "$refresh_agent_profile" "refresh agent" "com.shinycomputers.contextpanel.refresh-agent" assert_profile_app_group "$app_profile" "app" assert_profile_app_group "$widget_profile" "widget" assert_profile_app_group "$refresh_agent_profile" "refresh agent" From af514644a3d5169d7381eea1689f232ab1f5f4fa Mon Sep 17 00:00:00 2001 From: Chris Busillo Date: Fri, 15 May 2026 18:04:06 -0400 Subject: [PATCH 2/2] Use App Store installer certificate label --- docs/release.md | 11 ++++++----- scripts/upload-testflight-macos-app.sh | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/release.md b/docs/release.md index bb4d2b7..1a8dd2c 100644 --- a/docs/release.md +++ b/docs/release.md @@ -94,8 +94,9 @@ bundle identifiers: The workflow calls `scripts/upload-testflight-macos-app.sh`, which generates the Xcode project, installs the supplied provisioning profiles, archives with manual `Apple Distribution` signing, and exports with `method = app-store-connect` and -`installerSigningCertificate = Mac Installer Distribution`. Pass `upload: false` -when dispatching the workflow to export the `.pkg` without uploading it. +`installerSigningCertificate = 3rd Party Mac Developer Installer`. Pass +`upload: false` when dispatching the workflow to export the `.pkg` without +uploading it. The app and refresh-agent App Store entitlements must keep the sandbox enabled with App Group, outbound network, read-only user-selected file access, and @@ -230,6 +231,6 @@ passed `xcrun stapler validate`, and passed local Gatekeeper assessment as On 2026-05-12, the TestFlight export path was verified for current signing configuration in code review: Release archive signing is manual per target, uses Apple Distribution profile build settings, the export plist uses the -current App Store Connect method plus the Mac Installer Distribution certificate -label, and the upload script checks that all three provisioning profiles carry -the Context Panel App Group before archiving. +current App Store Connect method plus the 3rd Party Mac Developer Installer +certificate label, and the upload script checks that all three provisioning +profiles authorize the Context Panel App Group before archiving. diff --git a/scripts/upload-testflight-macos-app.sh b/scripts/upload-testflight-macos-app.sh index eb1dfd6..6c84f33 100755 --- a/scripts/upload-testflight-macos-app.sh +++ b/scripts/upload-testflight-macos-app.sh @@ -270,7 +270,7 @@ cat >"$export_options_path" <signingCertificate Apple Distribution installerSigningCertificate - Mac Installer Distribution + 3rd Party Mac Developer Installer provisioningProfiles com.shinycomputers.contextpanel