Skip to content

Commit 2609dc0

Browse files
authored
Merge pull request #3289 from arlosi/sr
RFC: resolve crates.io source replacement ambiguity
2 parents 796e5e2 + 894b770 commit 2609dc0

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
- Feature Name: source_replacement_ambiguity
2+
- Start Date: 2022-07-05
3+
- RFC PR: [rust-lang/rfcs#3289](https://github.com/rust-lang/rfcs/pull/3289)
4+
- Tracking Issue: [rust-lang/cargo#10894](https://github.com/rust-lang/cargo/issues/10894)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
When Cargo is performing an API operation (`yank`/`login`/`publish`/etc.) to a source-replaced `crates-io`, require the user to pass `--registry <NAME>` to specify exactly which registry to use. Additionally, ensure that the token for `crates-io` is never sent to a replacement registry.
10+
11+
# Motivation
12+
[motivation]: #motivation
13+
14+
There are multiple issues that this RFC attempts to resolve around source-replacement.
15+
16+
* When Cargo is performing an API operation, source replacement is only respected for `crates-io`, not alternative registries. This is inconsistent.
17+
* The [error message](https://github.com/rust-lang/cargo/issues/6722) for attempting to publish to a replaced crates-io is confusing, and there is no workaround other than temporarily removing the source replacement configuration.
18+
* When performing an API operation other than `publish` with a replaced `crates-io` source, the `crates-io` credentials are sent to the replacement registry's API. This is a security risk.
19+
* It's unclear which credentials should be used when fetching a source-replaced authenticated alternate registry ([RFC 3139][3139]).
20+
21+
# Guide-level explanation
22+
[guide-level-explanation]: #guide-level-explanation
23+
24+
When the `crates-io` source is replaced, the user needs to specify `--registry <NAME>` when running an API operation to disambiguate which registry to use. Otherwise, `cargo` will issue an error.
25+
26+
`cargo` only sends the token associated with a given registry to that registry and no other (even if source replacement is configured).
27+
28+
When replacing a source with a registry, the `replace-with` key can reference the name of a registry in the `[registries]` table.
29+
30+
## Example scenarios
31+
32+
### Local source replacement (vendoring)
33+
A repository has a local `.cargo/config.toml` that vendors all dependencies from crates.io. Fetching and building within the repository would work as expected with the vendored sources.
34+
35+
If the user decides to publish the crate, `cargo publish --registry crates-io` will ignore the source-replacement and publish to crates.io.
36+
37+
### `crates-io` mirror registry
38+
A server has been set up that provides a complete mirror of crates.io. The user has configured a `~/.cargo/config.toml` that points to the mirror registry in the `[registries]` table. The mirror requires authentication to access (based on [RFC 3139][3139]).
39+
40+
The user can log in to the mirror using `cargo login --registry mirror`. Fetching and building use the mirror.
41+
42+
The user decides to publish the crate to crates.io, and does `cargo login --registry crates-io` to log in to crates.io. Source replacement is ignored, and the token is saved.
43+
44+
Next, the user runs `cargo publish --registry crates-io` to publish to crates.io. Cargo ignores source replacement when building and publishing the crate to crates.io.
45+
46+
# Reference-level explanation
47+
[reference-level-explanation]: #reference-level-explanation
48+
49+
### Change 1: respect `--registry`
50+
When running an API operation (`login`, `logout`, `owner`, `publish`, `search`, `yank`), Cargo always uses the registry specified by `--registry <NAME>`, and never a source-replacement.
51+
52+
### Change 2: error for replaced crates-io
53+
When running an API operation (as defined above) and ALL of the following are true:
54+
* `crates-io` has been replaced by a remote-registry source.
55+
* command line argument `--registry <NAME>` is not present.
56+
* command line argument `--index <URL>` is not present.
57+
* `Cargo.toml` manifest key `publish = <NAME>` is not set (only applies for publishing).
58+
59+
`cargo` issues an error:
60+
```
61+
error: crates-io is replaced: use `--registry replacement` or `--registry crates-io`
62+
```
63+
64+
### Change 3: credentials are only sent to the same registry
65+
If the `crates-io` source is replaced with another remote registry, the credentials for
66+
`crates-io` are never sent to the replacement registry. This makes `crates-io` consistant
67+
with alternative registries and ensures credentials are only sent to the registry they are
68+
associated with.
69+
70+
### Change 4: `[source]` table can reference `[registries]` table
71+
The `replace-with` key in the `[source]` table can reference a registry defined in the `[registries]` table.
72+
73+
For example, the following configuration would be valid:
74+
75+
```
76+
[source.crates-io]
77+
replace-with = "my-registry"
78+
79+
[registries.my-registry]
80+
index = "https://my-registry-index/"
81+
```
82+
83+
This is necessary to allow the `--registry <NAME>` command-line argument to work with source-replaced registries. It also allows additional configuration (such as a token) to be specified for a source-replacement registry without duplicating configuration between `[registries]` and `[source]` tables.
84+
85+
# Drawbacks
86+
[drawbacks]: #drawbacks
87+
88+
Behavior is changed around where credentials are sent, which could break some workflows.
89+
90+
If a mirror of crates.io is set up with `config.json` containing `"api": "https://crates.io"`, then the current system of sending the crates.io token to the replaced source would work correctly, and this RFC would break it.
91+
92+
# Rationale and alternatives
93+
[rationale-and-alternatives]: #rationale-and-alternatives
94+
95+
## Alternative: ignore source replacement for API operations
96+
When doing an API operation with a replaced `crates-io`, `cargo` would ignore source replacement without additional arguments. This is how alternative registries currently work.
97+
98+
If the user wants to use the replacement, they could pass `--registry <NAME>`, but would not be required to do so.
99+
100+
A new option `--respect-source-config` could be added to make cargo follow the source replacement for API operations (similar to what we already have for `cargo vendor`).
101+
102+
This may be too confusing for users since it silently changes behavior. The RFC proposes a solution that requires the user to be explicit about which registry to use in the ambiguous situation (crates-io replacement).
103+
104+
## Alternative: disallow source replacement for API operations
105+
106+
Attempting an API operation on a replaced source would be an error. The user could use `--registry crates-io` to explicitly bypass the source replacement.
107+
```
108+
Error: <operation> is not supported on replaced source `crates-io-mirror`; use `--registry crates-io` for the original source
109+
```
110+
111+
# Prior art
112+
[prior-art]: #prior-art
113+
114+
Other package managers don't seem to have a source replacement feature.
115+
116+
# Unresolved questions
117+
[unresolved-questions]: #unresolved-questions
118+
119+
Should the `--registry <NAME>` command line argument be allowed to reference the name of a `source` from the `[source]` table as well? This makes it more flexible, but adds potentially unnecessary complexity.
120+
121+
Cargo's tests rely on the ability to replace the crates.io source and have the crates.io credentials go to the replaced source. We need a way for these tests to continue working.
122+
123+
# Future possibilities
124+
[future-possibilities]: #future-possibilities
125+
126+
Can't think of anything.
127+
128+
[3139]: https://rust-lang.github.io/rfcs/3139-cargo-alternative-registry-auth.html

0 commit comments

Comments
 (0)