Skip to content

Commit 91e36aa

Browse files
committed
Auto merge of #4957 - sfackler:registry-elaboration, r=alexcrichton
Elaborate registry names to index URLs when publishing This avoids introducing a dependency on the publisher's name for the registry. Closes #4880
2 parents 6dcd33e + 77ccd0e commit 91e36aa

File tree

6 files changed

+117
-45
lines changed

6 files changed

+117
-45
lines changed

src/cargo/core/package.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ impl Package {
134134
}
135135
}
136136

137-
pub fn to_registry_toml(&self) -> CargoResult<String> {
138-
let manifest = self.manifest().original().prepare_for_publish();
137+
pub fn to_registry_toml(&self, config: &Config) -> CargoResult<String> {
138+
let manifest = self.manifest().original().prepare_for_publish(config)?;
139139
let toml = toml::to_string(&manifest)?;
140140
Ok(format!("\
141141
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO\n\

src/cargo/ops/cargo_package.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ fn tar(ws: &Workspace,
249249
})?;
250250

251251
let mut header = Header::new_ustar();
252-
let toml = pkg.to_registry_toml()?;
252+
let toml = pkg.to_registry_toml(ws.config())?;
253253
header.set_path(&path)?;
254254
header.set_entry_type(EntryType::file());
255255
header.set_mode(0o644);

src/cargo/util/config.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,13 @@ impl Config {
552552
/// Gets the index for a registry.
553553
pub fn get_registry_index(&self, registry: &str) -> CargoResult<Url> {
554554
Ok(match self.get_string(&format!("registries.{}.index", registry))? {
555-
Some(index) => index.val.to_url()?,
555+
Some(index) => {
556+
let url = index.val.to_url()?;
557+
if url.username() != "" || url.password().is_some() {
558+
bail!("Registry URLs may not contain credentials");
559+
}
560+
url
561+
}
556562
None => bail!("No index found for registry: `{}`", registry),
557563
})
558564
}

src/cargo/util/toml/mod.rs

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -178,25 +178,26 @@ impl<'de> de::Deserialize<'de> for TomlDependency {
178178
}
179179

180180
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
181+
#[serde(rename_all = "kebab-case")]
181182
pub struct DetailedTomlDependency {
182183
version: Option<String>,
183184
registry: Option<String>,
185+
registry_index: Option<String>,
184186
path: Option<String>,
185187
git: Option<String>,
186188
branch: Option<String>,
187189
tag: Option<String>,
188190
rev: Option<String>,
189191
features: Option<Vec<String>>,
190192
optional: Option<bool>,
191-
#[serde(rename = "default-features")]
192193
default_features: Option<bool>,
193194
#[serde(rename = "default_features")]
194195
default_features2: Option<bool>,
195196
}
196197

197198
#[derive(Debug, Deserialize, Serialize)]
199+
#[serde(rename_all = "kebab-case")]
198200
pub struct TomlManifest {
199-
#[serde(rename = "cargo-features")]
200201
cargo_features: Option<Vec<String>>,
201202
package: Option<Box<TomlProject>>,
202203
project: Option<Box<TomlProject>>,
@@ -207,11 +208,9 @@ pub struct TomlManifest {
207208
test: Option<Vec<TomlTestTarget>>,
208209
bench: Option<Vec<TomlTestTarget>>,
209210
dependencies: Option<BTreeMap<String, TomlDependency>>,
210-
#[serde(rename = "dev-dependencies")]
211211
dev_dependencies: Option<BTreeMap<String, TomlDependency>>,
212212
#[serde(rename = "dev_dependencies")]
213213
dev_dependencies2: Option<BTreeMap<String, TomlDependency>>,
214-
#[serde(rename = "build-dependencies")]
215214
build_dependencies: Option<BTreeMap<String, TomlDependency>>,
216215
#[serde(rename = "build_dependencies")]
217216
build_dependencies2: Option<BTreeMap<String, TomlDependency>>,
@@ -471,13 +470,13 @@ struct Context<'a, 'b> {
471470
}
472471

473472
impl TomlManifest {
474-
pub fn prepare_for_publish(&self) -> TomlManifest {
473+
pub fn prepare_for_publish(&self, config: &Config) -> CargoResult<TomlManifest> {
475474
let mut package = self.package.as_ref()
476475
.or_else(|| self.project.as_ref())
477476
.unwrap()
478477
.clone();
479478
package.workspace = None;
480-
return TomlManifest {
479+
return Ok(TomlManifest {
481480
package: Some(package),
482481
project: None,
483482
profile: self.profile.clone(),
@@ -486,56 +485,68 @@ impl TomlManifest {
486485
example: self.example.clone(),
487486
test: self.test.clone(),
488487
bench: self.bench.clone(),
489-
dependencies: map_deps(self.dependencies.as_ref()),
490-
dev_dependencies: map_deps(self.dev_dependencies.as_ref()
491-
.or_else(|| self.dev_dependencies2.as_ref())),
488+
dependencies: map_deps(config, self.dependencies.as_ref())?,
489+
dev_dependencies: map_deps(config, self.dev_dependencies.as_ref()
490+
.or_else(|| self.dev_dependencies2.as_ref()))?,
492491
dev_dependencies2: None,
493-
build_dependencies: map_deps(self.build_dependencies.as_ref()
494-
.or_else(|| self.build_dependencies2.as_ref())),
492+
build_dependencies: map_deps(config, self.build_dependencies.as_ref()
493+
.or_else(|| self.build_dependencies2.as_ref()))?,
495494
build_dependencies2: None,
496495
features: self.features.clone(),
497-
target: self.target.as_ref().map(|target_map| {
496+
target: match self.target.as_ref().map(|target_map| {
498497
target_map.iter().map(|(k, v)| {
499-
(k.clone(), TomlPlatform {
500-
dependencies: map_deps(v.dependencies.as_ref()),
501-
dev_dependencies: map_deps(v.dev_dependencies.as_ref()
502-
.or_else(|| v.dev_dependencies2.as_ref())),
498+
Ok((k.clone(), TomlPlatform {
499+
dependencies: map_deps(config, v.dependencies.as_ref())?,
500+
dev_dependencies: map_deps(config, v.dev_dependencies.as_ref()
501+
.or_else(|| v.dev_dependencies2.as_ref()))?,
503502
dev_dependencies2: None,
504-
build_dependencies: map_deps(v.build_dependencies.as_ref()
505-
.or_else(|| v.build_dependencies2.as_ref())),
503+
build_dependencies: map_deps(config, v.build_dependencies.as_ref()
504+
.or_else(|| v.build_dependencies2.as_ref()))?,
506505
build_dependencies2: None,
507-
})
506+
}))
508507
}).collect()
509-
}),
508+
}) {
509+
Some(Ok(v)) => Some(v),
510+
Some(Err(e)) => return Err(e),
511+
None => None,
512+
},
510513
replace: None,
511514
patch: None,
512515
workspace: None,
513516
badges: self.badges.clone(),
514517
cargo_features: self.cargo_features.clone(),
515-
};
518+
});
516519

517-
fn map_deps(deps: Option<&BTreeMap<String, TomlDependency>>)
518-
-> Option<BTreeMap<String, TomlDependency>>
520+
fn map_deps(config: &Config, deps: Option<&BTreeMap<String, TomlDependency>>)
521+
-> CargoResult<Option<BTreeMap<String, TomlDependency>>>
519522
{
520523
let deps = match deps {
521524
Some(deps) => deps,
522-
None => return None
525+
None => return Ok(None),
523526
};
524-
Some(deps.iter().map(|(k, v)| (k.clone(), map_dependency(v))).collect())
527+
let deps = deps.iter()
528+
.map(|(k, v)| Ok((k.clone(), map_dependency(config, v)?)))
529+
.collect::<CargoResult<BTreeMap<_, _>>>()?;
530+
Ok(Some(deps))
525531
}
526532

527-
fn map_dependency(dep: &TomlDependency) -> TomlDependency {
533+
fn map_dependency(config: &Config, dep: &TomlDependency) -> CargoResult<TomlDependency> {
528534
match *dep {
529535
TomlDependency::Detailed(ref d) => {
530536
let mut d = d.clone();
531537
d.path.take(); // path dependencies become crates.io deps
532-
TomlDependency::Detailed(d)
538+
// registry specifications are elaborated to the index URL
539+
if let Some(registry) = d.registry.take() {
540+
let src = SourceId::alt_registry(config, &registry)?;
541+
d.registry_index = Some(src.url().to_string());
542+
}
543+
Ok(TomlDependency::Detailed(d))
533544
}
534545
TomlDependency::Simple(ref s) => {
535-
TomlDependency::Detailed(DetailedTomlDependency {
546+
Ok(TomlDependency::Detailed(DetailedTomlDependency {
536547
version: Some(s.clone()),
537548
..Default::default()
538-
})
549+
}))
539550
}
540551
}
541552
}
@@ -933,10 +944,18 @@ impl TomlDependency {
933944
None => SourceId::crates_io(cx.config)?
934945
};
935946

936-
let new_source_id = match (details.git.as_ref(), details.path.as_ref(), details.registry.as_ref()) {
937-
(Some(_), _, Some(_)) => bail!("dependency ({}) specification is ambiguous. \
947+
let new_source_id = match (
948+
details.git.as_ref(),
949+
details.path.as_ref(),
950+
details.registry.as_ref(),
951+
details.registry_index.as_ref(),
952+
) {
953+
(Some(_), _, Some(_), _) |
954+
(Some(_), _, _, Some(_))=> bail!("dependency ({}) specification is ambiguous. \
938955
Only one of `git` or `registry` is allowed.", name),
939-
(Some(git), maybe_path, _) => {
956+
(_, _, Some(_), Some(_)) => bail!("dependency ({}) specification is ambiguous. \
957+
Only one of `registry` or `registry-index` is allowed.", name),
958+
(Some(git), maybe_path, _, _) => {
940959
if maybe_path.is_some() {
941960
let msg = format!("dependency ({}) specification is ambiguous. \
942961
Only one of `git` or `path` is allowed. \
@@ -963,7 +982,7 @@ impl TomlDependency {
963982
let loc = git.to_url()?;
964983
SourceId::for_git(&loc, reference)?
965984
},
966-
(None, Some(path), _) => {
985+
(None, Some(path), _, _) => {
967986
cx.nested_paths.push(PathBuf::from(path));
968987
// If the source id for the package we're parsing is a path
969988
// source, then we normalize the path here to get rid of
@@ -981,8 +1000,12 @@ impl TomlDependency {
9811000
cx.source_id.clone()
9821001
}
9831002
},
984-
(None, None, Some(registry)) => SourceId::alt_registry(cx.config, registry)?,
985-
(None, None, None) => SourceId::crates_io(cx.config)?,
1003+
(None, None, Some(registry), None) => SourceId::alt_registry(cx.config, registry)?,
1004+
(None, None, None, Some(registry_index)) => {
1005+
let url = registry_index.to_url()?;
1006+
SourceId::for_registry(&url)?
1007+
}
1008+
(None, None, None, None) => SourceId::crates_io(cx.config)?,
9861009
};
9871010

9881011
let version = details.version.as_ref().map(|v| &v[..]);

tests/alt-registry.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ extern crate hamcrest;
33

44
use cargotest::ChannelChanger;
55
use cargotest::support::registry::{self, Package, alt_api_path};
6-
use cargotest::support::{project, execs};
6+
use cargotest::support::{paths, project, execs};
77
use hamcrest::assert_that;
8+
use std::fs::File;
9+
use std::io::Write;
810

911
#[test]
1012
fn is_feature_gated() {
@@ -423,3 +425,35 @@ fn publish_with_crates_io_dep() {
423425
.arg("--registry").arg("alternative").arg("-Zunstable-options"),
424426
execs().with_status(0));
425427
}
428+
429+
#[test]
430+
fn credentials_in_url_forbidden() {
431+
registry::init();
432+
433+
let config = paths::home().join(".cargo/config");
434+
435+
File::create(config)
436+
.unwrap()
437+
.write_all(br#"
438+
[registries.alternative]
439+
index = "ssh://git:[email protected]"
440+
"#)
441+
.unwrap();
442+
443+
let p = project("foo")
444+
.file("Cargo.toml", r#"
445+
cargo-features = ["alternative-registries"]
446+
447+
[project]
448+
name = "foo"
449+
version = "0.0.1"
450+
authors = []
451+
"#)
452+
.file("src/main.rs", "fn main() {}")
453+
.build();
454+
455+
assert_that(p.cargo("publish").masquerade_as_nightly_cargo()
456+
.arg("--registry").arg("alternative").arg("-Zunstable-options"),
457+
execs().with_status(101)
458+
.with_stderr_contains("error: Registry URLs may not contain credentials"));
459+
}

tests/package.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use std::fs::File;
99
use std::io::prelude::*;
1010
use std::path::{Path, PathBuf};
1111

12-
use cargotest::{cargo_process, process};
13-
use cargotest::support::{project, execs, paths, git, path2url, cargo_exe};
12+
use cargotest::{cargo_process, process, ChannelChanger};
13+
use cargotest::support::{project, execs, paths, git, path2url, cargo_exe, registry};
1414
use cargotest::support::registry::Package;
1515
use flate2::read::GzDecoder;
1616
use hamcrest::{assert_that, existing_file, contains, equal_to};
@@ -715,6 +715,8 @@ fn generated_manifest() {
715715
Package::new("ghi", "1.0.0").publish();
716716
let p = project("foo")
717717
.file("Cargo.toml", r#"
718+
cargo-features = ["alternative-registries"]
719+
718720
[project]
719721
name = "foo"
720722
version = "0.0.1"
@@ -730,7 +732,7 @@ fn generated_manifest() {
730732
731733
[dependencies]
732734
bar = { path = "bar", version = "0.1" }
733-
def = "1.0"
735+
def = { version = "1.0", registry = "alternative" }
734736
ghi = "1.0"
735737
abc = "1.0"
736738
"#)
@@ -744,7 +746,9 @@ fn generated_manifest() {
744746
.file("bar/src/lib.rs", "")
745747
.build();
746748

747-
assert_that(p.cargo("package").arg("--no-verify"),
749+
assert_that(p.cargo("package")
750+
.masquerade_as_nightly_cargo()
751+
.arg("--no-verify"),
748752
execs().with_status(0));
749753

750754
let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
@@ -761,6 +765,7 @@ fn generated_manifest() {
761765
// BTreeMap makes the order of dependencies in the generated file deterministic
762766
// by sorting alphabetically
763767
assert_that(&contents[..], equal_to(
768+
&*format!(
764769
r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
765770
#
766771
# When uploading crates to the registry Cargo will automatically
@@ -773,6 +778,8 @@ r#"# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
773778
# editing this file be aware that the upstream Cargo.toml
774779
# will likely look very different (and much more reasonable)
775780
781+
cargo-features = ["alternative-registries"]
782+
776783
[package]
777784
name = "foo"
778785
version = "0.0.1"
@@ -791,10 +798,12 @@ version = "0.1"
791798
792799
[dependencies.def]
793800
version = "1.0"
801+
registry-index = "{}"
794802
795803
[dependencies.ghi]
796804
version = "1.0"
797-
"#));
805+
"#,
806+
registry::alt_registry())));
798807
}
799808

800809
#[test]

0 commit comments

Comments
 (0)