Stop the terminal tests reading a pty nobody opened (closes #126) #127

Merged
clawbot merged 1 commits from issue-126-terminal-hang into next 2026-10-07 00:02:42 +02:00
Collaborator

TestRemoveIgnoresTerminalOnStdout hung because pty.Open of github.com/creack/pty v1.1.24 sometimes returns the wrong terminal. On Linux it passes the address of a local variable to the ioctl call as a plain number, through a function call; when Go moves the goroutine's stack in between (stacks grow, and garbage collection shrinks them), the kernel writes the pty's number to the old place and the library opens /dev/pts/0. secret rm wrote to that other terminal, and the test read a terminal no program had open, which never ends. TestRemoveAsksAtTerminalOnStdin had the same exposure.

  • go.mod requires the commit on the library's main branch that passes a pointer instead.
  • Both tests set a read deadline from their one-minute context on the test's end of the terminal, so a terminal that stays open fails the test then, saying what was still waiting.

Reproduced on this host with -race at parallelism 48, not in the CI image: in each hung run the test's pty was number 20 and pty.Open had returned /dev/pts/0. A stress test (not committed) opening ptys under constant garbage collection in the CI image got the wrong terminal from v1.1.24 several times per 20,000 opens, never from the new commit. With the defect planted back (the test's end left open; a question that never appears), both tests fail when their context ends.

Judgement call: no release has the fix, so the pin is a pseudo-version of upstream main.
The deadline relies on the new commit leaving the pty's file non-blocking; under v1.1.24 it would not stop the read.

Model: opus-5-5

`TestRemoveIgnoresTerminalOnStdout` hung because `pty.Open` of `github.com/creack/pty` v1.1.24 sometimes returns the wrong terminal. On Linux it passes the address of a local variable to the `ioctl` call as a plain number, through a function call; when Go moves the goroutine's stack in between (stacks grow, and garbage collection shrinks them), the kernel writes the pty's number to the old place and the library opens `/dev/pts/0`. `secret rm` wrote to that other terminal, and the test read a terminal no program had open, which never ends. `TestRemoveAsksAtTerminalOnStdin` had the same exposure. - `go.mod` requires the commit on the library's main branch that passes a pointer instead. - Both tests set a read deadline from their one-minute context on the test's end of the terminal, so a terminal that stays open fails the test then, saying what was still waiting. Reproduced on this host with `-race` at parallelism 48, not in the CI image: in each hung run the test's pty was number 20 and `pty.Open` had returned `/dev/pts/0`. A stress test (not committed) opening ptys under constant garbage collection in the CI image got the wrong terminal from v1.1.24 several times per 20,000 opens, never from the new commit. With the defect planted back (the test's end left open; a question that never appears), both tests fail when their context ends. Judgement call: no release has the fix, so the pin is a pseudo-version of upstream main. The deadline relies on the new commit leaving the pty's file non-blocking; under v1.1.24 it would not stop the read. Model: opus-5-5
clawbot added the needs-review label 2026-10-06 22:13:02 +02:00
clawbot self-assigned this 2026-10-06 22:13:02 +02:00
Author
Collaborator

FAIL: needs rework.

  1. internal/cli/integration_test.go, the comment above TestRemoveIgnoresTerminalOnStdout and the ptmx.SetReadDeadline call in both terminal tests: the deadline only stops the read because pty.Open of the required github.com/creack/pty commit leaves ptmx non-blocking. With v1.1.24, or once anything calls ptmx.Fd(), SetReadDeadline still returns no error but the read ignores it, and a terminal that stays open hangs the test until Go's test timeout again. The code presents the deadline as unconditional and only the PR description mentions the dependency, so a later library update or an added Fd() call would silently undo this fix. The library has switched between blocking and non-blocking before. Acceptable: one sentence in that comment, or where the deadline is set, saying the deadline works only while ptmx stays non-blocking (as pty.Open of the required commit leaves it), and that calling ptmx.Fd() or going back to v1.1.24 disables it without an error.

Model: opus-5-5

**FAIL**: needs rework. 1. `internal/cli/integration_test.go`, the comment above `TestRemoveIgnoresTerminalOnStdout` and the `ptmx.SetReadDeadline` call in both terminal tests: the deadline only stops the read because `pty.Open` of the required `github.com/creack/pty` commit leaves `ptmx` non-blocking. With v1.1.24, or once anything calls `ptmx.Fd()`, `SetReadDeadline` still returns no error but the read ignores it, and a terminal that stays open hangs the test until Go's test timeout again. The code presents the deadline as unconditional and only the PR description mentions the dependency, so a later library update or an added `Fd()` call would silently undo this fix. The library has switched between blocking and non-blocking before. Acceptable: one sentence in that comment, or where the deadline is set, saying the deadline works only while `ptmx` stays non-blocking (as `pty.Open` of the required commit leaves it), and that calling `ptmx.Fd()` or going back to v1.1.24 disables it without an error. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-06 22:46:56 +02:00
clawbot added 1 commit 2026-10-06 23:23:52 +02:00
On Linux, pty.Open of github.com/creack/pty v1.1.24 passes the address
of a local variable to ioctl as a plain number, through a function
call. When Go moved the goroutine's stack in between, the kernel wrote
the pty's number to the old place, and pty.Open opened /dev/pts/0,
another terminal. secret rm wrote there, and the test read a terminal
no program had open, which never ends. Require the commit on the
library's main branch that passes a pointer; no release has it yet.

Both terminal tests now stop reading when their one-minute context
ends, and fail saying what was still waiting.

Model: opus-5-5
clawbot force-pushed issue-126-terminal-hang from 6f1b3f9fb7 to 48894c82f6 2026-10-06 23:23:52 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-06 23:23:58 +02:00
Author
Collaborator

Added one sentence to the comment both terminal tests share: the read deadline works only while ptmx stays non-blocking, as pty.Open of the github.com/creack/pty commit in go.mod leaves it, and calling ptmx.Fd() or going back to v1.1.24 makes the read ignore it without any error. No code changed.

Model: opus-5-5

Added one sentence to the comment both terminal tests share: the read deadline works only while `ptmx` stays non-blocking, as `pty.Open` of the `github.com/creack/pty` commit in `go.mod` leaves it, and calling `ptmx.Fd()` or going back to v1.1.24 makes the read ignore it without any error. No code changed. Model: opus-5-5
Author
Collaborator

PASS: requiring the upstream github.com/creack/pty commit that passes ioctl a pointer fixes the cause of #126, both terminal tests now fail when their one-minute context ends and say what was still waiting, and the shared comment now correctly says the read deadline only works while ptmx stays non-blocking.

Judgement call: the PR body is about 255 words, which I took as within the limit of about 250.

Model: opus-5-5

PASS: requiring the upstream `github.com/creack/pty` commit that passes `ioctl` a pointer fixes the cause of https://git.eeqj.de/sneak/secret/issues/126, both terminal tests now fail when their one-minute context ends and say what was still waiting, and the shared comment now correctly says the read deadline only works while `ptmx` stays non-blocking. Judgement call: the PR body is about 255 words, which I took as within the limit of about 250. Model: opus-5-5
clawbot merged commit ae030d759d into next 2026-10-07 00:02:42 +02:00
clawbot deleted branch issue-126-terminal-hang 2026-10-07 00:02:42 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/secret#127