Repository navigation
feat: token auth and credential store - #12
Open
RogerCecilpot wants to merge 1 commit into
Open
RogerCecilpot wants to merge 1 commit into
RogerCecilpot wants to merge 1 commit into
Conversation
`devlyft auth login --with-token` reads an API token from stdin, checks it against the API (ListOrganizations, since the public API has no identity endpoint) and stores it with the organizations it can see. `auth status` checks the credential in use and shows its source (env|keyring|file); `auth token` prints it; `auth logout` deletes it (confirmation or --yes); `auth list` shows stored credentials without touching the keyring or the API. There is no --token flag. DEVLYFT_API_TOKEN takes precedence over stored credentials and is never written; with it set the credential store is not opened at all. internal/auth/credstore follows the #261 spike: go-keyring behind a timeout (3s off a TTY, 60s at one), any non-not-found keyring error falls back to credentials.json (0600 in a 0700 directory, atomic rename) with one warning naming the reason, and the keyring is skipped entirely in CI, in containers, under --insecure-storage, and on Linux without a session bus (so godbus never autolaunches dbus-launch). credentials.json also indexes every credential with its credential_store, so reads go straight to the right store. Also: - --api-url / DEVLYFT_API_URL, resolved in internal/config until contexts arrive (#244). - 401s from the API get the spec's hint: DEVLYFT_API_TOKEN is invalid or expired, or run `devlyft auth login`. - redact masks bare dvl_ API tokens. - The debug logger moves from cmdutil to internal/logging, so cmdutil can depend on the API facade without an import cycle in api's tests. Refs devlyft/devlyft#245 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RogerCecilpot
force-pushed
the
spike/261-credential-storage
branch
from
October 25, 2026 13:32
82ef0d4 to
d0d5548
Compare
RogerCecilpot
force-pushed
the
feat/245-token-auth
branch
from
October 25, 2026 13:32
cdbe1c3 to
a19d27f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes devlyft/devlyft#245.
Next in the stacked chain after #6 (
spike/261-credential-storage). Merge order: #2 → #5 → #3 → #4 → #8 → #9 → #10 → #7 → #6 → this.What
internal/cli/auth):auth login --with-token [--insecure-storage]: reads the token from stdin; refuses when stdin is a terminal or whenDEVLYFT_API_TOKENis set (exit 2). The token is checked against the API before it is stored.auth status: checks the credential in use and shows host, account, source (env|keyring|file) and organizations. Exit 3 when not logged in or rejected. Never prints the token.auth token: prints the token (help says it is sensitive).auth logout [--yes]: deletes the stored credential; confirms at a terminal, needs--yesotherwise.auth list: read-only; stored credentials plusDEVLYFT_API_TOKENif set. Touches neither the keyring nor the API.--format json|yaml,--jqand--quiet. There is no--tokenflag (a golden test pins that).internal/auth):DEVLYFT_API_TOKEN> stored credential for the API host. With the env var set, the credential store is never opened.auth.TokenSourceimplements the facade'sapi.TokenSource.internal/auth/credstore), as adjusted by the #261 spike:keyring.ErrNotFoundmaps to not found; any other error falls back tocredentials.jsonwith one warning naming the reason (no D-Bus session,no Secret Service provider,keyring is locked,keyring timed out,running in CI,running in a container)./.dockerenv,/run/.containerenv,$container), under--insecure-storage, and on Linux with no session bus. That last rule stops godbus autolaunchingdbus-launch. WSL is treated as headless Linux.credentials.json(mode 0600, directory 0700, atomic rename) is also the index: it records every credential'scredential_store, so reads go straight to the right store. Keyring-held entries carry no token. Replacing a keyring credential with a file one deletes the old keyring secret.credstore/mock, generated bymake generate.--api-url/DEVLYFT_API_URL/https://api.devlyft.io, ininternal/config.ResolveAPIURL, a small function for #244 to replace.devlyft auth login --with-tokento log in again.". This is set incli.execute, the single error path.redactnow also masks baredvl_…API tokens.internal/cmdutiltointernal/logging, socmdutil.Factorycan carry the API client factory without an import cycle ininternal/api's tests.Decisions worth a look
/me, and an API token's user-or-org scope isn't exposed.--with-tokenvalidates withListOrganizationsand records the organizations the token can see.auth statusshows them, which covers "org-scoped tokens show the org", but it can't show a user's email. AGET /v1/users/me(or a token-introspection endpoint) on the platform would fix that.defaultper host until contexts (#244) name accounts.auth loginis a usage error pointing at--with-tokenuntil #263.--insecure-storage. There's no silent fallback, because the file doesn't hold that token.Deferred
config.yaml. The credential index moves under it if wanted.Tests
credstore(89.5%): a fake keyring and injected environment. Covers each skip path with zero keyring calls, every error class falling back with one warning, timeout, stale and locked reads, delete with an unavailable keyring, list never touching the keyring, file and directory modes (skipped on Windows), bad and newer files, and the warning text per platform.auth(100%): precedence via the gomock store, error mapping and hints, and the token source resolving once.internal/cli/authat 91.5%).TestAuthNeverLeaksToken: runs the real HTTP client againsthttptestwith--verbosity debugand checks the token never reaches stderr or debug logs, and reaches stdout only throughauth token.🤖 Generated with Claude Code