Skip to content

Commit ab36df1

Browse files
committed
fix(toml): Reject registry-index in user-written manifests
1 parent 92ffbdf commit ab36df1

File tree

4 files changed

+78
-29
lines changed

4 files changed

+78
-29
lines changed

src/cargo/core/source_id.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,11 @@ impl SourceId {
387387
matches!(self.inner.kind, SourceKind::Git(_))
388388
}
389389

390+
/// Returns `true` if this source is from a directory.
391+
pub fn is_directory(self) -> bool {
392+
self.inner.kind == SourceKind::Directory
393+
}
394+
390395
/// Creates an implementation of `Source` corresponding to this ID.
391396
///
392397
/// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked.

src/cargo/util/toml/mod.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,40 @@ pub fn to_real_manifest(
12761276
gctx: &GlobalContext,
12771277
warnings: &mut Vec<String>,
12781278
_errors: &mut Vec<String>,
1279+
) -> CargoResult<Manifest> {
1280+
to_real_manifest_impl(
1281+
contents,
1282+
document,
1283+
original_toml,
1284+
normalized_toml,
1285+
features,
1286+
workspace_config,
1287+
source_id,
1288+
manifest_file,
1289+
is_embedded,
1290+
gctx,
1291+
warnings,
1292+
_errors,
1293+
false,
1294+
)
1295+
}
1296+
1297+
/// Internal implementation with cargo_generated parameter
1298+
#[tracing::instrument(skip_all)]
1299+
fn to_real_manifest_impl(
1300+
contents: String,
1301+
document: toml::Spanned<toml::de::DeTable<'static>>,
1302+
original_toml: manifest::TomlManifest,
1303+
normalized_toml: manifest::TomlManifest,
1304+
features: Features,
1305+
workspace_config: WorkspaceConfig,
1306+
source_id: SourceId,
1307+
manifest_file: &Path,
1308+
is_embedded: bool,
1309+
gctx: &GlobalContext,
1310+
warnings: &mut Vec<String>,
1311+
_errors: &mut Vec<String>,
1312+
cargo_generated: bool,
12791313
) -> CargoResult<Manifest> {
12801314
let package_root = manifest_file.parent().unwrap();
12811315
if !package_root.is_dir() {
@@ -1582,6 +1616,7 @@ pub fn to_real_manifest(
15821616
warnings,
15831617
platform: None,
15841618
root: package_root,
1619+
cargo_generated,
15851620
};
15861621
gather_dependencies(
15871622
&mut manifest_ctx,
@@ -1977,6 +2012,7 @@ fn to_virtual_manifest(
19772012
warnings,
19782013
platform: None,
19792014
root,
2015+
cargo_generated: false,
19802016
};
19812017
(
19822018
replace(&normalized_toml, &mut manifest_ctx)?,
@@ -2045,6 +2081,7 @@ struct ManifestContext<'a, 'b> {
20452081
warnings: &'a mut Vec<String>,
20462082
platform: Option<Platform>,
20472083
root: &'a Path,
2084+
cargo_generated: bool,
20482085
}
20492086

20502087
#[tracing::instrument(skip_all)]
@@ -2175,6 +2212,7 @@ pub(crate) fn to_dependency<P: ResolveToPath + Clone>(
21752212
warnings,
21762213
platform,
21772214
root,
2215+
cargo_generated: false,
21782216
},
21792217
kind,
21802218
)
@@ -2292,6 +2330,27 @@ fn detailed_dep_to_dependency<P: ResolveToPath + Clone>(
22922330
dep.set_registry_id(registry_id);
22932331
}
22942332
if let Some(registry_index) = &orig.registry_index {
2333+
// `registry-index` is for internal use only.
2334+
// It should not be used in user-written manifests as it bypasses the need for .cargo/config.toml configuration.
2335+
2336+
if !manifest_ctx.source_id.is_registry()
2337+
&& !manifest_ctx.source_id.is_directory()
2338+
&& !manifest_ctx.cargo_generated
2339+
{
2340+
// Check if this is a packaged manifest (in target/package or target\package)
2341+
// by checking if the path contains the pattern
2342+
let path_str: Cow<'_, str> = manifest_ctx.root.to_string_lossy();
2343+
let is_packaged_manifest =
2344+
path_str.contains("target/package") || path_str.contains("target\\package");
2345+
2346+
if !is_packaged_manifest {
2347+
bail!(
2348+
"dependency ({}) specification uses `registry-index` which is for internal use only\n\
2349+
help: use `registry = \"<name>\"` and configure the registry in `.cargo/config.toml`",
2350+
name_in_toml
2351+
);
2352+
}
2353+
}
22952354
let url = registry_index.into_url()?;
22962355
let registry_id = SourceId::for_registry(&url)?;
22972356
dep.set_registry_id(registry_id);
@@ -2936,7 +2995,7 @@ pub fn prepare_for_publish(
29362995
let mut warnings = Default::default();
29372996
let mut errors = Default::default();
29382997
let gctx = ws.gctx();
2939-
let manifest = to_real_manifest(
2998+
let manifest = to_real_manifest_impl(
29402999
contents.to_owned(),
29413000
document.clone(),
29423001
original_toml,
@@ -2949,6 +3008,7 @@ pub fn prepare_for_publish(
29493008
gctx,
29503009
&mut warnings,
29513010
&mut errors,
3011+
true, // cargo_generated - this is a Cargo-generated manifest
29523012
)?;
29533013
let new_pkg = Package::new(manifest, me.manifest_path());
29543014
Ok(new_pkg)

tests/testsuite/alt_registry.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -285,18 +285,14 @@ fn registry_index_not_allowed_in_user_manifests() {
285285
.file("src/lib.rs", "")
286286
.build();
287287

288-
// FIXME: This currently allows `registry-index` which is a bug.
289-
// It should error during manifest parsing because `registry-index` is for internal use only.
290-
// Instead, it tries to fetch from the URL and fails with a network error.
291288
p.cargo("check")
289+
.with_status(101)
292290
.with_stderr_data(str![[r#"
293-
[UPDATING] `[ROOT]/alternative-registry` index
294-
[LOCKING] 1 package to latest compatible version
295-
[DOWNLOADING] crates ...
296-
[DOWNLOADED] bar v0.1.0 (registry `[ROOT]/alternative-registry`)
297-
[CHECKING] bar v0.1.0 (registry `[ROOT]/alternative-registry`)
298-
[CHECKING] foo v0.0.0 ([ROOT]/foo)
299-
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
291+
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
292+
293+
Caused by:
294+
dependency (bar) specification uses `registry-index` which is for internal use only
295+
[HELP] use `registry = "<name>"` and configure the registry in `.cargo/config.toml`
300296
301297
"#]])
302298
.run();

tests/testsuite/publish.rs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4628,26 +4628,14 @@ fn registry_index_not_allowed_in_publish() {
46284628
.file("src/main.rs", "fn main() {}")
46294629
.build();
46304630

4631-
// FIXME: This currently allows `registry-index` which is a bug.
4632-
// It should error during manifest parsing because `registry-index` is for internal use only.
4633-
// Instead, it actually works and the package can be published.
46344631
p.cargo("publish --registry alternative")
4632+
.with_status(101)
46354633
.with_stderr_data(str![[r#"
4636-
[UPDATING] `alternative` index
4637-
[PACKAGING] foo v0.0.1 ([ROOT]/foo)
4638-
[UPDATING] `[ROOT]/registry` index
4639-
[PACKAGED] 4 files, [FILE_SIZE]B ([FILE_SIZE]B compressed)
4640-
[VERIFYING] foo v0.0.1 ([ROOT]/foo)
4641-
[DOWNLOADING] crates ...
4642-
[DOWNLOADED] bar v0.1.0 (registry `[ROOT]/registry`)
4643-
[COMPILING] bar v0.1.0 (registry `[ROOT]/registry`)
4644-
[COMPILING] foo v0.0.1 ([ROOT]/foo/target/package/foo-0.0.1)
4645-
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
4646-
[UPLOADING] foo v0.0.1 ([ROOT]/foo)
4647-
[UPLOADED] foo v0.0.1 to registry `alternative`
4648-
[NOTE] waiting for foo v0.0.1 to be available at registry `alternative`
4649-
[HELP] you may press ctrl-c to skip waiting; the crate should be available shortly
4650-
[PUBLISHED] foo v0.0.1 at registry `alternative`
4634+
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml`
4635+
4636+
Caused by:
4637+
dependency (bar) specification uses `registry-index` which is for internal use only
4638+
[HELP] use `registry = "<name>"` and configure the registry in `.cargo/config.toml`
46514639
46524640
"#]])
46534641
.run();

0 commit comments

Comments
 (0)