fix: lock down allow-run permissions more (#25370)

`--allow-run` even with an allow list has essentially been
`--allow-all`... this locks it down more.

1. Resolves allow list for `--allow-run=` on startup to an absolute
path, then uses these paths when evaluating if a command can execute.
Also, adds these paths to `--deny-write`
1. Resolves the environment (cwd and env vars) before evaluating
permissions and before executing a command. Then uses this environment
to evaluate the permissions and then evaluate the command.
This commit is contained in:
David Sherret 2024-09-04 14:51:24 +02:00 committed by GitHub
parent 334c842392
commit 74fc66da11
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 684 additions and 364 deletions

View file

@ -32,7 +32,6 @@ use std::path::PathBuf;
use std::str::FromStr;
use std::string::ToString;
use std::sync::Arc;
use which::which;
pub mod prompter;
use prompter::permission_prompt;
@ -317,7 +316,7 @@ pub trait Descriptor: Eq + Clone + Hash {
/// Parse this descriptor from a list of Self::Arg, which may have been converted from
/// command-line strings.
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError>;
fn parse(list: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError>;
/// Generic check function to check this descriptor against a `UnaryPermission`.
fn check_in_permission(
@ -333,9 +332,6 @@ pub trait Descriptor: Eq + Clone + Hash {
fn stronger_than(&self, other: &Self) -> bool {
self == other
}
fn aliases(&self) -> Vec<Self> {
vec![]
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
@ -423,43 +419,33 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
desc: Option<&T>,
allow_partial: AllowPartial,
) -> PermissionState {
let aliases = desc.map_or(vec![], T::aliases);
for desc in [desc]
.into_iter()
.chain(aliases.iter().map(Some).collect::<Vec<_>>())
{
let state = if self.is_flag_denied(desc) || self.is_prompt_denied(desc) {
PermissionState::Denied
} else if self.is_granted(desc) {
match allow_partial {
AllowPartial::TreatAsGranted => PermissionState::Granted,
AllowPartial::TreatAsDenied => {
if self.is_partial_flag_denied(desc) {
PermissionState::Denied
} else {
PermissionState::Granted
}
}
AllowPartial::TreatAsPartialGranted => {
if self.is_partial_flag_denied(desc) {
PermissionState::GrantedPartial
} else {
PermissionState::Granted
}
if self.is_flag_denied(desc) || self.is_prompt_denied(desc) {
PermissionState::Denied
} else if self.is_granted(desc) {
match allow_partial {
AllowPartial::TreatAsGranted => PermissionState::Granted,
AllowPartial::TreatAsDenied => {
if self.is_partial_flag_denied(desc) {
PermissionState::Denied
} else {
PermissionState::Granted
}
}
AllowPartial::TreatAsPartialGranted => {
if self.is_partial_flag_denied(desc) {
PermissionState::GrantedPartial
} else {
PermissionState::Granted
}
}
} else if matches!(allow_partial, AllowPartial::TreatAsDenied)
&& self.is_partial_flag_denied(desc)
{
PermissionState::Denied
} else {
PermissionState::Prompt
};
if state != PermissionState::Prompt {
return state;
}
} else if matches!(allow_partial, AllowPartial::TreatAsDenied)
&& self.is_partial_flag_denied(desc)
{
PermissionState::Denied
} else {
PermissionState::Prompt
}
PermissionState::Prompt
}
fn request_desc(
@ -512,9 +498,6 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
match desc {
Some(desc) => {
self.granted_list.retain(|v| !v.stronger_than(desc));
for alias in desc.aliases() {
self.granted_list.retain(|v| !v.stronger_than(&alias));
}
}
None => {
self.granted_global = false;
@ -582,11 +565,7 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
) {
match desc {
Some(desc) => {
let aliases = desc.aliases();
list.insert(desc);
for alias in aliases {
list.insert(alias);
}
}
None => *list_global = true,
}
@ -612,7 +591,7 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
ChildUnaryPermissionArg::GrantedList(granted_list) => {
let granted: Vec<T::Arg> =
granted_list.into_iter().map(From::from).collect();
perms.granted_list = T::parse(&Some(granted))?;
perms.granted_list = T::parse(Some(&granted))?;
if !perms
.granted_list
.iter()
@ -649,7 +628,7 @@ impl Descriptor for ReadDescriptor {
perm.check_desc(Some(self), true, api_name, || None)
}
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(args: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_path_list(args, ReadDescriptor)
}
@ -681,7 +660,7 @@ impl Descriptor for WriteDescriptor {
perm.check_desc(Some(self), true, api_name, || None)
}
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(args: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_path_list(args, WriteDescriptor)
}
@ -754,7 +733,7 @@ impl Descriptor for NetDescriptor {
perm.check_desc(Some(self), false, api_name, || None)
}
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(args: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_net_list(args)
}
@ -864,7 +843,7 @@ impl Descriptor for EnvDescriptor {
perm.check_desc(Some(self), false, api_name, || None)
}
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(list: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_env_list(list)
}
@ -883,6 +862,11 @@ impl AsRef<str> for EnvDescriptor {
}
}
pub enum RunDescriptorArg {
Name(String),
Path(PathBuf),
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum RunDescriptor {
/// Warning: You may want to construct with `RunDescriptor::from()` for case
@ -893,8 +877,26 @@ pub enum RunDescriptor {
Path(PathBuf),
}
impl From<String> for RunDescriptorArg {
fn from(s: String) -> Self {
#[cfg(windows)]
let s = s.to_lowercase();
let is_path = s.contains('/');
#[cfg(windows)]
let is_path = is_path || s.contains('\\') || Path::new(&s).is_absolute();
if is_path {
Self::Path(resolve_from_cwd(Path::new(&s)).unwrap())
} else {
match which::which(&s) {
Ok(path) => Self::Path(path),
Err(_) => Self::Name(s),
}
}
}
}
impl Descriptor for RunDescriptor {
type Arg = String;
type Arg = RunDescriptorArg;
fn check_in_permission(
&self,
@ -905,7 +907,7 @@ impl Descriptor for RunDescriptor {
perm.check_desc(Some(self), false, api_name, || None)
}
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(args: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_run_list(args)
}
@ -916,16 +918,6 @@ impl Descriptor for RunDescriptor {
fn name(&self) -> Cow<str> {
Cow::from(self.to_string())
}
fn aliases(&self) -> Vec<Self> {
match self {
RunDescriptor::Name(name) => match which(name) {
Ok(path) => vec![RunDescriptor::Path(path)],
Err(_) => vec![],
},
RunDescriptor::Path(_) => vec![],
}
}
}
impl From<String> for RunDescriptor {
@ -938,7 +930,10 @@ impl From<String> for RunDescriptor {
if is_path {
Self::Path(resolve_from_cwd(Path::new(&s)).unwrap())
} else {
Self::Name(s)
match which::which(&s) {
Ok(path) => Self::Path(path),
Err(_) => Self::Name(s),
}
}
}
}
@ -947,11 +942,7 @@ impl From<PathBuf> for RunDescriptor {
fn from(p: PathBuf) -> Self {
#[cfg(windows)]
let p = PathBuf::from(p.to_string_lossy().to_string().to_lowercase());
if p.is_absolute() {
Self::Path(p)
} else {
Self::Path(resolve_from_cwd(&p).unwrap())
}
Self::Path(resolve_from_cwd(&p).unwrap())
}
}
@ -988,7 +979,7 @@ impl Descriptor for SysDescriptor {
perm.check_desc(Some(self), false, api_name, || None)
}
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(list: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_sys_list(list)
}
@ -1025,7 +1016,7 @@ impl Descriptor for FfiDescriptor {
perm.check_desc(Some(self), true, api_name, || None)
}
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
fn parse(list: Option<&[Self::Arg]>) -> Result<HashSet<Self>, AnyError> {
parse_path_list(list, FfiDescriptor)
}
@ -1330,15 +1321,16 @@ impl UnaryPermission<RunDescriptor> {
pub fn check(
&mut self,
cmd: &str,
cmd: &Path,
api_name: Option<&str>,
) -> Result<(), AnyError> {
debug_assert!(cmd.is_absolute());
skip_check_if_is_permission_fully_granted!(self);
self.check_desc(
Some(&RunDescriptor::from(cmd.to_string())),
Some(&RunDescriptor::Path(cmd.to_path_buf())),
false,
api_name,
|| Some(format!("\"{}\"", cmd)),
|| Some(format!("\"{}\"", cmd.display())),
)
}
@ -1346,6 +1338,21 @@ impl UnaryPermission<RunDescriptor> {
skip_check_if_is_permission_fully_granted!(self);
self.check_desc(None, false, api_name, || None)
}
/// Queries without prompting
pub fn query_all(&mut self, api_name: Option<&str>) -> bool {
if self.is_allow_all() {
return true;
}
let (result, _prompted, _is_allow_all) =
self.query_desc(None, AllowPartial::TreatAsDenied).check2(
RunDescriptor::flag_name(),
api_name,
|| None,
/* prompt */ false,
);
result.is_ok()
}
}
impl UnaryPermission<FfiDescriptor> {
@ -1429,7 +1436,7 @@ pub struct PermissionsOptions {
pub deny_ffi: Option<Vec<PathBuf>>,
pub allow_read: Option<Vec<PathBuf>>,
pub deny_read: Option<Vec<PathBuf>>,
pub allow_run: Option<Vec<String>>,
pub allow_run: Option<Vec<PathBuf>>,
pub deny_run: Option<Vec<String>>,
pub allow_sys: Option<Vec<String>>,
pub deny_sys: Option<Vec<String>>,
@ -1440,8 +1447,8 @@ pub struct PermissionsOptions {
impl Permissions {
pub fn new_unary<T>(
allow_list: &Option<Vec<T::Arg>>,
deny_list: &Option<Vec<T::Arg>>,
allow_list: Option<&[T::Arg]>,
deny_list: Option<&[T::Arg]>,
prompt: bool,
) -> Result<UnaryPermission<T>, AnyError>
where
@ -1470,38 +1477,54 @@ impl Permissions {
pub fn from_options(opts: &PermissionsOptions) -> Result<Self, AnyError> {
Ok(Self {
read: Permissions::new_unary(
&opts.allow_read,
&opts.deny_read,
opts.allow_read.as_deref(),
opts.deny_read.as_deref(),
opts.prompt,
)?,
write: Permissions::new_unary(
&opts.allow_write,
&opts.deny_write,
opts.allow_write.as_deref(),
opts.deny_write.as_deref(),
opts.prompt,
)?,
net: Permissions::new_unary(
&opts.allow_net,
&opts.deny_net,
opts.allow_net.as_deref(),
opts.deny_net.as_deref(),
opts.prompt,
)?,
env: Permissions::new_unary(
&opts.allow_env,
&opts.deny_env,
opts.allow_env.as_deref(),
opts.deny_env.as_deref(),
opts.prompt,
)?,
sys: Permissions::new_unary(
&opts.allow_sys,
&opts.deny_sys,
opts.allow_sys.as_deref(),
opts.deny_sys.as_deref(),
opts.prompt,
)?,
run: Permissions::new_unary(
&opts.allow_run,
&opts.deny_run,
opts
.allow_run
.as_ref()
.map(|d| {
d.iter()
.map(|s| RunDescriptorArg::Path(s.clone()))
.collect::<Vec<_>>()
})
.as_deref(),
opts
.deny_run
.as_ref()
.map(|d| {
d.iter()
.map(|s| RunDescriptorArg::from(s.clone()))
.collect::<Vec<_>>()
})
.as_deref(),
opts.prompt,
)?,
ffi: Permissions::new_unary(
&opts.allow_ffi,
&opts.deny_ffi,
opts.allow_ffi.as_deref(),
opts.deny_ffi.as_deref(),
opts.prompt,
)?,
all: Permissions::new_all(opts.allow_all),
@ -1534,13 +1557,13 @@ impl Permissions {
fn none(prompt: bool) -> Self {
Self {
read: Permissions::new_unary(&None, &None, prompt).unwrap(),
write: Permissions::new_unary(&None, &None, prompt).unwrap(),
net: Permissions::new_unary(&None, &None, prompt).unwrap(),
env: Permissions::new_unary(&None, &None, prompt).unwrap(),
sys: Permissions::new_unary(&None, &None, prompt).unwrap(),
run: Permissions::new_unary(&None, &None, prompt).unwrap(),
ffi: Permissions::new_unary(&None, &None, prompt).unwrap(),
read: Permissions::new_unary(None, None, prompt).unwrap(),
write: Permissions::new_unary(None, None, prompt).unwrap(),
net: Permissions::new_unary(None, None, prompt).unwrap(),
env: Permissions::new_unary(None, None, prompt).unwrap(),
sys: Permissions::new_unary(None, None, prompt).unwrap(),
run: Permissions::new_unary(None, None, prompt).unwrap(),
ffi: Permissions::new_unary(None, None, prompt).unwrap(),
all: Permissions::new_all(false),
}
}
@ -1669,7 +1692,7 @@ impl PermissionsContainer {
#[inline(always)]
pub fn check_run(
&mut self,
cmd: &str,
cmd: &Path,
api_name: &str,
) -> Result<(), AnyError> {
self.0.lock().run.check(cmd, Some(api_name))
@ -1680,6 +1703,11 @@ impl PermissionsContainer {
self.0.lock().run.check_all(Some(api_name))
}
#[inline(always)]
pub fn query_run_all(&mut self, api_name: &str) -> bool {
self.0.lock().run.query_all(Some(api_name))
}
#[inline(always)]
pub fn check_sys(&self, kind: &str, api_name: &str) -> Result<(), AnyError> {
self.0.lock().sys.check(kind, Some(api_name))
@ -1871,12 +1899,12 @@ const fn unit_permission_from_flag_bools(
}
}
fn global_from_option<T>(flag: &Option<Vec<T>>) -> bool {
fn global_from_option<T>(flag: Option<&[T]>) -> bool {
matches!(flag, Some(v) if v.is_empty())
}
fn parse_net_list(
list: &Option<Vec<String>>,
list: Option<&[String]>,
) -> Result<HashSet<NetDescriptor>, AnyError> {
if let Some(v) = list {
v.iter()
@ -1888,7 +1916,7 @@ fn parse_net_list(
}
fn parse_env_list(
list: &Option<Vec<String>>,
list: Option<&[String]>,
) -> Result<HashSet<EnvDescriptor>, AnyError> {
if let Some(v) = list {
v.iter()
@ -1906,7 +1934,7 @@ fn parse_env_list(
}
fn parse_path_list<T: Descriptor + Hash>(
list: &Option<Vec<PathBuf>>,
list: Option<&[PathBuf]>,
f: fn(PathBuf) -> T,
) -> Result<HashSet<T>, AnyError> {
if let Some(v) = list {
@ -1925,7 +1953,7 @@ fn parse_path_list<T: Descriptor + Hash>(
}
fn parse_sys_list(
list: &Option<Vec<String>>,
list: Option<&[String]>,
) -> Result<HashSet<SysDescriptor>, AnyError> {
if let Some(v) = list {
v.iter()
@ -1943,22 +1971,19 @@ fn parse_sys_list(
}
fn parse_run_list(
list: &Option<Vec<String>>,
list: Option<&[RunDescriptorArg]>,
) -> Result<HashSet<RunDescriptor>, AnyError> {
let mut result = HashSet::new();
if let Some(v) = list {
for s in v {
if s.is_empty() {
return Err(AnyError::msg("Empty path is not allowed"));
} else {
let desc = RunDescriptor::from(s.to_string());
let aliases = desc.aliases();
result.insert(desc);
result.extend(aliases);
}
}
}
Ok(result)
let Some(v) = list else {
return Ok(HashSet::new());
};
Ok(
v.iter()
.map(|arg| match arg {
RunDescriptorArg::Name(s) => RunDescriptor::Name(s.clone()),
RunDescriptorArg::Path(l) => RunDescriptor::Path(l.clone()),
})
.collect(),
)
}
fn escalation_error() -> AnyError {
@ -2298,6 +2323,9 @@ mod tests {
macro_rules! svec {
($($x:expr),*) => (vec![$($x.to_string()),*]);
}
macro_rules! sarr {
($($x:expr),*) => ([$($x.to_string()),*]);
}
#[test]
fn check_paths() {
@ -2678,94 +2706,88 @@ mod tests {
set_prompter(Box::new(TestPrompter));
let perms1 = Permissions::allow_all();
let perms2 = Permissions {
read: Permissions::new_unary(
&Some(vec![PathBuf::from("/foo")]),
&None,
false,
)
.unwrap(),
read: Permissions::new_unary(Some(&[PathBuf::from("/foo")]), None, false)
.unwrap(),
write: Permissions::new_unary(
&Some(vec![PathBuf::from("/foo")]),
&None,
Some(&[PathBuf::from("/foo")]),
None,
false,
)
.unwrap(),
ffi: Permissions::new_unary(
&Some(vec![PathBuf::from("/foo")]),
&None,
ffi: Permissions::new_unary(Some(&[PathBuf::from("/foo")]), None, false)
.unwrap(),
net: Permissions::new_unary(Some(&sarr!["127.0.0.1:8000"]), None, false)
.unwrap(),
env: Permissions::new_unary(Some(&sarr!["HOME"]), None, false).unwrap(),
sys: Permissions::new_unary(Some(&sarr!["hostname"]), None, false)
.unwrap(),
run: Permissions::new_unary(
Some(&["deno".to_string().into()]),
None,
false,
)
.unwrap(),
net: Permissions::new_unary(&Some(svec!["127.0.0.1:8000"]), &None, false)
.unwrap(),
env: Permissions::new_unary(&Some(svec!["HOME"]), &None, false).unwrap(),
sys: Permissions::new_unary(&Some(svec!["hostname"]), &None, false)
.unwrap(),
run: Permissions::new_unary(&Some(svec!["deno"]), &None, false).unwrap(),
all: Permissions::new_all(false),
};
let perms3 = Permissions {
read: Permissions::new_unary(
&None,
&Some(vec![PathBuf::from("/foo")]),
false,
)
.unwrap(),
read: Permissions::new_unary(None, Some(&[PathBuf::from("/foo")]), false)
.unwrap(),
write: Permissions::new_unary(
&None,
&Some(vec![PathBuf::from("/foo")]),
None,
Some(&[PathBuf::from("/foo")]),
false,
)
.unwrap(),
ffi: Permissions::new_unary(
&None,
&Some(vec![PathBuf::from("/foo")]),
ffi: Permissions::new_unary(None, Some(&[PathBuf::from("/foo")]), false)
.unwrap(),
net: Permissions::new_unary(None, Some(&sarr!["127.0.0.1:8000"]), false)
.unwrap(),
env: Permissions::new_unary(None, Some(&sarr!["HOME"]), false).unwrap(),
sys: Permissions::new_unary(None, Some(&sarr!["hostname"]), false)
.unwrap(),
run: Permissions::new_unary(
None,
Some(&["deno".to_string().into()]),
false,
)
.unwrap(),
net: Permissions::new_unary(&None, &Some(svec!["127.0.0.1:8000"]), false)
.unwrap(),
env: Permissions::new_unary(&None, &Some(svec!["HOME"]), false).unwrap(),
sys: Permissions::new_unary(&None, &Some(svec!["hostname"]), false)
.unwrap(),
run: Permissions::new_unary(&None, &Some(svec!["deno"]), false).unwrap(),
all: Permissions::new_all(false),
};
let perms4 = Permissions {
read: Permissions::new_unary(
&Some(vec![]),
&Some(vec![PathBuf::from("/foo")]),
Some(&[]),
Some(&[PathBuf::from("/foo")]),
false,
)
.unwrap(),
write: Permissions::new_unary(
&Some(vec![]),
&Some(vec![PathBuf::from("/foo")]),
Some(&[]),
Some(&[PathBuf::from("/foo")]),
false,
)
.unwrap(),
ffi: Permissions::new_unary(
&Some(vec![]),
&Some(vec![PathBuf::from("/foo")]),
Some(&[]),
Some(&[PathBuf::from("/foo")]),
false,
)
.unwrap(),
net: Permissions::new_unary(
&Some(vec![]),
&Some(svec!["127.0.0.1:8000"]),
Some(&[]),
Some(&sarr!["127.0.0.1:8000"]),
false,
)
.unwrap(),
env: Permissions::new_unary(&Some(vec![]), &Some(svec!["HOME"]), false)
env: Permissions::new_unary(Some(&[]), Some(&sarr!["HOME"]), false)
.unwrap(),
sys: Permissions::new_unary(
&Some(vec![]),
&Some(svec!["hostname"]),
sys: Permissions::new_unary(Some(&[]), Some(&sarr!["hostname"]), false)
.unwrap(),
run: Permissions::new_unary(
Some(&[]),
Some(&["deno".to_string().into()]),
false,
)
.unwrap(),
run: Permissions::new_unary(&Some(vec![]), &Some(svec!["deno"]), false)
.unwrap(),
all: Permissions::new_all(false),
};
#[rustfmt::skip]
@ -2894,33 +2916,38 @@ mod tests {
set_prompter(Box::new(TestPrompter));
let mut perms = Permissions {
read: Permissions::new_unary(
&Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
&None,
Some(&[PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
None,
false,
)
.unwrap(),
write: Permissions::new_unary(
&Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
&None,
Some(&[PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
None,
false,
)
.unwrap(),
ffi: Permissions::new_unary(
&Some(vec![PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
&None,
Some(&[PathBuf::from("/foo"), PathBuf::from("/foo/baz")]),
None,
false,
)
.unwrap(),
net: Permissions::new_unary(
&Some(svec!["127.0.0.1", "127.0.0.1:8000"]),
&None,
Some(&sarr!["127.0.0.1", "127.0.0.1:8000"]),
None,
false,
)
.unwrap(),
env: Permissions::new_unary(&Some(svec!["HOME"]), &None, false).unwrap(),
sys: Permissions::new_unary(&Some(svec!["hostname"]), &None, false)
env: Permissions::new_unary(Some(&sarr!["HOME"]), None, false).unwrap(),
sys: Permissions::new_unary(Some(&sarr!["hostname"]), None, false)
.unwrap(),
run: Permissions::new_unary(&Some(svec!["deno"]), &None, false).unwrap(),
run: Permissions::new_unary(
Some(&["deno".to_string().into()]),
None,
false,
)
.unwrap(),
all: Permissions::new_all(false),
};
#[rustfmt::skip]
@ -3006,11 +3033,13 @@ mod tests {
.check(&NetDescriptor("deno.land".parse().unwrap(), None), None)
.is_err());
#[allow(clippy::disallowed_methods)]
let cwd = std::env::current_dir().unwrap();
prompt_value.set(true);
assert!(perms.run.check("cat", None).is_ok());
assert!(perms.run.check(&cwd.join("cat"), None).is_ok());
prompt_value.set(false);
assert!(perms.run.check("cat", None).is_ok());
assert!(perms.run.check("ls", None).is_err());
assert!(perms.run.check(&cwd.join("cat"), None).is_ok());
assert!(perms.run.check(&cwd.join("ls"), None).is_err());
prompt_value.set(true);
assert!(perms.env.check("HOME", None).is_ok());
@ -3102,12 +3131,14 @@ mod tests {
.is_ok());
prompt_value.set(false);
assert!(perms.run.check("cat", None).is_err());
#[allow(clippy::disallowed_methods)]
let cwd = std::env::current_dir().unwrap();
assert!(perms.run.check(&cwd.join("cat"), None).is_err());
prompt_value.set(true);
assert!(perms.run.check("cat", None).is_err());
assert!(perms.run.check("ls", None).is_ok());
assert!(perms.run.check(&cwd.join("cat"), None).is_err());
assert!(perms.run.check(&cwd.join("ls"), None).is_ok());
prompt_value.set(false);
assert!(perms.run.check("ls", None).is_ok());
assert!(perms.run.check(&cwd.join("ls"), None).is_ok());
prompt_value.set(false);
assert!(perms.env.check("HOME", None).is_err());
@ -3134,7 +3165,7 @@ mod tests {
let mut perms = Permissions::allow_all();
perms.env = UnaryPermission {
granted_global: false,
..Permissions::new_unary(&Some(svec!["HOME"]), &None, false).unwrap()
..Permissions::new_unary(Some(&sarr!["HOME"]), None, false).unwrap()
};
prompt_value.set(true);
@ -3150,14 +3181,14 @@ mod tests {
fn test_check_partial_denied() {
let mut perms = Permissions {
read: Permissions::new_unary(
&Some(vec![]),
&Some(vec![PathBuf::from("/foo/bar")]),
Some(&[]),
Some(&[PathBuf::from("/foo/bar")]),
false,
)
.unwrap(),
write: Permissions::new_unary(
&Some(vec![]),
&Some(vec![PathBuf::from("/foo/bar")]),
Some(&[]),
Some(&[PathBuf::from("/foo/bar")]),
false,
)
.unwrap(),
@ -3175,8 +3206,8 @@ mod tests {
fn test_net_fully_qualified_domain_name() {
let mut perms = Permissions {
net: Permissions::new_unary(
&Some(vec!["allowed.domain".to_string(), "1.1.1.1".to_string()]),
&Some(vec!["denied.domain".to_string(), "2.2.2.2".to_string()]),
Some(&["allowed.domain".to_string(), "1.1.1.1".to_string()]),
Some(&["denied.domain".to_string(), "2.2.2.2".to_string()]),
false,
)
.unwrap(),
@ -3341,8 +3372,8 @@ mod tests {
fn test_create_child_permissions() {
set_prompter(Box::new(TestPrompter));
let mut main_perms = Permissions {
env: Permissions::new_unary(&Some(vec![]), &None, false).unwrap(),
net: Permissions::new_unary(&Some(svec!["foo", "bar"]), &None, false)
env: Permissions::new_unary(Some(&[]), None, false).unwrap(),
net: Permissions::new_unary(Some(&sarr!["foo", "bar"]), None, false)
.unwrap(),
..Permissions::none_without_prompt()
};
@ -3358,8 +3389,8 @@ mod tests {
)
.unwrap(),
Permissions {
env: Permissions::new_unary(&Some(vec![]), &None, false).unwrap(),
net: Permissions::new_unary(&Some(svec!["foo"]), &None, false).unwrap(),
env: Permissions::new_unary(Some(&[]), None, false).unwrap(),
net: Permissions::new_unary(Some(&sarr!["foo"]), None, false).unwrap(),
..Permissions::none_without_prompt()
}
);
@ -3445,20 +3476,20 @@ mod tests {
set_prompter(Box::new(TestPrompter));
assert!(Permissions::new_unary::<ReadDescriptor>(
&Some(vec![Default::default()]),
&None,
Some(&[Default::default()]),
None,
false
)
.is_err());
assert!(Permissions::new_unary::<EnvDescriptor>(
&Some(vec![Default::default()]),
&None,
Some(&[Default::default()]),
None,
false
)
.is_err());
assert!(Permissions::new_unary::<NetDescriptor>(
&Some(vec![Default::default()]),
&None,
Some(&[Default::default()]),
None,
false
)
.is_err());