feat: check if config-include file ends with .toml

This is to avoid possible name collisions. For example, a user
creates a file called `.cargo/cache`, and then in the future
cargo wants to create a directory called `.cargo/cache/`, that
would collide with what the user specified. Restricting to `.toml`
extensions would avoid that since we won’t make a directory named
with a `.toml` extension.
This commit is contained in:
Weihang Lo 2023-06-21 01:39:45 +01:00
parent dead4b8740
commit 3f82ec7093
No known key found for this signature in database
GPG key ID: D7DBF189825E82E7
2 changed files with 53 additions and 25 deletions

View file

@ -1273,6 +1273,16 @@ impl Config {
return Ok(Vec::new()); return Ok(Vec::new());
} }
}; };
for (path, abs_path, def) in &includes {
if abs_path.extension() != Some(OsStr::new("toml")) {
bail!(
"expected a config include path ending with `.toml`, \
but found `{path}` from `{def}`",
)
}
}
Ok(includes) Ok(includes)
} }

View file

@ -6,9 +6,9 @@ use cargo_test_support::{no_such_file_err_msg, project};
#[cargo_test] #[cargo_test]
fn gated() { fn gated() {
// Requires -Z flag. // Requires -Z flag.
write_config("include='other'"); write_config("include='other.toml'");
write_config_at( write_config_at(
".cargo/other", ".cargo/other.toml",
" "
othervalue = 1 othervalue = 1
", ",
@ -25,13 +25,13 @@ fn simple() {
write_config_at( write_config_at(
".cargo/config", ".cargo/config",
" "
include = 'other' include = 'other.toml'
key1 = 1 key1 = 1
key2 = 2 key2 = 2
", ",
); );
write_config_at( write_config_at(
".cargo/other", ".cargo/other.toml",
" "
key2 = 3 key2 = 3
key3 = 4 key3 = 4
@ -89,19 +89,19 @@ fn left_to_right() {
write_config_at( write_config_at(
".cargo/config", ".cargo/config",
" "
include = ['one', 'two'] include = ['one.toml', 'two.toml']
primary = 1 primary = 1
", ",
); );
write_config_at( write_config_at(
".cargo/one", ".cargo/one.toml",
" "
one = 1 one = 1
primary = 2 primary = 2
", ",
); );
write_config_at( write_config_at(
".cargo/two", ".cargo/two.toml",
" "
two = 2 two = 2
primary = 3 primary = 3
@ -116,7 +116,7 @@ fn left_to_right() {
#[cargo_test] #[cargo_test]
fn missing_file() { fn missing_file() {
// Error when there's a missing file. // Error when there's a missing file.
write_config("include='missing'"); write_config("include='missing.toml'");
let config = ConfigBuilder::new() let config = ConfigBuilder::new()
.unstable_flag("config-include") .unstable_flag("config-include")
.build_err(); .build_err();
@ -127,10 +127,10 @@ fn missing_file() {
could not load Cargo configuration could not load Cargo configuration
Caused by: Caused by:
failed to load config include `missing` from `[..]/.cargo/config` failed to load config include `missing.toml` from `[..]/.cargo/config`
Caused by: Caused by:
failed to read configuration file `[..]/.cargo/missing` failed to read configuration file `[..]/.cargo/missing.toml`
Caused by: Caused by:
{}", {}",
@ -139,12 +139,30 @@ Caused by:
); );
} }
#[cargo_test]
fn wrong_file_extension() {
// Error when it doesn't end with `.toml`.
write_config("include='config.png'");
let config = ConfigBuilder::new()
.unstable_flag("config-include")
.build_err();
assert_error(
config.unwrap_err(),
"\
could not load Cargo configuration
Caused by:
expected a config include path ending with `.toml`, but found `config.png` from `[..]/.cargo/config`
",
);
}
#[cargo_test] #[cargo_test]
fn cycle() { fn cycle() {
// Detects a cycle. // Detects a cycle.
write_config_at(".cargo/config", "include='one'"); write_config_at(".cargo/config.toml", "include='one.toml'");
write_config_at(".cargo/one", "include='two'"); write_config_at(".cargo/one.toml", "include='two.toml'");
write_config_at(".cargo/two", "include='config'"); write_config_at(".cargo/two.toml", "include='config.toml'");
let config = ConfigBuilder::new() let config = ConfigBuilder::new()
.unstable_flag("config-include") .unstable_flag("config-include")
.build_err(); .build_err();
@ -154,16 +172,16 @@ fn cycle() {
could not load Cargo configuration could not load Cargo configuration
Caused by: Caused by:
failed to load config include `one` from `[..]/.cargo/config` failed to load config include `one.toml` from `[..]/.cargo/config.toml`
Caused by: Caused by:
failed to load config include `two` from `[..]/.cargo/one` failed to load config include `two.toml` from `[..]/.cargo/one.toml`
Caused by: Caused by:
failed to load config include `config` from `[..]/.cargo/two` failed to load config include `config.toml` from `[..]/.cargo/two.toml`
Caused by: Caused by:
config `include` cycle detected with path `[..]/.cargo/config`", config `include` cycle detected with path `[..]/.cargo/config.toml`",
); );
} }
@ -178,10 +196,10 @@ fn cli_include() {
bar = 2 bar = 2
", ",
); );
write_config_at(".cargo/config-foo", "foo = 2"); write_config_at(".cargo/config-foo.toml", "foo = 2");
let config = ConfigBuilder::new() let config = ConfigBuilder::new()
.unstable_flag("config-include") .unstable_flag("config-include")
.config_arg("include='.cargo/config-foo'") .config_arg("include='.cargo/config-foo.toml'")
.build(); .build();
assert_eq!(config.get::<i32>("foo").unwrap(), 2); assert_eq!(config.get::<i32>("foo").unwrap(), 2);
assert_eq!(config.get::<i32>("bar").unwrap(), 2); assert_eq!(config.get::<i32>("bar").unwrap(), 2);
@ -209,7 +227,7 @@ fn cli_include_failed() {
// Error message when CLI include fails to load. // Error message when CLI include fails to load.
let config = ConfigBuilder::new() let config = ConfigBuilder::new()
.unstable_flag("config-include") .unstable_flag("config-include")
.config_arg("include='foobar'") .config_arg("include='foobar.toml'")
.build_err(); .build_err();
assert_error( assert_error(
config.unwrap_err(), config.unwrap_err(),
@ -218,10 +236,10 @@ fn cli_include_failed() {
failed to load --config include failed to load --config include
Caused by: Caused by:
failed to load config include `foobar` from `--config cli option` failed to load config include `foobar.toml` from `--config cli option`
Caused by: Caused by:
failed to read configuration file `[..]/foobar` failed to read configuration file `[..]/foobar.toml`
Caused by: Caused by:
{}", {}",
@ -235,14 +253,14 @@ fn cli_merge_failed() {
// Error message when CLI include merge fails. // Error message when CLI include merge fails.
write_config("foo = ['a']"); write_config("foo = ['a']");
write_config_at( write_config_at(
".cargo/other", ".cargo/other.toml",
" "
foo = 'b' foo = 'b'
", ",
); );
let config = ConfigBuilder::new() let config = ConfigBuilder::new()
.unstable_flag("config-include") .unstable_flag("config-include")
.config_arg("include='.cargo/other'") .config_arg("include='.cargo/other.toml'")
.build_err(); .build_err();
// Maybe this error message should mention it was from an include file? // Maybe this error message should mention it was from an include file?
assert_error( assert_error(
@ -251,7 +269,7 @@ fn cli_merge_failed() {
failed to merge --config key `foo` into `[..]/.cargo/config` failed to merge --config key `foo` into `[..]/.cargo/config`
Caused by: Caused by:
failed to merge config value from `[..]/.cargo/other` into `[..]/.cargo/config`: \ failed to merge config value from `[..]/.cargo/other.toml` into `[..]/.cargo/config`: \
expected array, but found string", expected array, but found string",
); );
} }