Conversation
Issue #575. The write-guard lexer did not know ANSI-C (`$'...'`) or locale (`$"..."`) quoting: it kept the `$` as an ordinary character and stripped the following quote as an ordinary quote, so `$'tee'` read as the word `$tee`. Bash expands those forms before running, so the program, its prefixes, and its options were read wrong and a write could leave the workspace while bash:verify auto-approval and secret detection were bypassed. New leaf module `bash_write_guard/ansi_c_quoting.rs` scans the whole command before the lexer and returns the first `$'` / `$"` outside a shell quote; quote state mirrors `shell_tokens` (outside / `'...'` / `"..."` / `\` escape), so the introducer inside a quote, after a backslash, or a lone `$` stays allowed. The refusal reuses the env -S shape: a new operation value "ANSI-C / locale quoting" is pushed to write_targets and rejected by confinement_rejection, so the write is recognized (has_recognized_mutation is true) and bash:verify auto-approval no longer applies. Event names/schema and the other lexical analyses are unchanged; `$'tee'`-style spellings are refused as unverifiable rather than expanded. Two-point measurement (report) - Before, develop@1e193ae7 with the new test and unmodified source: `cargo test --test issue575_bash_ansi_c_quoting` FAILED -- `ansi_c_quoting_rejects_program_and_option_spellings` ("expected rejection: $'tee' /tmp/f") and `ansi_c_quoting_rejection_names_the_ansi_c_operation` ("expected rejection"). The allow test passed. - After: 5 lib unit tests + 3 integration tests pass. Mutation testing (report; cargo-mutants 27.1.0, test filter `ansi_c_quoting` so both the lib unit tests and the integration tests run) - New module: `cargo mutants -f src/tools/bash_write_guard/ansi_c_quoting.rs --jobs 2 --timeout 120 -o <out>/mutants-module2 -- ansi_c_quoting` => 13 mutants tested, 13 caught, 0 missed. - New wiring lines only: `cargo mutants -f src/tools/bash_write_guard.rs -F 'bash_write_guard\.rs:(33|130):' ...` => 3 mutants: 2 caught (the confinement_rejection operation check and the write_targets early return), 1 unviable (the `vec![Default::default()]` replacement does not compile), 0 missed. - Supplementary function-scope run (`-F 'write_targets|confinement_rejection'`) leaves 6 survivors, all on pre-existing lines this issue neither adds nor changes: the `/dev/null` skip (63/64), the `cd -` check (68), and the segment split (140). They survive because the second-layer `path_tokens` scan still rejects an outside path when the `/dev/null` skip is dropped, because the same assertions cover the changed conditions, and because the changed segment split yields an empty segment list that the fixtures do not distinguish. No survivor is on a line added by this change. Scope (report) - Declared and actual: src/tools/bash_write_guard.rs, src/tools/bash_write_guard/ansi_c_quoting.rs, tests/issue575_bash_ansi_c_quoting.rs. No other file changed; the referenced existing integration tests (issue566/567/428, bash_workspace_confinement) are untouched and pass. Gates (report; all exit 0) - cargo fmt --all -- --check - python3 scripts/validate_codex_skills.py --tracked-only - ruff check --isolated --select E4,E7,E9,F,I --ignore E402 <python paths> - shellcheck scripts/*.sh - python3 -m pytest tests/test_codex_orchestrate.py -q - python3 -m unittest discover -s workspace/management/scripts -p 'test_*.py' - python3 tests/eval/test_acceptance_contract.py - python3 tests/eval/test_completion_contract_snapshots.py - python3 tests/eval/test_false_positive_regression.py - RUSTFLAGS='-D warnings' cargo clippy --all-targets -- -D warnings - RUSTFLAGS='-D warnings' cargo test --all-targets - ruff check --isolated --select E4,E7,E9,F,I --ignore E402 scripts/nextjs_domain_oracle.py tests/test_nextjs_domain_oracle.py - npm ci --ignore-scripts --include=dev --prefix tests/nextjs_domain && python3 -m pytest tests/test_nextjs_domain_oracle.py -q Report-note: the issue asks for a "report"; scope.allow permits only the three files above, so this report is carried in the commit message and no report file was added. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
13 tasks
7 tasks
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.
Closes #575
What changed
src/tools/bash_write_guard/ansi_c_quoting.rs(new): scans the whole command for ANSI-C quoting$'…'and locale quoting$"…"outside quotes, in any word position.shell_tokens: inside'…',\is literal; inside"…"and outside quotes,\escapes the next character."$'x'",'$'and\$'x'stay allowed, because bash does not expand them.src/tools/bash_write_guard.rs: runs the scan at the start ofwrite_targets.shell_tokens, so the$'\''misreading cannot hide the commands after it. That misreading makesshell_tokensreturnNone, which leaves no write targets.confinement_rejectionrejects the result with the new operationANSI-C / locale quoting.printf 'a\tb\n'andgrep -P '\t'.tests/issue575_bash_ansi_c_quoting.rs(new): integration tests throughpath_confinement_rejection.Why reject instead of decoding
$"…"depends on the locale's translations.$'or$"0 times.Verification
1c01ed71(verify run 1176).-- ansi_c_quoting, no--libfilter,--jobs 2), 19 mutants: 15 caught, 2 missed, 2 unviable.--jobs 1.write_targets. Integration tests catch it.$'\''misreading,cat $'.env',cat $'sub/link/secret',"a"$'tee',\\$'tee',$(…), backticks,<(…), heredoc bodies.issue566_*,issue567_*,issue428_*,bash_workspace_confinement.Notes
$'or$"now count as writes, sobash:verifyno longer auto-allows them.cargo test,timeout 600 cargo test,cargo clippy …,npm test,python3 -m pytest.printf $'a\tb\n' > out.txt,grep $'\t' a.txt,IFS=$'\n' read -r x,read -d $'\0',echo $"hello".shell_tokensdoes not read comments or heredoc bodies. A'there can hide later commands ([security][tools] Bash の書き込み検査が、字句解析で読めないコマンド(heredoc・コメントの中の ')を丸ごと許可し、ワークスペース外へ書き込める(#575 の調査で発見) #576, pre-existing). When [security][tools] Bash の書き込み検査が、字句解析で読めないコマンド(heredoc・コメントの中の ')を丸ごと許可し、ワークスペース外へ書き込める(#575 の調査で発見) #576 teaches the lexer to skip them,ansi_c_quotingneeds the same handling.shell_tokens,path_tokens,sensitive_pathand the verify classifier are unchanged.{ … }の中の書き込みを認識せず、ワークスペース外へ書き込める(#509 の調査で発見) #566, [security][tools] Bash の書き込み検査が同じコマンドの cd・pushd の後の cwd を追わず、symlink を通ってワークスペース外へ書き込める(#509 の調査で発見) #568, [security][tools] Bash の書き込み検査が、字句解析で読めないコマンド(heredoc・コメントの中の ')を丸ごと許可し、ワークスペース外へ書き込める(#575 の調査で発見) #576, [security][tools] Bash の字句検査では、プログラム経由の間接書き込みや検証コマンドの副作用を閉じ込められない #502.Developed with the CommandMate parallel-dev harness (PM: Claude Code, leader: Claude_Dev, workers: Command Code).
🤖 Generated with Claude Code