Skip to content

fix(config): stop config create spinning forever on closed stdin - #179

Merged
tas50 merged 1 commit into
mainfrom
fix/config-create-eof-hang
Sep 8, 2026
Merged

fix(config): stop config create spinning forever on closed stdin#179
tas50 merged 1 commit into
mainfrom
fix/config-create-eof-hang

Conversation

@tas50

@tas50 tas50 commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

The defect

promptNoDefault swallows io.EOF and returns "". The "New profile name" loop in promptExistingFileAction rejects an empty name and continues, so with nothing left on stdin it asks again forever.

$ cinc config create < /dev/null   # with an existing ~/.cinc/credentials

A probe measured 57,593,758 prompts in 20 seconds, at 100% CPU, flooding stdout. Nothing exotic is needed to reach it: the action prompt defaults to "Add a new profile", so any non-interactive invocation against a credentials file that already holds profiles hangs. That includes CI jobs and anything piping input.

promptProfilePicker survives the same treatment only by accident, because its empty answer happens to map onto the default "1".

The fix

Separate the two cases a bare "" was conflating:

  • An empty line stays a real answer. The collision prompt (Update it instead? [Y/n]) and the replace prompt (Replace the file? [y/N]) both treat Enter as their default, and that still works.
  • A reader with nothing left to give now returns errStdinExhausted, which names the flags that configure a profile without prompting.

promptWithDefault is deliberately left alone. Returning the default on EOF is exactly what lets the onboarding flow accept defaults, and it has no loop to spin in.

Tests

TestConfigureStopsWhenStdinIsExhausted drives the real command with a closed stdin behind a 10s timeout. It fails on main by never returning (reporting the prompt count) and passes here.

go test ./..., go vet ./..., and gofmt -l . are all clean.

@tas50
tas50 force-pushed the fix/config-create-eof-hang branch from 698e1aa to 827d212 Compare September 8, 2026 15:15
`promptNoDefault` swallowed io.EOF and returned an empty string, so the
"New profile name" loop in `promptExistingFileAction` rejected the empty
answer and asked again, forever. Running `cinc config create < /dev/null`
against a credentials file that already had profiles pinned a core and
flooded stdout: a probe measured 57 million prompts in 20 seconds.

The action prompt defaults to "Add a new profile", so nothing unusual is
needed to reach it: any non-interactive invocation with an existing
credentials file hangs.

`promptNoDefault` now separates the two cases a bare `""` used to
conflate. An empty line is still a real answer (the collision and replace
prompts treat Enter as their default), but a reader with nothing left to
give returns errStdinExhausted, which names the flags that configure a
profile without prompting.

`promptWithDefault` is deliberately unchanged: falling back to the
default on EOF is what lets the onboarding flow accept defaults, and it
cannot loop.

Signed-off-by: Tim Smith <tim@mondoo.com>
@tas50
tas50 force-pushed the fix/config-create-eof-hang branch from 827d212 to 16e0125 Compare September 8, 2026 17:32
@tas50
tas50 merged commit 8dcc905 into main Sep 8, 2026
6 checks passed
@tas50
tas50 deleted the fix/config-create-eof-hang branch September 8, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant