Skip to content

Commit 82eba47

Browse files
authored
feat: add --ignore-env=... (#31187)
Adds the ability to ignore certain environment variables and return `undefined` instead of erroring.
1 parent 3c0f289 commit 82eba47

File tree

13 files changed

+417
-75
lines changed

13 files changed

+417
-75
lines changed

cli/args/flags.rs

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,7 @@ pub struct PermissionFlags {
814814
pub allow_all: bool,
815815
pub allow_env: Option<Vec<String>>,
816816
pub deny_env: Option<Vec<String>>,
817+
pub ignore_env: Option<Vec<String>>,
817818
pub allow_ffi: Option<Vec<String>>,
818819
pub deny_ffi: Option<Vec<String>>,
819820
pub allow_net: Option<Vec<String>>,
@@ -836,6 +837,7 @@ impl PermissionFlags {
836837
self.allow_all
837838
|| self.allow_env.is_some()
838839
|| self.deny_env.is_some()
840+
|| self.ignore_env.is_some()
839841
|| self.allow_ffi.is_some()
840842
|| self.deny_ffi.is_some()
841843
|| self.allow_net.is_some()
@@ -974,6 +976,17 @@ impl Flags {
974976
_ => {}
975977
}
976978

979+
match &self.permissions.ignore_env {
980+
Some(env_ignorelist) if env_ignorelist.is_empty() => {
981+
args.push("--ignore-env".to_string());
982+
}
983+
Some(env_ignorelist) => {
984+
let s = format!("--ignore-env={}", env_ignorelist.join(","));
985+
args.push(s);
986+
}
987+
_ => {}
988+
}
989+
977990
match &self.permissions.allow_run {
978991
Some(run_allowlist) if run_allowlist.is_empty() => {
979992
args.push("--allow-run".to_string());
@@ -4163,6 +4176,30 @@ fn compile_args_without_check_args(app: Command) -> Command {
41634176
}
41644177

41654178
fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
4179+
let make_deny_ignore_env_arg = |arg: Arg| {
4180+
let mut arg = arg
4181+
.num_args(0..)
4182+
.use_value_delimiter(true)
4183+
.require_equals(true)
4184+
.value_name("VARIABLE_NAME")
4185+
.long_help("false")
4186+
.value_parser(|key: &str| {
4187+
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
4188+
return Err(format!("invalid key \"{key}\""));
4189+
}
4190+
4191+
Ok(if cfg!(windows) {
4192+
key.to_uppercase()
4193+
} else {
4194+
key.to_string()
4195+
})
4196+
})
4197+
.hide(true);
4198+
if let Some(requires) = requires {
4199+
arg = arg.requires(requires)
4200+
}
4201+
arg
4202+
};
41664203
app
41674204
.after_help(cstr!(r#"<y>Permission options:</>
41684205
<y>Docs</>: <c>https://docs.deno.com/go/permissions</>
@@ -4367,33 +4404,8 @@ fn permission_args(app: Command, requires: Option<&'static str>) -> Command {
43674404
arg
43684405
}
43694406
)
4370-
.arg(
4371-
{
4372-
let mut arg = Arg::new("deny-env")
4373-
.long("deny-env")
4374-
.num_args(0..)
4375-
.use_value_delimiter(true)
4376-
.require_equals(true)
4377-
.value_name("VARIABLE_NAME")
4378-
.long_help("false")
4379-
.value_parser(|key: &str| {
4380-
if key.is_empty() || key.contains(&['=', '\0'] as &[char]) {
4381-
return Err(format!("invalid key \"{key}\""));
4382-
}
4383-
4384-
Ok(if cfg!(windows) {
4385-
key.to_uppercase()
4386-
} else {
4387-
key.to_string()
4388-
})
4389-
})
4390-
.hide(true);
4391-
if let Some(requires) = requires {
4392-
arg = arg.requires(requires)
4393-
}
4394-
arg
4395-
}
4396-
)
4407+
.arg(make_deny_ignore_env_arg(Arg::new("deny-env").long("deny-env")))
4408+
.arg(make_deny_ignore_env_arg(Arg::new("ignore-env").long("ignore-env")))
43974409
.arg(
43984410
{
43994411
let mut arg = Arg::new("allow-sys")
@@ -6624,6 +6636,11 @@ fn permission_args_parse(
66246636
debug!("env denylist: {:#?}", &flags.permissions.deny_env);
66256637
}
66266638

6639+
if let Some(env_wl) = matches.remove_many::<String>("ignore-env") {
6640+
flags.permissions.ignore_env = Some(env_wl.collect());
6641+
debug!("env ignorelist: {:#?}", &flags.permissions.ignore_env);
6642+
}
6643+
66276644
if let Some(run_wl) = matches.remove_many::<String>("allow-run") {
66286645
flags.permissions.allow_run = Some(run_wl.collect());
66296646
debug!("run allowlist: {:#?}", &flags.permissions.allow_run);
@@ -9208,6 +9225,26 @@ mod tests {
92089225
);
92099226
}
92109227

9228+
#[test]
9229+
fn ignore_env_ignorelist() {
9230+
let r =
9231+
flags_from_vec(svec!["deno", "run", "--ignore-env=HOME", "script.ts"]);
9232+
assert_eq!(
9233+
r.unwrap(),
9234+
Flags {
9235+
subcommand: DenoSubcommand::Run(RunFlags::new_default(
9236+
"script.ts".to_string(),
9237+
)),
9238+
permissions: PermissionFlags {
9239+
ignore_env: Some(svec!["HOME"]),
9240+
..Default::default()
9241+
},
9242+
code_cache_enabled: true,
9243+
..Flags::default()
9244+
}
9245+
);
9246+
}
9247+
92119248
#[test]
92129249
fn allow_env_allowlist_multiple() {
92139250
let r = flags_from_vec(svec![
@@ -9252,6 +9289,30 @@ mod tests {
92529289
);
92539290
}
92549291

9292+
#[test]
9293+
fn deny_env_ignorelist_multiple() {
9294+
let r = flags_from_vec(svec![
9295+
"deno",
9296+
"run",
9297+
"--ignore-env=HOME,PATH",
9298+
"script.ts"
9299+
]);
9300+
assert_eq!(
9301+
r.unwrap(),
9302+
Flags {
9303+
subcommand: DenoSubcommand::Run(RunFlags::new_default(
9304+
"script.ts".to_string(),
9305+
)),
9306+
permissions: PermissionFlags {
9307+
ignore_env: Some(svec!["HOME", "PATH"]),
9308+
..Default::default()
9309+
},
9310+
code_cache_enabled: true,
9311+
..Flags::default()
9312+
}
9313+
);
9314+
}
9315+
92559316
#[test]
92569317
fn allow_env_allowlist_validator() {
92579318
let r =

cli/args/mod.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,7 @@ fn flags_to_permissions_options(
15461546
}
15471547
}
15481548

1549-
fn handle_deny(
1549+
fn handle_deny_or_ignore(
15501550
value: Option<&Vec<String>>,
15511551
config: Option<&PermissionConfigValue>,
15521552
parse_config_value: &impl Fn(&str) -> String,
@@ -1616,19 +1616,24 @@ fn flags_to_permissions_options(
16161616
config.and_then(|c| c.permissions.env.allow.as_ref()),
16171617
&identity,
16181618
),
1619-
deny_env: handle_deny(
1619+
deny_env: handle_deny_or_ignore(
16201620
flags.deny_env.as_ref(),
16211621
config.and_then(|c| c.permissions.env.deny.as_ref()),
16221622
&identity,
16231623
),
1624+
ignore_env: handle_deny_or_ignore(
1625+
flags.ignore_env.as_ref(),
1626+
config.and_then(|c| c.permissions.env.ignore.as_ref()),
1627+
&identity,
1628+
),
16241629
allow_net: handle_allow(
16251630
flags.allow_all,
16261631
config.and_then(|c| c.permissions.all),
16271632
flags.allow_net.as_ref(),
16281633
config.and_then(|c| c.permissions.net.allow.as_ref()),
16291634
&identity,
16301635
),
1631-
deny_net: handle_deny(
1636+
deny_net: handle_deny_or_ignore(
16321637
flags.deny_net.as_ref(),
16331638
config.and_then(|c| c.permissions.net.deny.as_ref()),
16341639
&identity,
@@ -1640,7 +1645,7 @@ fn flags_to_permissions_options(
16401645
config.and_then(|c| c.permissions.ffi.allow.as_ref()),
16411646
&make_fs_config_value_absolute,
16421647
),
1643-
deny_ffi: handle_deny(
1648+
deny_ffi: handle_deny_or_ignore(
16441649
flags.deny_ffi.as_ref(),
16451650
config.and_then(|c| c.permissions.ffi.deny.as_ref()),
16461651
&make_fs_config_value_absolute,
@@ -1652,7 +1657,7 @@ fn flags_to_permissions_options(
16521657
config.and_then(|c| c.permissions.read.allow.as_ref()),
16531658
&make_fs_config_value_absolute,
16541659
),
1655-
deny_read: handle_deny(
1660+
deny_read: handle_deny_or_ignore(
16561661
flags.deny_read.as_ref(),
16571662
config.and_then(|c| c.permissions.read.deny.as_ref()),
16581663
&make_fs_config_value_absolute,
@@ -1664,7 +1669,7 @@ fn flags_to_permissions_options(
16641669
config.and_then(|c| c.permissions.run.allow.as_ref()),
16651670
&make_run_config_value_absolute,
16661671
),
1667-
deny_run: handle_deny(
1672+
deny_run: handle_deny_or_ignore(
16681673
flags.deny_run.as_ref(),
16691674
config.and_then(|c| c.permissions.run.deny.as_ref()),
16701675
&make_run_config_value_absolute,
@@ -1676,7 +1681,7 @@ fn flags_to_permissions_options(
16761681
config.and_then(|c| c.permissions.sys.allow.as_ref()),
16771682
&identity,
16781683
),
1679-
deny_sys: handle_deny(
1684+
deny_sys: handle_deny_or_ignore(
16801685
flags.deny_sys.as_ref(),
16811686
config.and_then(|c| c.permissions.sys.deny.as_ref()),
16821687
&identity,
@@ -1688,7 +1693,7 @@ fn flags_to_permissions_options(
16881693
config.and_then(|c| c.permissions.write.allow.as_ref()),
16891694
&make_fs_config_value_absolute,
16901695
),
1691-
deny_write: handle_deny(
1696+
deny_write: handle_deny_or_ignore(
16921697
flags.deny_write.as_ref(),
16931698
config.and_then(|c| c.permissions.write.deny.as_ref()),
16941699
&make_fs_config_value_absolute,
@@ -1700,7 +1705,7 @@ fn flags_to_permissions_options(
17001705
config.and_then(|c| c.permissions.import.allow.as_ref()),
17011706
&identity,
17021707
),
1703-
deny_import: handle_deny(
1708+
deny_import: handle_deny_or_ignore(
17041709
flags.deny_import.as_ref(),
17051710
config.and_then(|c| c.permissions.import.deny.as_ref()),
17061711
&identity,
@@ -1711,6 +1716,7 @@ fn flags_to_permissions_options(
17111716

17121717
#[cfg(test)]
17131718
mod test {
1719+
use deno_config::deno_json::AllowDenyIgnorePermissionConfig;
17141720
use deno_config::deno_json::AllowDenyPermissionConfig;
17151721
use deno_config::deno_json::PermissionsObject;
17161722
use pretty_assertions::assert_eq;
@@ -1823,13 +1829,16 @@ mod test {
18231829
"example.com".to_string(),
18241830
])),
18251831
},
1826-
env: AllowDenyPermissionConfig {
1832+
env: AllowDenyIgnorePermissionConfig {
18271833
allow: Some(PermissionConfigValue::Some(vec![
18281834
"env-allow".to_string(),
18291835
])),
18301836
deny: Some(PermissionConfigValue::Some(vec![
18311837
"env-deny".to_string(),
18321838
])),
1839+
ignore: Some(PermissionConfigValue::Some(vec![
1840+
"env-ignore".to_string(),
1841+
])),
18331842
},
18341843
net: AllowDenyPermissionConfig {
18351844
allow: Some(PermissionConfigValue::Some(vec![
@@ -1874,6 +1883,7 @@ mod test {
18741883
PermissionsOptions {
18751884
allow_env: Some(vec!["env-allow".to_string()]),
18761885
deny_env: Some(vec!["env-deny".to_string()]),
1886+
ignore_env: Some(vec!["env-ignore".to_string()]),
18771887
allow_net: Some(vec!["net-allow".to_string()]),
18781888
deny_net: Some(vec!["net-deny".to_string()]),
18791889
allow_ffi: Some(vec![
@@ -1973,6 +1983,7 @@ mod test {
19731983
PermissionsOptions {
19741984
allow_env: Some(vec![]),
19751985
deny_env: None,
1986+
ignore_env: None,
19761987
allow_net: Some(vec![]),
19771988
deny_net: None,
19781989
allow_ffi: Some(vec![]),

cli/schemas/config-file.v1.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@
1616
"items": { "type": "string" }
1717
}]
1818
},
19+
"allowDenyIgnorePermissionConfig": {
20+
"type": "object",
21+
"description": "Object form to allow, deny, and/or ignore permissions.",
22+
"additionalProperties": false,
23+
"properties": {
24+
"allow": { "$ref": "#/$defs/permissionConfigValue" },
25+
"deny": { "$ref": "#/$defs/permissionConfigValue" },
26+
"ignore": { "$ref": "#/$defs/permissionConfigValue" }
27+
}
28+
},
29+
"allowDenyIgnorePermissionConfigValue": {
30+
"oneOf": [{
31+
"$ref": "#/$defs/permissionConfigValue"
32+
}, {
33+
"$ref": "#/$defs/allowDenyIgnorePermissionConfig"
34+
}]
35+
},
1936
"allowDenyPermissionConfig": {
2037
"type": "object",
2138
"description": "Object form to allow and/or deny permissions.",
@@ -52,7 +69,7 @@
5269
"read": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },
5370
"write": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },
5471
"import": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },
55-
"env": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },
72+
"env": { "$ref": "#/$defs/allowDenyIgnorePermissionConfigValue" },
5673
"net": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },
5774
"run": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },
5875
"ffi": { "$ref": "#/$defs/allowDenyPermissionConfigValue" },

0 commit comments

Comments
 (0)