Skip to content

Viewport should fail hard when a child reads the controlling TTY directly (sudo PIN/askpass pierces the render) #25

Description

@sfriedenberg-etsy

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 / runProgramtea.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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions