From 10b00f5c227914a9f2145d16d88d54b153eda8a3 Mon Sep 17 00:00:00 2001 From: oratis Date: Fri, 19 Jun 2026 23:51:45 +0800 Subject: [PATCH 1/3] fix(mas): build-mas.sh survives no-Frameworks bundle; add App Store entitlements Two bugs surfaced on the first real Mac App Store build of Markup: 1. build-mas.sh step 3 ran `find "$APP/Contents/Frameworks"` unconditionally. tauri.conf.json sets "frameworks": [], so Markup.app has no Contents/Frameworks dir; find exits non-zero and `set -o pipefail` killed the script before any codesign ran. Guard the find with a directory check. 2. Entitlements.mas.plist lacked com.apple.application-identifier and com.apple.developer.team-identifier, which App Store signing requires (the .pkg upload is rejected without them). Add both (9LH9NBX7P4.com.appkon.markup / 9LH9NBX7P4). Verified by building a signed, sandboxed Markup.pkg (v1.0.1) locally: pkgutil chain = "3rd Party Mac Developer Installer: Bihao Wang"; embedded app signed by "Apple Distribution: Bihao Wang" with app-sandbox + application-identifier + the embedded provisioning profile; codesign --verify --deep --strict passes. Co-Authored-By: Claude Opus 4.8 --- scripts/build-mas.sh | 13 +++++++++---- src-tauri/Entitlements.mas.plist | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/scripts/build-mas.sh b/scripts/build-mas.sh index 9ac723f..46d8511 100755 --- a/scripts/build-mas.sh +++ b/scripts/build-mas.sh @@ -62,10 +62,15 @@ cp "$MAS_PROFILE" "$APP/Contents/embedded.provisionprofile" echo "==> 3/5 Signing nested code, then the app (Apple Distribution + sandbox entitlements)" # Sign inner binaries/frameworks first (inside-out), then the bundle. -find "$APP/Contents/Frameworks" -type f \( -name "*.dylib" -o -perm -111 \) 2>/dev/null | while read -r f; do - codesign --force --timestamp --options runtime \ - --sign "$MAS_APP_IDENTITY" "$f" || true -done +# Tauri's bundle has no Contents/Frameworks when tauri.conf.json sets +# "frameworks": [] — guard the find so a missing dir doesn't trip +# `set -o pipefail` (find exits non-zero on a nonexistent path). +if [ -d "$APP/Contents/Frameworks" ]; then + find "$APP/Contents/Frameworks" -type f \( -name "*.dylib" -o -perm -111 \) 2>/dev/null | while read -r f; do + codesign --force --timestamp --options runtime \ + --sign "$MAS_APP_IDENTITY" "$f" || true + done +fi codesign --force --timestamp \ --entitlements "$ENTITLEMENTS" \ --sign "$MAS_APP_IDENTITY" \ diff --git a/src-tauri/Entitlements.mas.plist b/src-tauri/Entitlements.mas.plist index 0d4536a..5780ae4 100644 --- a/src-tauri/Entitlements.mas.plist +++ b/src-tauri/Entitlements.mas.plist @@ -5,6 +5,8 @@ the hardened-runtime set for the direct/notarized DMG). MAS apps run under App Sandbox instead of the hardened-runtime exceptions. + - application-identifier / team-identifier: required for App Store signing; + the .pkg upload is rejected without them. Must match the bundle id + team. - app-sandbox: mandatory for MAS. - files.user-selected.read-write: lets the user grant a vault folder via the system open panel. @@ -22,6 +24,10 @@ --> + com.apple.application-identifier + 9LH9NBX7P4.com.appkon.markup + com.apple.developer.team-identifier + 9LH9NBX7P4 com.apple.security.app-sandbox com.apple.security.files.user-selected.read-write From 905ec033c227bd67976b8cfc1bb7b2d38dafca8f Mon Sep 17 00:00:00 2001 From: oratis Date: Sat, 20 Jun 2026 22:25:05 +0800 Subject: [PATCH 2/3] fix(mas): build a universal (arm64 + x86_64) .pkg App Store rejected the arm64-only build (Transporter validation 409): our minimumSystemVersion is 10.15 (< 12.0), so Apple requires Intel support too. Build with `--target universal-apple-darwin` (output moves to target/universal-apple-darwin/) and `rustup target add` both arches so it works locally and on CI. Verified: `lipo -archs` on the app binary = "x86_64 arm64"; signed, sandboxed pkg. Co-Authored-By: Claude Opus 4.8 --- scripts/build-mas.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/build-mas.sh b/scripts/build-mas.sh index 46d8511..c3ba7c6 100755 --- a/scripts/build-mas.sh +++ b/scripts/build-mas.sh @@ -44,14 +44,21 @@ if [ ! -f "$MAS_PROFILE" ]; then exit 1 fi -APP="src-tauri/target/release/bundle/macos/Markup.app" +# Universal (arm64 + x86_64). MAS requires Intel support unless the deployment +# target is macOS 12+ (ours is 10.15), so `tauri --target universal-apple-darwin` +# lipos both arches into one bundle; output lands under target/universal-apple-darwin/. +APP="src-tauri/target/universal-apple-darwin/release/bundle/macos/Markup.app" ENTITLEMENTS="src-tauri/Entitlements.mas.plist" -PKG="src-tauri/target/release/bundle/macos/Markup.pkg" +PKG="src-tauri/target/universal-apple-darwin/release/bundle/macos/Markup.pkg" -echo "==> 1/5 Building sandboxed app (VITE_MARKUP_MAS=1, MAS entitlements)" +echo "==> 1/5 Building sandboxed universal app (VITE_MARKUP_MAS=1, MAS entitlements)" +# Both arches must be present for the universal build — no-op if already added; +# works locally and on CI (rustup manages the toolchain in both). +rustup target add aarch64-apple-darwin x86_64-apple-darwin >/dev/null 2>&1 || true # --bundles app: we package the .pkg ourselves after signing. # --config layers the MAS entitlements over tauri.conf.json. VITE_MARKUP_MAS=1 pnpm tauri build \ + --target universal-apple-darwin \ --bundles app \ --config src-tauri/tauri.mas.conf.json From bf5e00a1469e110492ed8cb074960f83e47d260b Mon Sep 17 00:00:00 2001 From: oratis Date: Sat, 20 Jun 2026 23:05:50 +0800 Subject: [PATCH 3/3] fix(mas): strip com.apple.quarantine before signing A browser-downloaded provisioning profile carries the com.apple.quarantine xattr; copied into the .app it makes the App Store reject the upload (error 91109). Run `xattr -cr` on the bundle before signing/packaging. Co-Authored-By: Claude Opus 4.8 --- scripts/build-mas.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/build-mas.sh b/scripts/build-mas.sh index c3ba7c6..e4d52d8 100755 --- a/scripts/build-mas.sh +++ b/scripts/build-mas.sh @@ -67,6 +67,11 @@ VITE_MARKUP_MAS=1 pnpm tauri build \ echo "==> 2/5 Embedding provisioning profile" cp "$MAS_PROFILE" "$APP/Contents/embedded.provisionprofile" +# Strip extended attributes before signing: a browser-downloaded provisioning +# profile carries com.apple.quarantine, and the App Store rejects any file with +# it (error 91109). Clearing here keeps the bundle clean for the signature/pkg. +xattr -cr "$APP" + echo "==> 3/5 Signing nested code, then the app (Apple Distribution + sandbox entitlements)" # Sign inner binaries/frameworks first (inside-out), then the bundle. # Tauri's bundle has no Contents/Frameworks when tauri.conf.json sets