Skip to content

Commit 2fd9476

Browse files
committed
Error on absolute src paths
These lead to non-deterministic lockfile contents because they depend on the depth of the directory the repo is checked out into. This may possibly introduce false positives because of hard-coded /dev/null or similar in actual published crates - hopefully it doesn't (ideally people aren't publishing this kind of thing to crates.io), but if it does, we can loosen those to a warning or add a per-crate opt-out or something.
1 parent 13e566e commit 2fd9476

File tree

11 files changed

+168
-29
lines changed

11 files changed

+168
-29
lines changed

crate_universe/src/context.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl Context {
5252
Ok(serde_json::from_str(&data)?)
5353
}
5454

55-
pub(crate) fn new(annotations: Annotations, sources_are_present: bool) -> Result<Self> {
55+
pub(crate) fn new(annotations: Annotations, sources_are_present: bool) -> anyhow::Result<Self> {
5656
// Build a map of crate contexts
5757
let crates: BTreeMap<CrateId, CrateContext> = annotations
5858
.metadata
@@ -68,11 +68,11 @@ impl Context {
6868
annotations.config.generate_binaries,
6969
annotations.config.generate_build_scripts,
7070
sources_are_present,
71-
);
71+
)?;
7272
let id = CrateId::new(context.name.clone(), context.version.clone());
73-
(id, context)
73+
Ok::<_, anyhow::Error>((id, context))
7474
})
75-
.collect();
75+
.collect::<Result<_, _>>()?;
7676

7777
// Filter for any crate that contains a binary
7878
let binary_crates: BTreeSet<CrateId> = crates

crate_universe/src/context/crate_context.rs

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ impl CrateContext {
352352
include_binaries: bool,
353353
include_build_scripts: bool,
354354
sources_are_present: bool,
355-
) -> Self {
355+
) -> anyhow::Result<Self> {
356356
let package: &Package = &packages[&annotation.node.id];
357357
let current_crate_id = CrateId::new(package.name.clone(), package.version.clone());
358358

@@ -430,7 +430,7 @@ impl CrateContext {
430430
gen_binaries,
431431
include_build_scripts,
432432
sources_are_present,
433-
);
433+
)?;
434434

435435
// Parse the library crate name from the set of included targets
436436
let library_target_name = {
@@ -511,7 +511,7 @@ impl CrateContext {
511511
};
512512

513513
// Create the crate's context and apply extra settings
514-
CrateContext {
514+
Ok(CrateContext {
515515
name: package.name.clone(),
516516
version: package.version.clone(),
517517
license: package.license.clone(),
@@ -529,7 +529,7 @@ impl CrateContext {
529529
alias_rule: None,
530530
override_targets: BTreeMap::new(),
531531
}
532-
.with_overrides(extras)
532+
.with_overrides(extras))
533533
}
534534

535535
fn with_overrides(mut self, extras: &BTreeMap<CrateId, PairedExtras>) -> Self {
@@ -755,7 +755,7 @@ impl CrateContext {
755755
gen_binaries: &GenBinaries,
756756
include_build_scripts: bool,
757757
sources_are_present: bool,
758-
) -> BTreeSet<Rule> {
758+
) -> anyhow::Result<BTreeSet<Rule>> {
759759
let package = &packages[&node.id];
760760

761761
let package_root = package
@@ -774,6 +774,10 @@ impl CrateContext {
774774
// content to align when rendering, the package target names are always sanitized.
775775
let crate_name = sanitize_module_name(&target.name);
776776

777+
if !target.src_path.starts_with(package_root) {
778+
return Some(Err(anyhow::anyhow!("Package {:?} target {:?} had an absolute source path {:?}, which is not supported", package.name, target.name, target.src_path)));
779+
}
780+
777781
// Locate the crate's root source file relative to the package root normalized for unix
778782
let crate_root = pathdiff::diff_paths(&target.src_path, package_root).map(
779783
// Normalize the path so that it always renders the same regardless of platform
@@ -782,29 +786,29 @@ impl CrateContext {
782786

783787
// Conditionally check to see if the dependencies is a build-script target
784788
if include_build_scripts && kind == "custom-build" {
785-
return Some(Rule::BuildScript(TargetAttributes {
789+
return Some(Ok(Rule::BuildScript(TargetAttributes {
786790
crate_name,
787791
crate_root,
788792
srcs: Glob::new_rust_srcs(!sources_are_present),
789-
}));
793+
})));
790794
}
791795

792796
// Check to see if the dependencies is a proc-macro target
793797
if kind == "proc-macro" {
794-
return Some(Rule::ProcMacro(TargetAttributes {
798+
return Some(Ok(Rule::ProcMacro(TargetAttributes {
795799
crate_name,
796800
crate_root,
797801
srcs: Glob::new_rust_srcs(!sources_are_present),
798-
}));
802+
})));
799803
}
800804

801805
// Check to see if the dependencies is a library target
802806
if ["lib", "rlib"].contains(&kind.as_str()) {
803-
return Some(Rule::Library(TargetAttributes {
807+
return Some(Ok(Rule::Library(TargetAttributes {
804808
crate_name,
805809
crate_root,
806810
srcs: Glob::new_rust_srcs(!sources_are_present),
807-
}));
811+
})));
808812
}
809813

810814
// Check if the target kind is binary and is one of the ones included in gen_binaries
@@ -814,11 +818,11 @@ impl CrateContext {
814818
GenBinaries::Some(set) => set.contains(&target.name),
815819
}
816820
{
817-
return Some(Rule::Binary(TargetAttributes {
821+
return Some(Ok(Rule::Binary(TargetAttributes {
818822
crate_name: target.name.clone(),
819823
crate_root,
820824
srcs: Glob::new_rust_srcs(!sources_are_present),
821-
}));
825+
})));
822826
}
823827

824828
None
@@ -866,7 +870,8 @@ mod test {
866870
include_binaries,
867871
include_build_scripts,
868872
are_sources_present,
869-
);
873+
)
874+
.unwrap();
870875

871876
assert_eq!(context.name, "common");
872877
assert_eq!(
@@ -914,7 +919,8 @@ mod test {
914919
include_binaries,
915920
include_build_scripts,
916921
are_sources_present,
917-
);
922+
)
923+
.unwrap();
918924

919925
assert_eq!(context.name, "common");
920926
assert_eq!(
@@ -979,7 +985,8 @@ mod test {
979985
include_binaries,
980986
include_build_scripts,
981987
are_sources_present,
982-
);
988+
)
989+
.unwrap();
983990

984991
assert_eq!(context.name, "openssl-sys");
985992
assert!(context.build_script_attrs.is_some());
@@ -1026,7 +1033,8 @@ mod test {
10261033
include_binaries,
10271034
include_build_scripts,
10281035
are_sources_present,
1029-
);
1036+
)
1037+
.unwrap();
10301038

10311039
assert_eq!(context.name, "openssl-sys");
10321040
assert!(context.build_script_attrs.is_none());
@@ -1062,7 +1070,8 @@ mod test {
10621070
include_binaries,
10631071
include_build_scripts,
10641072
are_sources_present,
1065-
);
1073+
)
1074+
.unwrap();
10661075

10671076
assert_eq!(context.name, "sysinfo");
10681077
assert!(context.build_script_attrs.is_none());
@@ -1104,7 +1113,8 @@ mod test {
11041113
include_binaries,
11051114
include_build_scripts,
11061115
are_sources_present,
1107-
);
1116+
)
1117+
.unwrap();
11081118

11091119
assert_eq!(context.name, "common");
11101120
check_context(context);
@@ -1236,11 +1246,44 @@ mod test {
12361246
include_binaries,
12371247
include_build_scripts,
12381248
are_sources_present,
1239-
);
1249+
)
1250+
.unwrap();
12401251

12411252
let mut expected = Select::new();
12421253
expected.insert("unique_feature".to_owned(), None);
12431254

12441255
assert_eq!(context.common_attrs.crate_features, expected);
12451256
}
1257+
1258+
#[test]
1259+
fn absolute_paths_for_srcs_are_errors() {
1260+
let annotations = Annotations::new(
1261+
crate::test::metadata::abspath(),
1262+
crate::test::lockfile::abspath(),
1263+
crate::config::Config::default(),
1264+
)
1265+
.unwrap();
1266+
1267+
let crate_annotation = &annotations.metadata.crates[&PackageId {
1268+
repr: "path+file://{TEMP_DIR}/common#0.1.0".to_owned(),
1269+
}];
1270+
1271+
let include_binaries = false;
1272+
let include_build_scripts = false;
1273+
let are_sources_present = false;
1274+
let err = CrateContext::new(
1275+
crate_annotation,
1276+
&annotations.metadata.packages,
1277+
&annotations.lockfile.crates,
1278+
&annotations.pairred_extras,
1279+
&annotations.metadata.workspace_metadata.tree_metadata,
1280+
include_binaries,
1281+
include_build_scripts,
1282+
are_sources_present,
1283+
)
1284+
.unwrap_err()
1285+
.to_string();
1286+
1287+
assert_eq!(err, "Package \"common\" target \"common\" had an absolute source path \"/dev/null\", which is not supported");
1288+
}
12461289
}

crate_universe/src/test.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,14 @@ pub(crate) mod metadata {
170170
)))
171171
.unwrap()
172172
}
173+
174+
pub(crate) fn abspath() -> cargo_metadata::Metadata {
175+
serde_json::from_str(include_str!(concat!(
176+
env!("CARGO_MANIFEST_DIR"),
177+
"/test_data/metadata/abspath/metadata.json"
178+
)))
179+
.unwrap()
180+
}
173181
}
174182

175183
pub(crate) mod lockfile {
@@ -238,4 +246,12 @@ pub(crate) mod lockfile {
238246
)))
239247
.unwrap()
240248
}
249+
250+
pub(crate) fn abspath() -> cargo_lock::Lockfile {
251+
cargo_lock::Lockfile::from_str(include_str!(concat!(
252+
env!("CARGO_MANIFEST_DIR"),
253+
"/test_data/metadata/abspath/Cargo.lock"
254+
)))
255+
.unwrap()
256+
}
241257
}

crate_universe/test_data/metadata/abspath/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "common"
3+
version = "0.1.0"
4+
edition = "2018"
5+
6+
[lib]
7+
path = "fake.rs"

crate_universe/test_data/metadata/abspath/metadata.json

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/bazel_env/rust/hello_world/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ edition = "2021"
55
publish = false
66

77
[lib]
8-
path = "/dev/null"
8+
path = "fake.rs"

examples/bzlmod/all_crate_deps/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
publish = false
77

88
[lib]
9-
path = "/dev/null"
9+
path = "fake.rs"
1010

1111
[dependencies]
1212
anyhow = "1.0.79"

examples/bzlmod/hello_world/third-party/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
publish = false
77

88
[lib]
9-
path = "/dev/null"
9+
path = "fake.rs"
1010

1111
[dependencies]
1212
anyhow = "1.0.77"

examples/bzlmod/override_target/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
publish = false
77

88
[lib]
9-
path = "/dev/null"
9+
path = "fake.rs"
1010

1111
[dependencies.foo]
1212
version = "0.0.0"

0 commit comments

Comments
 (0)