feat: support configurable CLI global config#1011
Conversation
| * Throws AbortError when the signal is aborted. | ||
| * Read a token from CLI-managed credentials. Uses `coder login token --url` | ||
| * when keyring auth is active, otherwise reads the file credentials under | ||
| * --global-config. Returns undefined on any failure (resolver, CLI, empty |
There was a problem hiding this comment.
Why not just use coder login token for both paths? It works for file-based storage as well. We will have call it with the global flags of course so it reads the right files.
This would also have the advantage of being able to get the token from the default config location, since right now we require the user to fill out a separate variable. nvm idk why I said that, we do still read credentials from the default location with the current setup.
There was a problem hiding this comment.
coder login token was only added in 2.31.0 (January of this year), we still need handle the older deployments and thus we need to read the file system
There was a problem hiding this comment.
We could do something like this:
- Is binary resolvable and >= 2.31?
- Use
coder login tokenfor both paths (delegates format knowledge to the CLI). - Otherwise keep the direct file read.
- Use
There was a problem hiding this comment.
I think it is reasonable to scope the feature to 2.31.0 personally, unless product has asked us to make older versions work?
There was a problem hiding this comment.
We're keeping the direct file read to support deployments older than 2.31.0, where coder login token doesn't exist. Even scoped to 2.31+, shelling out to read the url/session files the extension wrote is more work (binary resolution + process spawn).
I am confused by the "scope to 2.31.0" since this would affect all reads and not just the when users have a custom global-config
There was a problem hiding this comment.
shelling out to read the url/session files the extension wrote is more work
We should really be using coder login to write these as well IMO (this is how the Toolbox extension does it). As far as work, I suppose it is more overhead, but to me it feels like an anti-pattern for one tool to read/write the config of another tool, there is no public API or guarantee so we rely on internal knowledge of how the configs happen to work.
We're keeping the direct file read to support deployments older than 2.31.
If we have to do this, then we gotta do it. But if not, we could have a single code path and only support this token-sharing feature for 2.31.0 and above.
I am confused by the "scope to 2.31.0" since this would affect all reads and not just the when users have a custom global-config
Oh yeah this was unclear, I just meant scoping the token read feature, not the whole thing. So for versions lower than 2.31.0, readToken would always return undefined. In other words, if a user wants the plugin to read credentials created by the CLI, they would need to update to 2.31.0 or higher.
Actually, I guess we have two features mixed up in this PR, the global config, and also reading the token from the CLI when using file storage.
There was a problem hiding this comment.
Done. Write now uses coder login --use-token-as-session, read uses coder login token (2.31+, returns nothing below that), and delete uses coder logout. We no longer read or write the credential files ourselves except a pre-0.25 write fallback. Read and write floors differ (0.25 write, 2.31 read), which is fine.
But actually, can we drop support to pre-0.25? That feels old enough IMO
There was a problem hiding this comment.
100% agree we can drop support for <0.25, the Toolbox plugin does not support it either.
There was a problem hiding this comment.
In fact this was way back when we still had to use vscodessh which we straight up do not support anymore anyway, so it is impossible to use <0.25 already.
Wait no I misread the check lol, we do still support vscodessh 🤦 ignore me.
But! Maybe we can just update that minimum check for 0.14 to 0.25.
There was a problem hiding this comment.
Made the minimum 0.25 and dropped the file write/read 👀
9a72ccf to
6d03c00
Compare
|
With 7e5d315 we have the following. @code-asher I think this simplified things a bit and we can further cut down if we drop support for <0.25 (very old tbh - 3 years old). Global config / credential changes (vs
|
| Mode / version | main |
new |
|---|---|---|
| keyring (mac/win, 2.29+) | coder login --use-token-as-session <url> |
same |
| file, 0.25+ | extension writes <dir>/session + <dir>/url |
coder login --use-token-as-session <url> --global-config <dir> |
| file, <0.25 | extension writes the files | extension writes the files (fallback) |
READ
| Mode / version | main |
new |
|---|---|---|
| keyring (2.31+) | coder login token --url <url> |
same |
| file, 2.31+ | nothing (only keyring was read) | coder login token --url <url> --global-config <dir> |
| <2.31 | nothing | nothing |
DELETE
rm <default> files always runs: it is the only deleter when coder logout is unavailable (<0.25 or binary unresolvable), and it sweeps the default dir, which coder logout --global-config <override> does not touch.
| Mode / version | main |
new |
|---|---|---|
| keyring (2.29+) | coder logout --url <url> --yes + rm <default> files |
same |
| file, 0.25+ | rm <default> files only |
coder logout --url <url> --global-config <dir> --yes + rm <default> files |
| file, <0.25 / no binary | rm <default> files |
rm <default> files (no coder logout) |
Config dir / --global-config
main |
new | |
|---|---|---|
| Custom dir | not configurable | --global-config in coder.globalFlags (2.31+, file mode) |
| Binary cache | under <default> |
always plugin dir (coder.binaryDestination still applies) |
What it means for the user (vs main)
- New: point the extension at a shared CLI dir (
--global-config=~/.config/coderv2incoder.globalFlags) to share login with the terminalcoder, on 2.31+. - New: on 2.31+ the extension picks up file based CLI credentials (
mainonly read the keyring). - File writes/deletes now go through
coder login/coder logoutinstead of the extension touching the files directly. - No change for keyring users.
7e5d315 to
36cfde3
Compare
Split src/util.ts into focused modules: src/util/uri.ts (toSafeHost,
removeTrailingSlashes, resolveUiUrl, openInBrowser) and
src/util/authority.ts (Remote SSH authority helpers), replacing
src/uri/utils.ts. Migrate all importers and mirror the unit tests.
Make CliCredentialManager.readToken return the token together with its
source ("keyring" | "files") so LoginCoordinator labels the login
method from the actual source instead of re-deriving it from whether
keyring is enabled.
…malization - Add loginCoordinator test for the keyring_token method (source: "keyring") - Add comprehensive toRemoteAuthority tests over varied URI types - Test toSafeHost/normalizeUrl with Arabic alongside Japanese IDNs - Consolidate the trim + strip-trailing-slashes logic into a shared normalizeUrl in util/uri, reused by resolveUiUrl and cliCredentialManager
Replace the dedicated `coder.globalConfig` setting with a `--global-config` passthrough in `coder.globalFlags`, honored on 2.31.0+. The extension no longer reads/writes the CLI credential files itself: it writes via `coder login` (0.25.0+, `--use-token-as-session`), reads via `coder login token` (2.31.0+), and deletes via `coder logout` (keyring or file with `--global-config`). Direct file writes remain only as a pre-0.25 fallback. The binary cache no longer follows the config dir.
36cfde3 to
b69b20b
Compare
- Bump the minimum supported deployment version to 0.25.0 (where `coder login` lives), gating on `featureSet.cliLogin`, and move the compatibility check before credential configuration so older servers get a clear message. - Remove the pre-0.25 direct-file-write fallback; credential writes now always go through `coder login`. Drop the now-unused `vscodessh` feature flag and the dead `CredentialFileError` class plus its `filesystem`/`file` telemetry categories. - Collapse the `resolveCli` overloads into one throwing resolver; the best-effort read path catches instead. - Fix the stale `coder.globalConfig` CHANGELOG entry (the setting was dropped) and two pre-existing test typecheck breaks (`toSafeHost` import path and a `CliAuth.allowOverride` literal).
Routing file-mode credentials through `coder login`/`logout` means the credential binary resolver now runs in the login and logout flows, not just on connect. It previously fell back to `fetchBinary` on a cache miss, so a file-mode user's login (including auto-login on startup) or logout could trigger a surprise CLI download with a progress popup, where before it was silent file I/O. Make the resolver locate-only. The connect and CLI-command flows still fetch the binary first, so credential ops become best-effort against an already-present binary and never download on their own. If no binary exists yet, credential sharing is simply skipped until a real connection fetches one.
| // Locate-only: never download from credential ops; the connect and | ||
| // CLI-command flows fetch the binary first. | ||
| return this.cliManager.locateBinary(url); |
There was a problem hiding this comment.
locate-only means a keyring user with no binary yet won't get their terminal token picked up at first login until something fetches the binary (main would download for them). Keep it, or revert to download-on-demand?
I'm hesitant about downloading on login/logout because that doesn't seem very UX friendly
Summary
coder.globalConfigas a machine-scoped directory setting for the CLI--global-configpath, withCODER_CONFIG_DIRfallback and existing per-deployment storage as the default.PathResolver, CLI auth flags, credential file reads/writes/deletes, active remote reload prompts, and support bundle settings.Closes #185.
Testing
pnpm test:extension ./test/unit/cliConfig.test.ts ./test/unit/core/pathResolver.test.ts ./test/unit/core/cliCredentialManager.test.ts ./test/unit/login/loginCoordinator.test.ts ./test/unit/supportBundle/settings.test.tspnpm testpnpm typecheckpnpm lintpnpm format:checkpnpm buildgit diff --checkGenerated by Coder Agents.
Implementation plan
coder.globalConfigsetting for a directory path and keepcoder.globalFlagsfrom overriding managed--global-config/--use-keyringflags.PathResolver:coder.globalConfigfirst, thenCODER_CONFIG_DIR, then the existing<globalStorage>/<safeHostname>default.--urlfor active supported keyring auth, otherwise--global-config <resolvedDir>.