fix(bash-local): keep /dev/null stdin when no bytes supplied
Address review on the bash stdin/env seam PR: the seam spawned stdin as a `'pipe'` for EVERY call, closing it empty when no stdin was supplied. That is NOT observationally equivalent to the pre-seam `'ignore'` default — node's spawn pipe is an AF_UNIX socket, so `test -c /dev/stdin` (and any fd-0 type probe) flipped for every model-driven bash call, even though the code claimed the no-stdin path was unchanged. Spawn stdin as `'pipe'` only when the caller supplies bytes; otherwise `'ignore'` (fd 0 → /dev/null), the exact prior default. A literal `stdio` tuple per branch preserves the typed `spawn` overload's non-null stdout/stderr. Regression test asserts fd 0 is a char device with no stdin and a socket when supplied — proven red on the always-pipe code.
This commit is contained in:
@@ -22,7 +22,7 @@ Three deliberate choices:
|
||||
|
||||
3. **`stdin`/`env` are required-absent-OK (plain optional) on the resolved spec, NOT required-but-nullable like `owner`.** `owner` is required-but-nullable because a *silently* missing owner yields an unowned, cross-session-readable task — a security footgun that a visible `undefined` guards against. `stdin`/`env` have no such hazard: a missing one means "no stdin / no extra env", which is the safe, ordinary case (every model-driven call). So they stay plain optionals, matching `signal`.
|
||||
|
||||
`dsh-bash-local` now ALWAYS spawns stdin as a `'pipe'` and closes it immediately — with the supplied bytes when a caller set `stdin`, empty otherwise. A closed empty pipe gives a reading child EOF exactly as the previous `'ignore'` (`/dev/null`) did, so the no-stdin path is behavior-equivalent; keeping the `stdio` tuple a literal `['pipe','pipe','pipe']` also preserves the typed `spawn` overload that guarantees non-null `stdout`/`stderr`. A child that exits without reading makes the stdin write fail EPIPE; that error is swallowed (the command's outcome rides on its exit code/output, not the write) so it never crashes the host or rejects `done`.
|
||||
`dsh-bash-local` spawns stdin as a `'pipe'` (writing the supplied bytes, then closing) ONLY when a caller set `stdin`; with none supplied it uses `'ignore'` — fd 0 → `/dev/null` — the exact pre-seam default. This distinction is observable and deliberate: a closed empty pipe and `/dev/null` are NOT the same file type (node's spawn pipe is an `AF_UNIX` socket, so `test -c /dev/stdin` holds for `/dev/null` but not for an empty pipe), so the no-stdin path — every model-driven call — must keep `/dev/null` rather than regress to an always-open pipe. Each branch's `stdio` tuple is a literal, which preserves the typed `spawn` overload that guarantees non-null `stdout`/`stderr`. When stdin IS written, a child that exits without reading makes the write fail EPIPE; that error is swallowed (the command's outcome rides on its exit code/output, not the write) so it never crashes the host or rejects `done`.
|
||||
|
||||
## Scope: configurable scrub pattern is NOT included
|
||||
|
||||
|
||||
Reference in New Issue
Block a user