Development record
2026-10-17 — Refines dcn-2610170805446355: the text an approval hands back is cd -- '<dir>' && /bin/bash --noprofile --norc -p -c '<command>'. It drops exec, because the host joins its own text after the approved one (&& pwd -P >| <file>, its record of the shell's working directory), which must still run, and exec guards nothing the agent controls. It adds -p after the long options, since bash 3.2 refuses a long option after a short one, so bash ignores BASH_ENV, functions exported as BASH_FUNC_* and SHELLOPTS from the environment, and the approved command runs under /bin/bash with its profile, rc and environment start-up files ignored. The check of the text handed back accepts exactly that shape and nothing else. And a command holding a NUL byte is refused under the new id command-holds-nul before the guard reads it, since the guard's reading removes a NUL before it reads a word, so the command it would judge is not the one sent.
2026-10-17 — Refines dcn-2610170805446355: the text an approval hands back is cd -- '<dir>' && /bin/bash --noprofile --norc -p -c '<command>'. It drops exec, because the host joins its own text after the approved one (&& pwd -P >| <file>, its record of the shell's working directory), which must still run, and exec guards nothing the agent controls. It adds -p after the long options, since bash 3.2 refuses a long option after a short one, so bash ignores BASH_ENV, functions exported as BASH_FUNC_* and SHELLOPTS from the environment, and the approved command runs under /bin/bash with its profile, rc and environment start-up files ignored. The check of the text handed back accepts exactly that shape and nothing else. And a command holding a NUL byte is refused under the new id command-holds-nul before the guard reads it, since the guard's reading removes a NUL before it reads a word, so the command it would judge is not the one sent.
Frontmatter
| id | dcn-2610170937000859 |
|---|---|
| type | decision |
| date | 2026-10-17 |
.abcd/work/decisions/dcn-2610170937000859-refines-dcn-2610170805446355-the-text-an.md
open on GitHub ↗ · commit history ↗
mentions2
- dcn-26101708054463552026-10-17 — Refines dcn-2610170739186543: an approved command runs under bash, because the guard reads every command in bash's grammar, so the command it judged is the command that runs. The approval hands back cd -- '<dir>' && exec /bin/bash --noprofile --norc -c '<command>', the command one single-quoted word, so the person's login shell, zsh or bash, only changes directory and, when that succeeds, starts bash, with its profile and rc files switched off. A construct only zsh gives a meaning to (glob qualifiers, (:A) modifiers, { … } always { … }) is a syntax error to bash, and bash runs nothing of that line. The check of the text handed back reads it with the guard's own parse and approves it only when it is exactly that change of directory joined by && to that one bash call, with the whole command as its last word and nothing else, refused as tree-group-broken otherwise. It no longer reads the command's own groups, ifs, loops and cases, since nothing in the single-quoted word can end it early: a } or a fi with nothing open is bash's syntax error inside the working tree, not a refusal. The refusal of a command where an unquoted ( stands in a word, and the reading of a quoted } as a command's name, stay as a second layer.
- dcn-26101709441537202026-10-17 — The headless approver refuses arithmetic on anything but written numbers. Bash evaluates a name it meets in an arithmetic context as arithmetic in turn, so a value the line does not fix can hold an array index that runs a command the line never names. The approver reads the whole command text, quotes and here-documents included, and refuses a name, a quote or an expansion in (( )), $(( )), $[ ] and a for (( )) header, the number tests and -v of [[ ]], let and integer or name-reference declarations, a non-numeric array index or substring offset, ${!name}, and a variable name not written in the line handed to read, unset, printf -v, wait -p, test -v or a declaration. [ and test compare numbers without evaluating them and stay approved. Reading the text whole over-refuses a script that only quotes such a construct, which the agent can write another way; a reader that tracked quoting could be misled by what a quote hides. This refines dcn-2610170937000859.