Skip to content

fix(pty-proxy): don't re-exec shells running commands from a string or file - #4414

Merged
atuin-bot merged 1 commit into
atuinsh:mainfrom
dannyshafer:fix-4412-pty-proxy-noninteractive-command
Oct 20, 2026
Merged

atuin-bot merged 1 commit into
atuinsh:mainfrom
dannyshafer:fix-4412-pty-proxy-noninteractive-command

Conversation

@dannyshafer

@dannyshafer dannyshafer commented Oct 14, 2026 •

Copy link
Copy Markdown

The bash/zsh preamble re-execs any interactive shell attached to a terminal as atuin pty-proxy, which drops the command passed to bash -ic or zsh -ic and leaves the user at a prompt. Skip the re-exec when BASH_EXECUTION_STRING or ZSH_EXECUTION_STRING is set.

Fixes #4412

Edit by @taylordotfish: I added support for detecting bash -i <file> and zsh -i <file> too. There are some caveats as it isn't possible to check for this with 100% accuracy. In particular, these cases will continue to have incorrect behavior:

  • Zsh:

    • If the basename of <file> is zsh or -zsh, we will incorrectly spawn a proxy (though this can depend on whether the shell is a login shell).
    • If Zsh is spawned with a custom argv[0], we will, in general, not spawn a proxy even though we should. However, before this PR, we would actually try to execute argv[0] which would simply kill the shell, so this is an improvement. (Note that if argv[0] happens to be a valid executable, we will still incorrectly execute it as before.)
    • If Zsh is an older version that doesn't set ZSH_ARGZERO, we can't detect when we're reading from a file and will always spawn a proxy.
  • Bash:

    • If <file> is bash or -bash, we will incorrectly spawn a proxy (though can depend on whether the shell is a login shell).
    • If Bash is invoked via a relative path (./bin/bash) and the shell has changed CWD before the proxy check is run, we will not spawn a proxy even though we should.
    • If Bash is spawned with a custom argv[0], we will, in general, not spawn a proxy even though we should.
    • If Bash is started as a login shell but the user's shell in /etc/passwd isn't Bash, we will not spawn a proxy even though we should. However, before this PR, we would incorrectly execute that non-Bash program, so this is an improvement. However, if the /etc/passwd shell is a different installation of Bash, we will still incorrectly spawn that other Bash as before.
    • If Bash is older than version 5.2, we can't detect when we're reading from a file and will always spawn a proxy.

Checks

  • I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
  • I have checked that there are no existing pull requests for the same thing

@greptile-apps

greptile-apps Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable new issues were found.

Summary

Prevents Bash and Zsh from replacing command or file invocations with a PTY proxy.

  • Bash and Zsh run supplied commands and files before the proxy takes over.

Reviews (3) Β· Last reviewed commit: "Fix tests on older Bash" Β· Reviewed by Greptile

Comment thread crates/atuin-pty-proxy/src/pty_proxy.rs Resolved
@taylordotfish taylordotfish self-assigned this Oct 14, 2026
@taylordotfish

Copy link
Copy Markdown
Member

Thanks for the PR! I'm trying to see if we can also detect bash -i <file> too, since that has the same problem. Unfortunately, it doesn't appear to be as easy to detect whether a file was passed.

@taylordotfish taylordotfish changed the title fix(pty-proxy): don't re-exec shells started with -c fix(pty-proxy): don't re-exec shells running commands from a string or file Oct 20, 2026
@taylordotfish

Copy link
Copy Markdown
Member

/merge

@atuin-bot

atuin-bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Landed as 658b539. GitHub shows this merged once it reaches main.

…r file (atuinsh#4414)

The bash/zsh preamble re-execs any interactive shell attached to a terminal as `atuin pty-proxy`, which drops the command passed to `bash -ic` or `zsh -ic` and leaves the user at a prompt. Skip the re-exec when BASH_EXECUTION_STRING or ZSH_EXECUTION_STRING is set.

Fixes atuinsh#4412

Edit by @taylordotfish: I added support for detecting `bash -i <file>` and `zsh -i <file>` too. There are some caveats as it isn't possible to check for this with 100% accuracy. In particular, these cases will continue to have incorrect behavior:

* Zsh:
  - If the basename of `<file>` is `zsh` or `-zsh`, we will incorrectly spawn a proxy (though this can depend on whether the shell is a login shell).
  - If Zsh is spawned with a custom `argv[0]`, we will, in general, not spawn a proxy even though we should. However, before this PR, we would actually try to execute `argv[0]` which would simply kill the shell, so this is an improvement. (Note that if `argv[0]` happens to be a valid executable, we will still incorrectly execute it as before.)
  - If Zsh is an older version that doesn't set `ZSH_ARGZERO`, we can't detect when we're reading from a file and will always spawn a proxy.

* Bash:
  - If `<file>` is `bash` or `-bash`, we will incorrectly spawn a proxy (though can depend on whether the shell is a login shell).
  - If Bash is invoked via a relative path (`./bin/bash`) and the shell has changed CWD before the proxy check is run, we will not spawn a proxy even though we should.
  - If Bash is spawned with a custom `argv[0]`, we will, in general, not spawn a proxy even though we should.
  - If Bash is started as a login shell but the user's shell in `/etc/passwd` isn't Bash, we will not spawn a proxy even though we should. However, before this PR, we would incorrectly execute that non-Bash program, so this is an improvement. However, if the `/etc/passwd` shell is a different installation of Bash, we will still incorrectly spawn that other Bash as before.
  - If Bash is older than version 5.2, we can't detect when we're reading from a file and will always spawn a proxy.

<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord -->

## Checks
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing

Co-authored-by: taylor.fish <contact@taylor.fish>
@atuin-bot
atuin-bot force-pushed the fix-4412-pty-proxy-noninteractive-command branch from 5f68b0c to 658b539 Compare October 20, 2026 21:15
@atuin-bot
atuin-bot merged commit 658b539 into atuinsh:main Oct 20, 2026
4 of 5 checks passed
atuin-bot pushed a commit that referenced this pull request Oct 22, 2026
### Bug Fixes

- *(ai)* Import IntoStaticStr from strum_macros, not strum ([&#35;4480](#4480))
- *(ai)* Improve detection of git repositories ([&#35;4450](#4450))
- *(client)* Resolve relative config paths beside config.toml, not the cwd ([&#35;4479](#4479))
- *(config)* Don't print errors twice ([&#35;4501](#4501))
- *(daemon)* Fetch the server's capabilities until a fetch succeeds
- *(daemon)* Spare a stale pidfile's PID when evicting ([&#35;4512](#4512))
- *(daemon)* Handle daemons not spawned by atuin ([&#35;4516](#4516))
- *(output)* Keep quoted words together in output search ([&#35;4502](#4502))
- *(packfile)* Load only the records inside a manifest's range
- *(pty-proxy)* Standalone init with `atuin pty-proxy init` ([&#35;4449](#4449))
- *(pty-proxy)* Wait for input on a non-blocking inherited stdin ([&#35;4486](#4486))
- *(pty-proxy)* Don't re-exec shells running commands from a string or file ([&#35;4414](#4414))
- *(search)* Don't panic when copying with no results ([&#35;4426](#4426))
- *(server)* Let `ATUIN_*` environment variables override server.toml ([&#35;4456](#4456))
- *(update)* Accept ATUIN_GITHUB_TOKEN ([&#35;4262](#4262))
- Remove duplicated word in the no-history stats message ([&#35;4451](#4451))
- Error printing in `?` handler ([&#35;4448](#4448))
- Normalize relative gitdir paths in worktree resolution ([&#35;4506](#4506))
- Upgrade regressions found in release QA ([&#35;4519](#4519))


### Documentation

- Fix ctrl_n_shortcuts default value ([&#35;4458](#4458))
- List all history list --format variables ([&#35;4460](#4460))
- Fix the --reverse default for history list ([&#35;4472](#4472))
- Mention December default in wrapped --year help ([&#35;4476](#4476))


### Features

- *(common)* AbsPath and AbsPathBuf, Path and PathBuf checked to be absolute ([&#35;4481](#4481))
- *(common)* Find a process's cgroup under cgroup v1 and v2 ([&#35;4513](#4513))
- *(daemon)* Run the daemon as a launchd agent on macOS ([&#35;4517](#4517))
- *(pty-proxy)* Window title follows child process ([&#35;4447](#4447))
- *(secrets)* Keep HashiCorp tokens out of history ([&#35;4445](#4445))


### Miscellaneous Tasks

- Give mono its own nixfmt step and scope atuin's to atuin/
- Say a /merge's landed commit gets CI on main
- Rebuild the apt .deb cache for Ubuntu 24.04 ([&#35;4504](#4504))
- Remove the benchmarks ([&#35;4511](#4511))


### Performance

- *(common)* Compile the vendor regexes once ([&#35;4485](#4485))
- *(common)* Drop the tree watcher's file-id cache ([&#35;4492](#4492))
- *(common)* Release a line reader's buffer at the end of the file ([&#35;4494](#4494))
- *(common)* Keep no tree watcher entry for a rejected file ([&#35;4493](#4493))
- *(daemon)* Warm up only a resumed session's unanswered calls ([&#35;4490](#4490))
- *(packfile)* Compress packs in one shot ([&#35;4484](#4484))


### Refactor

- *(daemon)* Managed daemon service with multiple backends ([&#35;4488](#4488))
- *(daemon)* Move daemon startup into the service module ([&#35;4503](#4503))
- *(daemon)* Keep where the daemon listens behind service::address ([&#35;4514](#4514))
- *(daemon)* Take up the daemon's socket in SocketHolder, not Backend ([&#35;4515](#4515))
- *(deps)* Bump clap_complete_nushell from 4.6.0 to 4.6.2 ([&#35;4473](#4473))
- *(deps)* Bump clap_complete from 4.6.9 to 4.6.11 ([&#35;4396](#4396))
- *(deps)* Bump ratatui from 0.30.0 to 0.30.2 ([&#35;4474](#4474))
- *(deps)* Bump certifi from 2025.11.12 to 2026.10.19 in /docs in the uv group across 1 directory ([&#35;4500](#4500))
- *(pty-proxy)* Run on tokio with the parser on its own runtime ([&#35;4482](#4482))
- *(pty-proxy)* Forward captures to the daemon on the proxy's runtime ([&#35;4487](#4487))
- *(pty-proxy)* Rename the screen's parser to Emulator ([&#35;4510](#4510))
- *(pty-proxy)* Migrate output parsing to vte ([&#35;4518](#4518))


### Testing

- *(daemon)* Run the output index tests under rstest ([&#35;4496](#4496))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: pty-proxy init re-execs zsh -ic / bash -ic and drops the command

4 participants