feat(deploy): add --fix-accessibility flag + document TCC requirement
macOS invalidates Accessibility permission whenever the app binary changes (code signature shifts on each build). New --fix-accessibility flag runs tccutil reset + a sudo sqlite3 TCC grant via SSH after the .app is synced. Falls back gracefully if sqlite3 grant fails (SIP or missing sudoers), logging a warning with a pointer to the manual steps. README documents the symptom, manual fix, sudoers one-time setup, and bundle ID (com.electron.aetherlauncher). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
40
README.md
40
README.md
@@ -63,6 +63,9 @@ Devices API key section). All laptops share one key per event. Delete it after t
|
||||
|
||||
# Update seed.json only (no .app copy — e.g. when rotating the API key):
|
||||
./deploy/deploy.sh --seed-only all
|
||||
|
||||
# Deploy and re-grant Accessibility permission in one pass:
|
||||
./deploy/deploy.sh --fix-accessibility all
|
||||
```
|
||||
|
||||
The script auto-detects each Mac's CPU architecture, copies the correct `.app` build, writes
|
||||
@@ -74,6 +77,43 @@ continues, then reports which laptops need a retry.
|
||||
After the script completes, launch the app on each laptop and confirm it connects and shows
|
||||
the correct device name in the Launcher UI.
|
||||
|
||||
### macOS Accessibility Permission
|
||||
|
||||
The launcher sends keystrokes to PowerPoint and Keynote via AppleScript. macOS requires
|
||||
explicit **Accessibility** access for this. Every time a new `.app` binary is deployed, macOS
|
||||
invalidates the stored permission because the code signature changes — even when rsync
|
||||
updates in-place.
|
||||
|
||||
**Symptom:** Slide control silently fails; `osascript` eventually returns a permissions error.
|
||||
|
||||
**Manual fix** (GUI — always works):
|
||||
1. System Settings → Privacy & Security → Accessibility
|
||||
2. Find `aether_launcher` in the list → remove it (− button)
|
||||
3. Re-add it (+ button → `/Applications/aether_launcher.app`) and toggle it on
|
||||
|
||||
**Automated fix** — use the `--fix-accessibility` deploy flag:
|
||||
```bash
|
||||
./deploy/deploy.sh --fix-accessibility 01 02 03
|
||||
./deploy/deploy.sh --build --fix-accessibility all
|
||||
```
|
||||
This runs `tccutil reset` (no password required) then attempts a direct TCC database grant
|
||||
via `sudo sqlite3`. The sqlite3 step requires NOPASSWD sudo on each Mac — one-time setup:
|
||||
|
||||
```bash
|
||||
ssh "speaker ready"@192.168.32.1XX "sudo visudo -f /etc/sudoers.d/aether-tcc"
|
||||
```
|
||||
Add this line, then save:
|
||||
```text
|
||||
speaker ready ALL=(ALL) NOPASSWD: /usr/bin/sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db *
|
||||
```
|
||||
|
||||
If the sqlite3 grant fails (SIP enabled, sudoers not configured), the script logs a warning
|
||||
and falls back gracefully — a fresh permission prompt appears the first time the app uses
|
||||
accessibility. The `--fix-accessibility` flag can be combined with any other flag.
|
||||
|
||||
**Long-term fix:** Code-sign the app with an Apple Developer certificate. A stable signature
|
||||
means macOS never invalidates the permission on updates. Currently out of scope.
|
||||
|
||||
### Adding SSH key to a new laptop (first time only)
|
||||
|
||||
```bash
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
# deploy.sh — Deploy Aether Native Launcher to onsite Mac laptops
|
||||
#
|
||||
# USAGE:
|
||||
# ./deploy.sh <num> [num ...] Deploy to one or more laptops (e.g. 03 04 05)
|
||||
# ./deploy.sh all Deploy to all laptops in devices.conf
|
||||
# ./deploy.sh --seed-only <num> Update seed.json only — skip .app copy
|
||||
# ./deploy.sh <num> [num ...] Deploy to one or more laptops (e.g. 03 04 05)
|
||||
# ./deploy.sh all Deploy to all laptops in devices.conf
|
||||
# ./deploy.sh --seed-only <num> Update seed.json only — skip .app copy
|
||||
# ./deploy.sh --seed-only all
|
||||
# ./deploy.sh --build <num> [num ...] Build first (npm run package:mac), then deploy
|
||||
# ./deploy.sh --build <num> [num ...] Build first (npm run package:mac), then deploy
|
||||
# ./deploy.sh --build all
|
||||
# ./deploy.sh --fix-accessibility <num> [num ...] Re-grant macOS Accessibility permission after .app update
|
||||
# ./deploy.sh --fix-accessibility all (requires NOPASSWD sudo for sqlite3 — see README)
|
||||
#
|
||||
# REQUIRES:
|
||||
# event.env — copy from event.env.example and fill in AETHER_API_KEY
|
||||
@@ -27,7 +29,10 @@ BUILD_DIR="$SCRIPT_DIR/../builds"
|
||||
|
||||
SEED_ONLY=false
|
||||
BUILD_FIRST=false
|
||||
FIX_ACCESSIBILITY=false
|
||||
TARGETS=()
|
||||
# Bundle ID as embedded in Info.plist by electron-packager (no --app-bundle-id override)
|
||||
BUNDLE_ID="com.electron.aetherlauncher"
|
||||
|
||||
usage() {
|
||||
grep '^#' "$0" | grep -v '^#!/' | sed 's/^# \{0,1\}//'
|
||||
@@ -38,9 +43,10 @@ if [[ $# -eq 0 ]]; then usage; fi
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--seed-only) SEED_ONLY=true ;;
|
||||
--build) BUILD_FIRST=true ;;
|
||||
--help|-h) usage ;;
|
||||
--seed-only) SEED_ONLY=true ;;
|
||||
--build) BUILD_FIRST=true ;;
|
||||
--fix-accessibility) FIX_ACCESSIBILITY=true ;;
|
||||
--help|-h) usage ;;
|
||||
all) TARGETS+=("all") ;;
|
||||
*) TARGETS+=("$1") ;;
|
||||
esac
|
||||
@@ -162,6 +168,26 @@ deploy_laptop() {
|
||||
}
|
||||
EOF
|
||||
|
||||
# ── Accessibility permission ───────────────────────────────────────────
|
||||
if [[ "$FIX_ACCESSIBILITY" == "true" ]]; then
|
||||
echo " Resetting Accessibility permission (tccutil)..."
|
||||
if ssh "$SSH_USER@$ip" "tccutil reset Accessibility $BUNDLE_ID" 2>/dev/null; then
|
||||
echo " tccutil reset OK."
|
||||
else
|
||||
echo " WARNING: tccutil reset failed (non-fatal)."
|
||||
fi
|
||||
|
||||
echo " Granting Accessibility via TCC database (requires NOPASSWD sudo)..."
|
||||
# shellcheck disable=SC2016
|
||||
TCC_SQL="INSERT OR REPLACE INTO access(service,client,client_type,auth_value,auth_reason,auth_version) VALUES('kTCCServiceAccessibility','$BUNDLE_ID',0,2,4,1);"
|
||||
if ssh "$SSH_USER@$ip" "sudo sqlite3 '/Library/Application Support/com.apple.TCC/TCC.db' \"$TCC_SQL\"" 2>/dev/null; then
|
||||
echo " ✓ Accessibility granted."
|
||||
else
|
||||
echo " WARNING: TCC grant failed — manual re-authorization required."
|
||||
echo " See README: macOS Accessibility Permission."
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Verify ─────────────────────────────────────────────────────────────
|
||||
echo " Verifying..."
|
||||
ssh "$SSH_USER@$ip" "cat ~/seed.json"
|
||||
|
||||
Reference in New Issue
Block a user