Redirect zsh HISTFILE out of the signed app bundle#266
Open
nedtwigg wants to merge 2 commits into
Open
Conversation
macOS /etc/zshrc runs while ZDOTDIR still points at the bundled shell-integration directory and sets HISTFILE inside it. On shell exit zsh then writes .zsh_history into the signed app bundle, breaking its code signature — the next launch fails Gatekeeper with "Dormouse Terminal.app is damaged and can't be opened". Our .zshrc now redirects a HISTFILE that points into our directory back to the user's ZDOTDIR, after sourcing the user's rc so a HISTFILE they set themselves is never touched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
9f0fab3
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://f9a7c1de.mouseterm.pages.dev |
| Branch Preview URL: | https://fix-zsh-history-breaks-bundl.mouseterm.pages.dev |
dormouse-bot
left a comment
Collaborator
There was a problem hiding this comment.
The fix is sound and I traced it end to end: DORMOUSE_ZDOTDIR is reliably set in .zshenv before this check runs, the redirect target reproduces exactly what /etc/zshrc would have chosen without Dormouse, running after the user's rc correctly leaves a user-set HISTFILE untouched, and the ${...}/* pattern does match a dotfile like .zsh_history in a [[ ]] conditional (the leading-. rule is filename-generation only, not pattern matching). Sidecar tests 70/70, lint:specs clean, spec prose matches the code.
One robustness edge case worth hardening — see the inline suggestion. Not a blocker; the default /Applications/Dormouse Terminal.app/... path is unaffected.
Default zsh treats unquoted parameter expansions in [[ == ]] patterns literally, but a user rc that enables GLOB_SUBST (sh/ksh emulation) turns the install path into a pattern — glob metacharacters in the path would then silently defeat the guard. Quoting keeps the directory literal while /* stays a wildcard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dormouse-bot
approved these changes
Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Auto-updating to 1.0.1 and then launching produced macOS's "Dormouse Terminal.app is damaged and can't be opened" dialog. The build and updater were fine — the app bricks itself after its first zsh session:
ZDOTDIRpointed at the shell-integration directory inside the signed app bundle./etc/zshrcruns before our.zshrchandsZDOTDIRback to the user, and setsHISTFILE=${ZDOTDIR:-$HOME}/.zsh_history— capturing the in-bundle path (unless the user's own config overrides HISTFILE, which default-ish setups don't)..zsh_historyinto the sealed bundle. Any file added inside a signed bundle invalidates the signature; the next launch fails Gatekeeper.codesign --verifyon the affected install showed exactly this:v1.0.0 shipped the same integration, so every macOS zsh user is exposed; it manifests on the first launch after a zsh session has exited. A bricked install can't launch its own updater — recovery is deleting the stray file or re-downloading the DMG — so this wants a hotfix release.
The fix
In the bundled
.zshrc, after sourcing the user's rc, redirect aHISTFILEthat points into our directory back toUSER_ZDOTDIR. Running after the user's rc also catches user.zshenv/.zprofilefiles that setHISTFILErelative toZDOTDIRwhile it was still pinned to ours, and guarantees aHISTFILEthe user sets themselves is never touched. Also corrects the header comment's wrong claim that the shipped directory is read-only, and documents the invariant interminal-escapes.md.Non-issue checked along the way: Apple Terminal's session-restore (
/etc/zshrc_Apple_Terminal) writes.zsh_sessions/+.zsh_historyintoZDOTDIRvia a later hook, but it only loads whenTERM_PROGRAM=Apple_Terminal— Dormouse unconditionally setsTERM_PROGRAM=iTerm.app(pty-core.js), so that path can't fire in a Dormouse-spawned shell.Verification
Spawned zsh exactly as Dormouse does (
ZDOTDIR→ integration dir,USER_ZDOTDIRset,TERM_PROGRAM=iTerm.app):HISTFILElands inUSER_ZDOTDIR/.zsh_historyHISTFILE→ untouchedpnpm lint:specsOK; sidecarpty-core.test.js70/70 pass.🤖 Generated with Claude Code