Repository navigation
Description
Repository > Open in Terminal launches Terminal.app but the new shell is not
placed in the repository directory, and git status is never run. No error is
shown, so the command looks like it simply did nothing.
Root cause: the released app is signed with the hardened runtime but without
com.apple.security.automation.apple-events, so macOS blocks the Apple Event
before the user is ever asked for consent.
Steps to reproduce
- Install a released build of GitX (not a local Xcode build, see below).
- Open any repository.
- Choose
Repository > Open in Terminal(or theConsoletoolbar button).
Expected: a Terminal window in the repository working directory, showing the
output of git status.
Actual: Terminal.app starts up with no window at all, or an ordinary window
in the home directory. Nothing else happens and no error is reported.
Why it fails
PBTerminalUtil does not ask Terminal to open a directory. It builds one shell
line and sends it to Terminal as an Apple Event through Scripting Bridge:
NSString *fullCommand = [NSString stringWithFormat:@"cd \"%@\"; clear; echo '# Opened by GitX'; %@", directory.path, command];
TerminalApplication *term = [SBApplication applicationWithBundleIdentifier:@"com.apple.Terminal"];
[term doScript:fullCommand in:nil];The cd is part of the payload of that event, so if the event is not delivered,
nothing happens at all. Two details combine to make the failure look like a
half-working feature:
SBApplicationlaunches the target through LaunchServices before delivering
the event, and launches it for scripting, which is why Terminal appears but
with no window.- The released app may not send Apple Events at all, as measured below.
GitX ships with the hardened runtime enabled and an empty entitlements file:
$ codesign -dv /Applications/GitX.app
CodeDirectory v=20500 ... flags=0x10000(runtime) ...
$ codesign -d --entitlements - /Applications/GitX.app
[Dict]
Under the hardened runtime, sending Apple Events requires
com.apple.security.automation.apple-events. Without it the send is rejected
with errAEEventNotPermitted (-1743) at the security layer, which sits below
TCC, so no consent dialog is ever presented and the app never appears under
System Settings > Privacy & Security > Automation. Declaring
NSAppleEventsUsageDescription in Info.plist, which GitX does, is necessary
but not sufficient.
Measurements
One minimal app bundle sending tell application "Terminal" to count windows,
re-signed three ways and run unchanged each time:
| Signed with | Result |
|---|---|
-o runtime, no entitlements (matches the release build) |
-1743 Not authorized to send Apple events to Terminal, no prompt |
-o runtime + com.apple.security.automation.apple-events |
succeeds |
-o runtime + com.apple.security.get-task-allow (matches a local Debug build) |
succeeds |
Observed on the affected machine immediately after triggering the menu item:
$ osascript -e 'tell application "System Events" to count windows of process "Terminal"'
0
Terminal was running and had not crashed. doScript never executed, and GitX is
absent from the Automation list, which is the diagnostic signature of the event
being blocked rather than declined.
Why this has gone unnoticed
The third row above is the important one. Xcode signs local builds with
com.apple.security.get-task-allow, and that entitlement relaxes the hardened
runtime restriction, so Open in Terminal works when built from Xcode and fails
in the shipped app. Anyone testing from a local build cannot reproduce it.
This is very likely what happened in #460, where the same symptom was reported,
the maintainer could not reproduce it, and the reporter found that a locally
built copy worked, and closed it as an obscure local setting.
The failure is also silent
Every failure path in PBTerminalUtil ends in an NSLog:
- (nullable id)eventDidFail:(const AppleEvent *)event withError:(NSError *)error
{
NSLog(@"terminal handler error: %@", error);
return nil;
}plus NSLog(@"No usable terminal handler found") in runCommand:inDirectory:.
Nothing reaches the user, which is what made #460 impossible to diagnose from the
UI.
Suggested fix
-
Add
com.apple.security.automation.apple-eventstoGitX.entitlements. This
is the one-line fix for the reported bug. -
Report the failure instead of only logging it, so a blocked or declined event
is visible to the user. -
Consider not needing Apple Events for the common case. LaunchServices opens
Terminal already placed in a directory, with no consent requirement and no
silent-failure path. Verified on the same machine:$ open -a Terminal /Users/me/GitRepos/GitXproduced a window titled
GitX - -zsh - 80x24, correctly in the repository.
-[NSWorkspace openURLs:withApplicationAtURL:configuration:error:]is the API
form. The Scripting Bridge path would then only be needed for the extra
convenience of runninggit status.
Related
#460, same symptom, closed as a local setting.
Activity
Fix Open in Terminal doing nothing in released builds (issue gitx#636)
Fix Open in Terminal doing nothing in released builds (issue gitx#636)
Fix Open in Terminal doing nothing in released builds (issue gitx#636)