Symptom
While running a command pipeline through the crap viewport (:: exec ... | crap-present), one of the wrapped commands tried to prompt for a sudo PIN / password. sudo (and other auth prompts like pinentry) does not read from the program's stdin pipe — it opens the controlling TTY directly (/dev/tty) for both the prompt write and the secret read. This pierces the viewport: the prompt text and the user's keystrokes land on the same terminal the bubbletea TUI is rendering to, corrupting the live frame and the secret entry.
Concrete trigger (from eng): spinclass merge-this-session's pre-merge hook runs just build-nix build-home-dry validate-formatting. The build-home-dry recipe runs sudo cmp, sudo cp, and sudo darwin-rebuild build — each can fire a TTY-direct sudo prompt mid-viewport.
The two halves
This issue is the viewport-hardening half. The other half — running sudo so it prompts outside stdin/the controlling TTY — is tracked in the spinclass issue crosslinked below (it's an eng/spinclass-side recipe + askpass concern, not a crap concern).
Ask (this repo)
The viewport reads its record stream on a pipe and explicitly gives the bubbletea program an empty input reader so keystrokes are never consumed from the data pipe (see viewport/present.go Present / runProgram — tea.WithInput(strings.NewReader(""))). But nothing stops a child process spawned under a :: exec node from opening /dev/tty directly and reading from it.
We want the viewport (or the :: exec producer) to fail hard / surface a clear diagnostic when a child attempts to read the controlling TTY that wasn't explicitly handed to it, rather than silently letting the prompt corrupt the render and the secret entry. Open questions to evaluate:
- Where does the guard live —
:: exec (it owns the child's process attributes, go-crap/exec.go) or crap-present (it owns the terminal)?
- Can
:: exec run the child with no controlling TTY (new session / detached from /dev/tty) so a /dev/tty open fails loudly, turning the silent pierce into a clean node failure with a diagnostic?
- Is there a legitimate case where a viewport-wrapped command should be allowed to prompt? If so, that path needs an explicit opt-in/passthrough rather than the current implicit inheritance. (Relates to the broader "TTY-queried tools within viewports" evaluation.)
Acceptance
- A
:: exec-wrapped child that tries to read /dev/tty produces a deterministic node failure with a diagnostic naming the TTY-pierce, instead of a corrupted viewport.
- No regression to normal output capture (stdout/stderr →
output records).
Crosslink: amarbel-llc/spinclass#144 (run sudo in the merge hook so it prompts off-stdin / off-TTY).
:clown: filed with Clown 0.4.0+cd38c2d
amarbel-llc/clown@cd38c2d
Symptom
While running a command pipeline through the crap viewport (
:: exec ... | crap-present), one of the wrapped commands tried to prompt for a sudo PIN / password.sudo(and other auth prompts like pinentry) does not read from the program's stdin pipe — it opens the controlling TTY directly (/dev/tty) for both the prompt write and the secret read. This pierces the viewport: the prompt text and the user's keystrokes land on the same terminal the bubbletea TUI is rendering to, corrupting the live frame and the secret entry.Concrete trigger (from eng):
spinclass merge-this-session's pre-merge hook runsjust build-nix build-home-dry validate-formatting. Thebuild-home-dryrecipe runssudo cmp,sudo cp, andsudo darwin-rebuild build— each can fire a TTY-direct sudo prompt mid-viewport.The two halves
This issue is the viewport-hardening half. The other half — running
sudoso it prompts outside stdin/the controlling TTY — is tracked in the spinclass issue crosslinked below (it's an eng/spinclass-side recipe + askpass concern, not a crap concern).Ask (this repo)
The viewport reads its record stream on a pipe and explicitly gives the bubbletea program an empty input reader so keystrokes are never consumed from the data pipe (see
viewport/present.goPresent/runProgram—tea.WithInput(strings.NewReader(""))). But nothing stops a child process spawned under a:: execnode from opening/dev/ttydirectly and reading from it.We want the viewport (or the
:: execproducer) to fail hard / surface a clear diagnostic when a child attempts to read the controlling TTY that wasn't explicitly handed to it, rather than silently letting the prompt corrupt the render and the secret entry. Open questions to evaluate::: exec(it owns the child's process attributes,go-crap/exec.go) orcrap-present(it owns the terminal)?:: execrun the child with no controlling TTY (new session / detached from/dev/tty) so a/dev/ttyopen fails loudly, turning the silent pierce into a clean node failure with a diagnostic?Acceptance
:: exec-wrapped child that tries to read/dev/ttyproduces a deterministic node failure with a diagnostic naming the TTY-pierce, instead of a corrupted viewport.outputrecords).Crosslink: amarbel-llc/spinclass#144 (run sudo in the merge hook so it prompts off-stdin / off-TTY).
:clown: filed with Clown 0.4.0+cd38c2d
amarbel-llc/clown@cd38c2d