feat: Add buf beta registry cargo credential provider#4541
Open
kjvalencik wants to merge 1 commit into
Open
Conversation
Add a new `buf beta registry cargo` subcommand that implements Cargo's
`cargo:token-from-stdout` credential-provider protocol, so Cargo can
obtain a Bearer token for BSR-hosted Cargo registries by shelling out
to buf instead of storing tokens in `credentials.toml`.
Users configure it via `~/.cargo/config.toml`:
[registry]
global-credential-providers = ["cargo:token-from-stdout buf beta registry cargo"]
Behavior:
- Reads CARGO_REGISTRY_INDEX_URL, extracts the host (strips an optional
"sparse+" prefix, lowercases, drops the port).
- Checks the host against a positional-argument allow-list. With no
positional args the allow-list defaults to [buf.build]; positional
args replace (not extend) the default. Ports in positional args are
stripped so they compare equal to URL-extracted hosts.
- For an allow-listed host, resolves a token via the existing bufconnect
chain: BUF_TOKEN env var first, then ~/.netrc.
- On success, writes `Bearer <token>\n` to stdout and exits 0.
- For hosts outside the allow-list (or a missing/unparseable URL),
exits non-zero with no output so Cargo can fall through to its next
configured credential provider.
- For allow-listed hosts with no token, writes a "Failure: ..." message
pointing at `buf registry login` and exits non-zero.
- A malformed BUF_TOKEN produces a redacted user-visible error; the
underlying bufconnect parser error (which embeds the raw token value)
is logged at --debug level only.
No new bufconnect or authentication primitives are introduced; the
command is a thin orchestrator over existing token providers. Cargo
invokes credential providers on every dependency resolution, so the
implementation makes no network calls and constructs no Connect clients.
Includes command-level tests covering the silent/loud contract,
allow-list semantics, BUF_TOKEN precedence over .netrc, host
case-insensitivity, host:port normalization, and a leak-prevention
assertion that the BUF_TOKEN value never reaches stderr.
|
|
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.
Summary
Adds a new
buf beta registry cargosubcommand that implements Cargo'scargo:token-from-stdoutcredential-provider protocol. With this in place, Cargo can resolve a Bearer token for a BSR-hosted Cargo registry by shelling out tobuf, instead of users having to copy a token into~/.cargo/credentials.tomland keep two copies in sync.The command is registered under
betaso we have room to iterate on the UX before promoting it.Motivation
Today, a developer pulling crates from a BSR-hosted Cargo registry has to:
buf registry login buf.buildto authenticatebuf.~/.cargo/credentials.toml(orcargo login) so Cargo can use it.Two stores for one secret, two places to rotate, two places to leak. This change lets users delegate the second step to
buf:Now any
cargooperation against a BSR-hosted registry invokesbuf beta registry cargo, which resolves the token from the same chainbufalready uses (BUF_TOKENenv var, then~/.netrc).Configuration
Default — public BSR at
buf.build:Enterprise BSR (positional args replace the default;
buf.buildis not implicitly included):Multiple hosts:
Token management continues to flow through
buf registry login <host>; no Cargo-specific login is required.How it works
On each invocation Cargo sets
CARGO_REGISTRY_INDEX_URL(and other env vars per the spec) and reads a single line from stdout. The command:CARGO_REGISTRY_INDEX_URL(strips an optionalsparse+prefix, parses as a URL, lowercases, drops any port).[buf.build]). Allow-list entries are also lowercased and port-stripped sobsr.example.com:8443matchessparse+https://bsr.example.com:8443/....bufconnect.NewTokenProviderFromContainer(theBUF_TOKENenv var) and falls through tobufconnect.NewNetrcTokenProvider(~/.netrc).Bearer <token>\nto stdout and exits0.No Connect clients are constructed and no network calls are made — credential providers are on the hot path of every dependency resolution.
Failure semantics
CARGO_REGISTRY_INDEX_URLunset, unparseable, or host not in the allow-listFailure: no token found for <host>. Run "buf registry login <host>" ...bufhas no credentials for it — surface a fixBUF_TOKENis malformedFailure: the BUF_TOKEN environment variable could not be parsed. Either unset BUF_TOKEN, or run "buf registry login <host>" .... Underlying parser error is debug-onlybufconnectparse error embeds the raw token value, so the user-visible message is deliberately redactedPass
--debugto log host extraction, allow-list matching, and (when present) the rawBUF_TOKENparser error.Out of scope
cargo login/cargo logoutsupport — thecargo:token-from-stdoutprotocol explicitly doesn't support them.bufconnector any existing authentication primitive; this is a thin orchestrator over what's already there.Test plan
go test -race ./cmd/buf/internal/command/beta/registry/registrycargo/...(15 unit + command-level tests covering the contract matrix: unset URL, default and explicit allow-lists, scoped vs unscopedBUF_TOKEN, scoped-miss → netrc fallthrough, env-wins-over-netrc, netrc match + miss, uppercase URL host, uppercase positional, positionalhost:port, malformedBUF_TOKENwith leak-preventionNotContainsassertion).golangci-lint run ./cmd/buf/internal/command/beta/registry/registrycargo/...— 0 issues.go build ./...andgo vet ./...clean.CARGO_REGISTRY_INDEX_URL.Bearer <token>and exits 0.--debugsurfaces structured logs and (only with--debug) the rawBUF_TOKENparser error.BUF_TOKEN=secret@host,secret@host→ user-facing stderr does not containsecret; only the debug log does.Notes for review
cmd/buf/internal/command/beta/registry/registrycargo. The only touches outside it are a 2-line wiring change incmd/buf/buf.goand a 1-lineCHANGELOG.mdentry.errSilentsentinel for silent exits, following the same pattern asprivate/pkg/bandeps/cmd/bandeps/main.go. The top-levelwrapErrorincmd/buf/buf.goalready bypasses itsFailure:prefix whenerr.Error() == "".betaper the design discussion; promote tobuf registry cargoonce we've shipped to early users.