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
2 changes: 1 addition & 1 deletion App/Blurt/Blurt.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1949,7 +1949,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\n# Debug-only: installs a re-signed copy at a stable path so TCC will\n# register Blurt in the Accessibility / Input Monitoring lists.\n# Release builds skip this — the release-build.sh script handles\n# staging, secure-timestamp signing, DMG creation, and notarization\n# separately.\ncase \"$CONFIGURATION\" in\n Debug | Debug-Local) ;; # local dev + test builds install\n *)\n echo \"Skipping Install to /Applications for $CONFIGURATION builds.\"\n exit 0\n ;;\nesac\nif [ \"${CODE_SIGNING_ALLOWED:-YES}\" = \"NO\" ]; then\n echo \"Skipping Install to /Applications: codesigning disabled (CI / health check).\"\n exit 0\nfi\nif [ \"${CODE_SIGN_IDENTITY:-}\" = \"-\" ]; then\n # Ad-hoc identity — the UI-test / CI build (scripts/uitest.sh and\n # check.sh sign ad-hoc so the XCUITest runner satisfies library\n # validation). The Developer ID re-sign below can't run without the\n # maintainer's cert, and the tests launch the app straight from\n # DerivedData, so there's nothing to install.\n echo \"Skipping Install to /Applications: ad-hoc signing (UI test / CI).\"\n exit 0\nfi\n# Copy + re-sign into /Applications so TCC sees a permanent path.\n# (Xcode/CLI builds otherwise live in DerivedData / /tmp — paths\n# macOS treats as transient and refuses to add to the Privacy\n# & Security toggle list.) Falls back to ~/Applications if the\n# system folder isn't writable on this machine.\nif [ -w /Applications ]; then\n DEST=\"/Applications/${PRODUCT_NAME}.app\"\nelse\n DEST=\"$HOME/Applications/${PRODUCT_NAME}.app\"\n mkdir -p \"$HOME/Applications\"\nfi\nrm -rf \"$DEST\"\ncp -R \"$BUILT_PRODUCTS_DIR/${PRODUCT_NAME}.app\" \"$DEST\"\n\n# Re-sign with the Apple Development cert (login keychain), matching the\n# build above — NOT the Developer ID release key (dedicated locked\n# keychain, release-only). Same team, so TCC stays stable.\n# Errors are NOT swallowed.\nIDENTITY=\"Apple Development\"\nENTS=\"${SRCROOT}/Blurt/Blurt.entitlements\"\n# Inside-out signing: Debug builds emit unsigned dylibs\n# (__preview.dylib, Blurt.debug.dylib). Signing the bundle\n# alone doesn't recurse, so verify fails. Sign nested code first.\nfind \"$DEST\" -type f \\( -name \"*.dylib\" -o -name \"*.so\" \\) \\\n -print0 | while IFS= read -r -d '' f; do\n codesign --force --sign \"$IDENTITY\" --options runtime \"$f\"\ndone\ncodesign --force --sign \"$IDENTITY\" \\\n --entitlements \"$ENTS\" \\\n --options runtime \\\n \"$DEST\"\ncodesign --verify --strict --verbose=1 \"$DEST\"\necho \"Installed: $DEST\"\n\n# Keep LaunchServices pointing only at the stable install. This build\n# also leaves a copy in DerivedData ($BUILT_PRODUCTS_DIR) registered\n# under the same bundle id; if it lingers, macOS can resolve the id to\n# that transient path and Blurt disappears from the Accessibility\n# list. Drop the DerivedData copy and (re)register the install.\nLSREGISTER=\"/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister\"\n\"$LSREGISTER\" -u \"$BUILT_PRODUCTS_DIR/${PRODUCT_NAME}.app\" >/dev/null 2>&1 || true\n\"$LSREGISTER\" -f \"$DEST\" >/dev/null 2>&1 || true\n";
shellScript = "set -e\n# Debug-only: installs a re-signed copy at a stable path so TCC will\n# register Blurt in the Accessibility / Input Monitoring lists.\n# Release builds skip this — the release-build.sh script handles\n# staging, secure-timestamp signing, DMG creation, and notarization\n# separately.\ncase \"$CONFIGURATION\" in\n Debug | Debug-Local) ;; # local dev + test builds install\n *)\n echo \"Skipping Install to /Applications for $CONFIGURATION builds.\"\n exit 0\n ;;\nesac\nif [ \"${CODE_SIGNING_ALLOWED:-YES}\" = \"NO\" ]; then\n echo \"Skipping Install to /Applications: codesigning disabled (CI / health check).\"\n exit 0\nfi\nif [ \"${CODE_SIGN_IDENTITY:-}\" = \"-\" ]; then\n # Ad-hoc identity — the UI-test / CI build (scripts/uitest.sh and\n # check.sh sign ad-hoc so the XCUITest runner satisfies library\n # validation). The Developer ID re-sign below can't run without the\n # maintainer's cert, and the tests launch the app straight from\n # DerivedData, so there's nothing to install.\n echo \"Skipping Install to /Applications: ad-hoc signing (UI test / CI).\"\n exit 0\nfi\n# Copy + re-sign into /Applications so TCC sees a permanent path.\n# (Xcode/CLI builds otherwise live in DerivedData / /tmp — paths\n# macOS treats as transient and refuses to add to the Privacy\n# & Security toggle list.) Falls back to ~/Applications if the\n# system folder isn't writable on this machine.\nif [ -w /Applications ]; then\n DEST=\"/Applications/${PRODUCT_NAME}.app\"\nelse\n DEST=\"$HOME/Applications/${PRODUCT_NAME}.app\"\n mkdir -p \"$HOME/Applications\"\nfi\nrm -rf \"$DEST\"\ncp -R \"$BUILT_PRODUCTS_DIR/${PRODUCT_NAME}.app\" \"$DEST\"\n\n# Re-sign with the Apple Development cert (login keychain), matching the\n# build above — NOT the Developer ID release key (dedicated locked\n# keychain, release-only).\n# Errors are NOT swallowed.\nIDENTITY=\"Apple Development\"\nENTS=\"${SRCROOT}/Blurt/Blurt.entitlements\"\n# Pin an explicit, TEAM-based designated requirement. TCC keys the\n# Accessibility / Input Monitoring grant to the app's designated\n# requirement, and codesign's DEFAULT DR for an Apple Development cert\n# pins the specific leaf cert's Common Name (\"Apple Development: … (ID)\")\n# — which changes every time that cert rotates (they expire ~yearly and\n# Xcode reissues them), silently orphaning the grant (\"toggle on, still\n# denied\"). A team-based DR stays stable across cert rotation AND is\n# satisfied by both Apple Development and Developer ID signatures (both\n# carry OU = the team id), so dev and release builds share one identity\n# as far as TCC is concerned.\nREQ='designated => identifier \"'\"${PRODUCT_BUNDLE_IDENTIFIER}\"'\" and anchor apple generic and certificate leaf[subject.OU] = \"'\"${DEVELOPMENT_TEAM}\"'\"'\n# Inside-out signing: Debug builds emit unsigned dylibs\n# (__preview.dylib, Blurt.debug.dylib). Signing the bundle\n# alone doesn't recurse, so verify fails. Sign nested code first.\nfind \"$DEST\" -type f \\( -name \"*.dylib\" -o -name \"*.so\" \\) \\\n -print0 | while IFS= read -r -d '' f; do\n codesign --force --sign \"$IDENTITY\" --options runtime \"$f\"\ndone\ncodesign --force --sign \"$IDENTITY\" \\\n --entitlements \"$ENTS\" \\\n --options runtime \\\n -r=\"$REQ\" \\\n \"$DEST\"\ncodesign --verify --strict --verbose=1 \"$DEST\"\necho \"Installed: $DEST\"\n\n# Keep LaunchServices pointing only at the stable install. This build\n# also leaves a copy in DerivedData ($BUILT_PRODUCTS_DIR) registered\n# under the same bundle id; if it lingers, macOS can resolve the id to\n# that transient path and Blurt disappears from the Accessibility\n# list. Drop the DerivedData copy and (re)register the install.\nLSREGISTER=\"/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister\"\n\"$LSREGISTER\" -u \"$BUILT_PRODUCTS_DIR/${PRODUCT_NAME}.app\" >/dev/null 2>&1 || true\n\"$LSREGISTER\" -f \"$DEST\" >/dev/null 2>&1 || true\n";
};
/* End PBXShellScriptBuildPhase section */

Expand Down
14 changes: 13 additions & 1 deletion App/Blurt/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,21 @@ targets:

# Re-sign with the Apple Development cert (login keychain), matching the
# build above — NOT the Developer ID release key (dedicated locked
# keychain, release-only). Same team, so TCC stays stable.
# keychain, release-only).
# Errors are NOT swallowed.
IDENTITY="Apple Development"
ENTS="${SRCROOT}/Blurt/Blurt.entitlements"
# Pin an explicit, TEAM-based designated requirement. TCC keys the
# Accessibility / Input Monitoring grant to the app's designated
# requirement, and codesign's DEFAULT DR for an Apple Development cert
# pins the specific leaf cert's Common Name ("Apple Development: … (ID)")
# — which changes every time that cert rotates (they expire ~yearly and
# Xcode reissues them), silently orphaning the grant ("toggle on, still
# denied"). A team-based DR stays stable across cert rotation AND is
# satisfied by both Apple Development and Developer ID signatures (both
# carry OU = the team id), so dev and release builds share one identity
# as far as TCC is concerned.
REQ='designated => identifier "'"${PRODUCT_BUNDLE_IDENTIFIER}"'" and anchor apple generic and certificate leaf[subject.OU] = "'"${DEVELOPMENT_TEAM}"'"'
# Inside-out signing: Debug builds emit unsigned dylibs
# (__preview.dylib, Blurt.debug.dylib). Signing the bundle
# alone doesn't recurse, so verify fails. Sign nested code first.
Expand All @@ -165,6 +176,7 @@ targets:
codesign --force --sign "$IDENTITY" \
--entitlements "$ENTS" \
--options runtime \
-r="$REQ" \
"$DEST"
codesign --verify --strict --verbose=1 "$DEST"
echo "Installed: $DEST"
Expand Down