Authenticate index requests to private registries#968
Open
sunsided wants to merge 3 commits into
Open
Conversation
`cargo upgrade` aborted with `status code '401 Unauthorized': the request was not authorized` whenever a workspace depended on a private registry with `auth-required = true`. `RemoteIndex::krate` builds the sparse-index request via tame-index's `make_remote_request`, which intentionally attaches no credentials, and cargo-edit never read or sent a registry token. The request therefore went out unauthenticated and the registry rejected it with 401. This was always broken for auth-required registries; before 0.13.2 the error was silently swallowed (the dependency was skipped), but killercup#925 made index errors propagate, so the 401 now aborts the whole run. Resolve the registry token (`CARGO_REGISTRIES_<NAME>_TOKEN`, then `token` under `[registries.<name>]` in credentials/config, walking `.cargo/` up to `$CARGO_HOME`) and attach it verbatim as the `Authorization` header, matching cargo. The crates.io index is left unauthenticated so its publish token is not leaked to the CDN-fronted sparse index. Fixes killercup#931
There was a problem hiding this comment.
Pull request overview
This PR updates cargo upgrade to authenticate sparse index requests for private registries by resolving a registry token (matching Cargo’s precedence rules) and attaching it as the Authorization header on the index HTTP request.
Changes:
- Added
registry_token()to resolve per-registry auth tokens from env/config/credentials files while explicitly opting out for the default (crates.io) registry. - Threaded an optional auth value through
IndexCache/RemoteIndexand attach it as theAuthorizationheader for remote sparse index requests. - Wired token lookup into
cargo upgrade, and added regression tests plus a changelog entry.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/registry.rs | Adds token resolution logic (registry_token) and unit tests for precedence/behavior. |
| src/lib.rs | Re-exports registry_token for use by binaries. |
| src/index.rs | Threads optional auth into remote index access and attaches Authorization header; adds request-capture tests. |
| src/bin/upgrade/upgrade.rs | Wires token resolution into the existing index lookup call in cargo upgrade. |
| CHANGELOG.md | Documents the fix in Unreleased notes. |
Comments suppressed due to low confidence (1)
src/index.rs:93
- IndexCache is keyed only by registry Url, but the RemoteIndex stores
authas state. If the same Url is queried with differentauthvalues in one run (e.g. default crates.io with None, then a named registry/source replacement mapping to the same Url with Some(token), or two names sharing an index Url), the cached RemoteIndex will keep the first auth value. This can either omit credentials (causing 401) or send a token on requests that were meant to be unauthenticated (credential leakage). Consider updating the cached RemoteIndex's auth on every access (or include auth in the cache key).
if !self.index.contains_key(registry) {
let index = AnyIndex::open(registry, self.certs_source, auth)?;
let index = AnyIndexCache::new(index);
self.index.insert(registry.clone(), index);
}
Ok(self.index.get_mut(registry).unwrap())
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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
cargo upgradenow sends the registry authentication token when querying a private sparse-registry index, so workspaces depending on anauth-required = trueregistry can be upgraded instead of failing with401 Unauthorized.Why
Reported in #931:
cargo upgrade --incompatiblefails withstatus code '401 Unauthorized': the request was not authorizedagainst a private registry, whilecargo search/build/testsucceed with the same credentials, and downgrading to 0.13.1 avoids it.The index request was always unauthenticated:
RemoteIndex::kratebuilds it via tame-index'smake_remote_request, which by design attaches no credentials, and cargo-edit never read or sent a token. Before 0.13.2 the resulting 401 was silently swallowed and the dependency skipped; #925 made index errors propagate, turning that long-standing gap into a hard failure that aborts the whole run.Key changes
registry_token()insrc/registry.rsresolves a registry's token fromCARGO_REGISTRIES_<NAME>_TOKEN, thentokenunder[registries.<name>]incredentials/configfiles, walking.cargo/from the manifest up to$CARGO_HOME.RemoteIndexcarries the token and attaches it verbatim as theAuthorizationheader on the index request, matching cargo (noBearerprefix is injected).IndexCacheto the single call site incargo upgrade.Authorizationheader is present with a token and absent without.Known gap: credential providers
Only static tokens are handled. The
CARGO_REGISTRIES_<NAME>_TOKENenv var and a plaintexttokenincredentials.toml/config.toml. Cargo credential providers (registries.<name>.credential-provider,[registry] global-credential-providers, e.g.cargo:token-from-stdout,cargo:libsecret, or anycredential-process) are not invoked. Users who keep their token in a provider rather than a plaintexttokenwill still hit the 401. Matching cargo's full credential-provider resolution is left as a follow-up.Review instructions
Start with
registry_token()insrc/registry.rs, resolution order and the crates.io opt-out. ThenRemoteIndex::krateinsrc/index.rs, where the header is attached right after the tame-index request is converted to a reqwest request. Thesrc/bin/upgrade/upgrade.rschange is just wiring the token into the existingindex.kratecall. Worth scrutiny: the token precedence (env over file, credentials over config, nearest dir first) and the decision to send the token verbatim.Closes #931