Skip to content

auth login/status/doctor hang forever (no timeout) when keyring's D-Bus handshake stalls; BASECAMP_NO_KEYRING=1 works but is undocumented #800

Description

@jethrojones

Summary

Any basecamp command that touches stored credentials (auth login, auth status, doctor, projects list, etc.) hangs forever, with no error and no timeout, on a Linux desktop where a D-Bus session bus and gnome-keyring-daemon are both present and working normally. Root cause: the github.com/zalando/go-keyring Secret Service (D-Bus) backend's low-level D-Bus auth handshake never completes, and nothing times it out.

Environment

  • basecamp version 0.11.0
  • Linux (Omarchy/Hyprland desktop), gnome-keyring-daemon running (pkcs11,secrets components), registered on the session bus as org.freedesktop.secrets / org.gnome.keyring
  • dbus-send --session ... org.freedesktop.DBus.ListNames works fine and returns immediately — the bus itself and other D-Bus clients are healthy
  • System clock is NTP-synced

Reproduction

$ basecamp auth status --json
# hangs indefinitely, no output, no timeout

Same hang on basecamp doctor --json, basecamp auth login (both default browser flow and --device-code/--remote), and any data command like basecamp projects list once credentials need to be read. --version and --help return instantly (they don't touch the credential store), which is what pointed us at credential storage rather than the network as the culprit — a plain curl -v https://3.basecamp.com / https://launchpad.37signals.com completes in well under 200ms the whole time this is hanging, ruling out a network/proxy issue.

Diagnosis

Sent SIGQUIT to the hung process to get a goroutine dump (Go's default behavior — dumps all stacks and exits). The main goroutine is parked here even during a device-code login after the OAuth exchange has already succeeded (Authorization.GetInfo and People.Me both completed):

goroutine 1 [chan receive]:
...
github.com/zalando/go-keyring.secretServiceProvider.Set(...)
	github.com/zalando/go-keyring@.../secret_service/...
...

with a companion goroutine permanently blocked reading from the D-Bus unix socket during the SASL/EXTERNAL auth handshake:

github.com/godbus/dbus/v5.(*Conn).inWorker(...)
	github.com/godbus/dbus/v5@v5.2.2/conn.go:390
net.(*UnixConn).ReadMsgUnix(...)
internal/poll.(*FD).ReadMsg(...)

So: the CLI opens its own new D-Bus connection (rather than reusing/sharing the session bus connection other tools use) to talk to the Secret Service, and on this machine that connection's auth handshake never resolves — even though the exact same bus is trivially reachable via dbus-send in another process at the same moment. Whatever the cause on the D-Bus/gnome-keyring side, the CLI has no timeout around this call, so it wedges the whole process (and, transitively, auth login, auth status, and doctor, since they all go through the same credential store).

Confirmed workaround

Setting BASECAMP_NO_KEYRING=1 (an env var already compiled into the binary, presumably intended for exactly this) skips the keyring path entirely and every command returns instantly:

$ BASECAMP_NO_KEYRING=1 basecamp auth status --json
{"ok":true,"data":{"authenticated":true,...}}   # instant

This isn't documented anywhere in --help output (auth --help, config --help, top-level --help), so it took a strings pass over the binary to discover. Also worth noting: basecamp already has a message for the explicit-error keyring-unavailable case ("system keyring unavailable (%v), credentials stored in plaintext at %s"), it just doesn't reach that fallback when the keyring call hangs instead of erroring.

Suggested fixes

  1. Wrap the keyring Set/Get calls in a bounded context/timeout (a few seconds is plenty) and fall back to the existing plaintext-storage path on timeout, the same as the existing "keyring unavailable" error path.
  2. Document BASECAMP_NO_KEYRING in --help output and/or basecamp doctor, so people hitting this don't have to reverse-engineer it.
  3. Possibly related to the gnome-keyring Secret Service/D-Bus issues already tracked in basecamp/hey-cli#352 and basecamp/hey-cli#453 (see also this comment diagnosing the OpenSession/GVariant assertion chain on GNOME Keyring 50.0 on Omarchy) — different symptom (daemon aborts vs. a client-side hang with no timeout), same subsystem (zalando/go-keyring + gnome-keyring D-Bus Secret Service on Omarchy/Hyprland), so may share a root cause worth checking together.

Happy to provide the full goroutine dump or test further if useful.

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