commit 0a9a470714dd8cc1fa0ccc865917bc9c6acf26c1
parent acc376df3e73dc267d7c19250b2ca230edb446ed
Author: Michael Camilleri <[email protected]>
Date: Mon, 29 Jun 2026 17:32:12 +0900
Guard release push configuration
Custom worker pushes could silently disappear from TestFlight builds
when the archive was produced without the local push-worker URL. In that
state PushClient never existed, so nudges, pause summaries, and account
presence pushes only logged 'no pushClient' at send time while CloudKit
sync and badge updates continued to work.
This commit makes that configuration failure visible and blocks it from
shipping. PushClient now records why it disabled itself when the bundled
push URL is missing, unresolved, or invalid, and the iOS publish script
feeds the restored Generated/Local.xcconfig values into archive builds
before checking the exported IPA for a production APNs environment and
an HTTPS push base URL.
Co-Authored-By: Codex GPT 5.5 <[email protected]>
Diffstat:
2 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/Crossmate/Services/PushClient.swift b/Crossmate/Services/PushClient.swift
@@ -90,12 +90,23 @@ final class PushClient {
session: URLSession = PushClient.makeWorkerSession(),
log: @escaping (String) -> Void = { _ in }
) {
- guard
- let rawBase = Bundle.main.object(forInfoDictionaryKey: "CrossmatePushBaseURL") as? String,
- case let trimmedBase = rawBase.trimmingCharacters(in: .whitespacesAndNewlines),
- !trimmedBase.isEmpty,
- let base = URL(string: trimmedBase)
- else { return nil }
+ guard let rawBase = Bundle.main.object(forInfoDictionaryKey: "CrossmatePushBaseURL") as? String else {
+ log("Push disabled: missing CrossmatePushBaseURL")
+ return nil
+ }
+ let trimmedBase = rawBase.trimmingCharacters(in: .whitespacesAndNewlines)
+ guard !trimmedBase.isEmpty, !trimmedBase.hasPrefix("$(") else {
+ log("Push disabled: empty CrossmatePushBaseURL")
+ return nil
+ }
+ guard let base = URL(string: trimmedBase),
+ let scheme = base.scheme,
+ scheme == "https",
+ base.host?.isEmpty == false
+ else {
+ log("Push disabled: invalid CrossmatePushBaseURL")
+ return nil
+ }
self.baseURL = base
self.deviceID = deviceID
self.session = session
diff --git a/Scripts/publish-ios.sh b/Scripts/publish-ios.sh
@@ -11,6 +11,47 @@ fi
source "$SECRETS"
+LOCAL_XCCONFIG="$REPO_ROOT/Generated/Local.xcconfig"
+
+xcconfig_value() {
+ local name="$1"
+ [[ -f "$LOCAL_XCCONFIG" ]] || return 0
+ awk -F= -v key="$name" '
+ $1 ~ "^[[:space:]]*" key "[[:space:]]*$" {
+ value = $2
+ sub(/^[[:space:]]+/, "", value)
+ sub(/[[:space:]]+$/, "", value)
+ print value
+ exit
+ }
+ ' "$LOCAL_XCCONFIG"
+}
+
+build_setting() {
+ local name="$1"
+ local value="${!name:-}"
+ if [[ -z "$value" ]]; then
+ value="$(xcconfig_value "$name")"
+ fi
+ printf '%s' "$value"
+}
+
+CROSSMATE_PUSH_BASE_URL="$(build_setting CROSSMATE_PUSH_BASE_URL)"
+CROSSMATE_ENGAGEMENT_SOCKET_URL="$(build_setting CROSSMATE_ENGAGEMENT_SOCKET_URL)"
+CROSSMATE_SHARE_LINK_BASE_URL="$(build_setting CROSSMATE_SHARE_LINK_BASE_URL)"
+CROSSMATE_SHARE_LINK_HOST="$(build_setting CROSSMATE_SHARE_LINK_HOST)"
+
+require_build_setting() {
+ local name="$1"
+ local value="${!name:-}"
+ if [[ -z "$value" ]]; then
+ echo "Error: $name is not set in $SECRETS or $LOCAL_XCCONFIG."
+ exit 1
+ fi
+}
+
+require_build_setting "CROSSMATE_PUSH_BASE_URL"
+
SCHEME="Crossmate"
# Archive into the Xcode Archives library at a unique per-build path so
# Organizer indexes every build and TestFlight crashes symbolicate
@@ -71,6 +112,10 @@ xcodebuild \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath "$ARCHIVE_PATH" \
+ CROSSMATE_PUSH_BASE_URL="$CROSSMATE_PUSH_BASE_URL" \
+ CROSSMATE_ENGAGEMENT_SOCKET_URL="${CROSSMATE_ENGAGEMENT_SOCKET_URL:-}" \
+ CROSSMATE_SHARE_LINK_BASE_URL="${CROSSMATE_SHARE_LINK_BASE_URL:-}" \
+ CROSSMATE_SHARE_LINK_HOST="${CROSSMATE_SHARE_LINK_HOST:-}" \
archive
echo "==> Writing export options..."
@@ -116,6 +161,17 @@ echo "==> Checking entitlements in exported IPA..."
CHECK_DIR="/tmp/Crossmate-ipa-check"
rm -rf "$CHECK_DIR"
unzip -q "$IPA_PATH" -d "$CHECK_DIR"
+INFO_PLIST="$CHECK_DIR/Payload/Crossmate.app/Info.plist"
+PUSH_BASE_URL=$(/usr/libexec/PlistBuddy -c "Print :CrossmatePushBaseURL" "$INFO_PLIST")
+APS_ENVIRONMENT=$(/usr/libexec/PlistBuddy -c "Print :CrossmateAPSEnvironment" "$INFO_PLIST")
+if [[ "$PUSH_BASE_URL" != https://* ]]; then
+ echo "Error: exported app has invalid CrossmatePushBaseURL: $PUSH_BASE_URL"
+ exit 1
+fi
+if [[ "$APS_ENVIRONMENT" != "production" ]]; then
+ echo "Error: exported app has unexpected CrossmateAPSEnvironment: $APS_ENVIRONMENT"
+ exit 1
+fi
echo "--- iOS app entitlements ---"
codesign -d --entitlements - "$CHECK_DIR/Payload/Crossmate.app"
rm -rf "$CHECK_DIR"