Skip to content

hookdeck login opens a browser and hangs forever when there is no terminal #400

Description

@leggetter

Summary

hookdeck login opens a browser window and blocks indefinitely when there is no terminal, instead of failing fast with guidance.

Reproduce

With an empty config and no TTY:

hookdeck login --hookdeck-config <empty.toml> </dev/null   # stdout+stderr redirected

Output: Press Enter to open the browser (^C to quit)Waiting for confirmation...

It then opens a real browser window on the user's desktop and blocks. Killed at 60s with no sign of stopping on its own. This happened to a maintainer during testing.

Root cause

pkg/login/client_login.go:

  • Login() has the headless guard, but only inside if config.Profile.APIKey != "" (~line 62):
    needsStdin := !isSSH() && canOpenBrowser()
    if !stdinIsTerminal() && needsStdin { return ErrRejectedKeyNoTerminal }
  • With an empty config that entire block is skipped, so execution reaches waitForLoginSession() unguarded.
  • There (~line 120) the else-branch does fmt.Printf("Press Enter to open the browser (^C to quit)"), then fmt.Fscanln(input), then openBrowser(...). With stdin at /dev/null, Fscanln returns instantly on EOF and the browser opens anyway.

The comment above the existing guard reads "mirroring the branch in waitForLoginSession" — so the branch was known about, and only the rejected-key path was guarded.

The isSSH() || !canOpenBrowser() branch prints a URL and polls without reading stdin. That works headlessly and must keep working.

Why this matters

Any CI job, Dockerfile, nohup script or coding agent that runs hookdeck login hangs indefinitely and spawns browser processes.

It also means the v2.5.0 release-note claim for #337"Unauthenticated commands no longer hang for four minutes… Without a terminal it now exits immediately with instructions" — was never true for hookdeck login itself.

Two sub-issues on the same line

  • Press Enter to open the browser (^C to quit) has no trailing newline, so it runs straight into Waiting for confirmation....
  • It advertises ^C to quit while holding no terminal that can deliver ^C.

Suggested fix

Apply the same guard on the fresh-login path, with an error matching the quality of the existing rejected-key message — naming hookdeck ci --api-key, hookdeck login --cli-key, and HOOKDECK_API_KEY as the ways forward.

Testing

Unit: pkg/login/client_login_test.go already stubs stdinIsTerminal and canOpenBrowser. Cover no-key + no-terminal + browser-capable → fast error and no browser; no-key + no-terminal + SSH → still prints the URL and polls.

Related


Filed by Claude on Phil's behalf, from release-candidate testing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions