#16427

CLI: keychain read errors over SSH or without Secret Service are reported as "(no credentials)" (macOS + Linux)

OpenSrini-Bopened 10d ago

Version

but 0.22.3 (latest release) on both machines.

Operating System

macOS and Linux

Distribution Method

  • macOS: dmg (Mac OS - Apple Silicon). but is the app's bundled CLI, symlinked from ~/.local/bin/but to GitButler.app/Contents/MacOS/gitbutler-tauri.
  • Linux: standalone but binary in ~/.local/bin.

Describe the issue

but cannot read a valid stored GitHub token when it runs outside the user's desktop login session. It then reports that no credentials exist:

  • but config forge shows OAuth: <user> (no credentials) and Some accounts have invalid or missing credentials. Re-authenticate using: but config forge auth.
  • but pr new and but pr set-ready fail with No authenticated forge users found. Run 'but config forge auth' to authenticate with GitHub.

The token is present and valid. In the same user's desktop terminal, but config forge shows the account with valid credentials. The real problem is that the credential store is locked or cannot be reached from that process. The suggested fix, but config forge auth, is therefore misleading. It cannot repair a locked keychain, and it replaces a token that is still valid.

How we run but

We run but from an AI coding agent (Amp). The agent runs every command non-interactively, with no TTY and TERM=dumb, and it cannot answer any prompt.

  • macOS (Apple Silicon, macOS 26.6.2). The agent runner is a long-running local process (amp --no-tui --runner-id …) on the Mac. It runs each command directly as a child process, not over a new SSH connection. The runner was started from an SSH login (over Tailscale, from another of our Macs) and kept running after that login ended. It and every but command it runs inherit that session: launchctl managername returns Background, not Aqua. The same user is logged in to the GUI at the same time, and GitButler works normally there. From the runner's session, the login keychain cannot be read:
    • security show-keychain-info ~/Library/Keychains/login.keychain-db returns User interaction is not allowed.
    • security find-generic-password -s "com.gitbutler.app-github_oauth_<user>" -a GitButler finds the item. The token entry exists.
    • Reading the secret with -w fails with exit code 36, because the keychain is locked for this session.
  • Linux (Ubuntu 26.04.1, x86_64). The agent runner (amp --no-tui) runs as the user, and gnome-keyring serves Secret Service on the normal user bus (unix:path=/run/user/1000/bus).
    • Commands with that bus work. Both plain ssh host 'but config forge' and the runner's own environment report (valid credentials).
    • The runner also starts a remote desktop session under dbus-run-session, which has its own private session bus without gnome-keyring. A process with that bus, or with no session bus, gets the same false (no credentials):
$ DBUS_SESSION_BUS_ADDRESS="unix:path=/tmp/dbus-XXXX" but config forge
  • OAuth: <user> (no credentials)
Some accounts have invalid or missing credentials.

$ env -u DBUS_SESSION_BUS_ADDRESS -u XDG_RUNTIME_DIR but config forge
  • OAuth: <user> (no credentials)
Some accounts have invalid or missing credentials.

$ but config forge   # normal user bus
  • OAuth: <user> (valid credentials)

Where the error is lost

but_secret::retrieve() maps only keyring::Error::NoEntry to Ok(None). It returns every other failure as an error, and annotate_keychain_error() adds a description such as "System keychain is not available". find_github_account() in crates/but-github/src/token.rs (lines 306, 322 and 341 at 9fc1a24) then discards those errors:

retrieve_github_secret(access_token_key).ok().flatten()

As a result, a locked macOS Keychain (errSecInteractionNotAllowed), an unreachable Secret Service, or a wrong session bus all look the same as a missing token. The CLI cannot report the real cause.

Related

  • #15870 covers headless Linux forge auth. Its fix, BUT_CREDENTIALS_DIRECTORY (commit 0652bf3, 2026-09-23), is not in a release yet; 0.22.3 is the latest. It is also Linux-only, so macOS-over-SSH still has no workaround.
  • #10784 is the broader discussion of secret storage.

How to reproduce (Optional)

macOS:

  1. Run but config forge auth in a GUI terminal, and confirm that but config forge shows valid credentials.
  2. SSH into the same Mac as the same user, while the GUI session stays logged in. A long-running process started from that SSH login, then detached, behaves the same way.
  3. Run but config forge. It shows (no credentials).
  4. In a repository with a pushed branch, run but pr new <branch>. It fails with No authenticated forge users found.

Linux:

  1. Authenticate with but config forge auth in a session where gnome-keyring is reachable.
  2. Run DBUS_SESSION_BUS_ADDRESS=<a private bus from dbus-run-session> but config forge, or unset DBUS_SESSION_BUS_ADDRESS and XDG_RUNTIME_DIR.
  3. It shows (no credentials).

Expected behavior (Optional)

  1. Report the real cause. When the token cannot be read because of a keychain or Secret Service error, show that error, for example "Keychain is locked or cannot be reached from this session". Do not report it as missing credentials. Show re-auth advice only after a confirmed NoEntry.
  2. Support non-interactive use on macOS. Give headless sessions a supported way to authenticate. Options include a token environment variable such as BUT_GITHUB_TOKEN or GH_TOKEN, using gh auth token when it is available, or making BUT_CREDENTIALS_DIRECTORY work on macOS as well.
  3. Release the Linux fallback. Ship BUT_CREDENTIALS_DIRECTORY in a release, and document it for SSH, agent and CI use.

Relevant log output (Optional)

$ but config forge
Authenticated GitHub accounts:

  • OAuth: <user> (no credentials)

Some accounts have invalid or missing credentials.
Re-authenticate using: but config forge auth

$ but pr new my-branch --draft -F msg.txt
Error: Failed to create forge review for branch.

Caused by:
    No authenticated forge users found.
    Run 'but config forge auth' to authenticate with GitHub.

$ security show-keychain-info ~/Library/Keychains/login.keychain-db
security: SecKeychainCopySettings /Users/<user>/Library/Keychains/login.keychain-db: User interaction is not allowed.

Activity

0

No activity yet.