mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
perf(permissions): Fast exit from checks when permission is in "fully-granted" state (#22894)
Skips the access check if the specific unary permission is in an all-granted state. Generally prevents an allocation or two. Hooks up a quiet "all" permission that is automatically inherited. This permission will be used in the future to indicate that the user wishes to accept all side-effects of the permissions they explicitly granted. The "all" permission is an "ambient flag"-style permission that states whether "allow-all" was passed on the command-line.
This commit is contained in:
parent
eca7b0cddd
commit
c9a9d040a3
2 changed files with 310 additions and 299 deletions
|
@ -867,7 +867,8 @@ mod tests {
|
|||
fn create_test_worker() -> MainWorker {
|
||||
let main_module =
|
||||
resolve_path("./hello.js", &std::env::current_dir().unwrap()).unwrap();
|
||||
let permissions = PermissionsContainer::new(Permissions::default());
|
||||
let permissions =
|
||||
PermissionsContainer::new(Permissions::none_without_prompt());
|
||||
|
||||
let options = WorkerOptions {
|
||||
startup_snapshot: crate::js::deno_isolate_init(),
|
||||
|
|
|
@ -20,6 +20,7 @@ use once_cell::sync::Lazy;
|
|||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
@ -36,6 +37,16 @@ use prompter::PERMISSION_EMOJI;
|
|||
pub use prompter::set_prompt_callbacks;
|
||||
pub use prompter::PromptCallback;
|
||||
|
||||
/// Fast exit from permission check routines if this permission
|
||||
/// is in the "fully-granted" state.
|
||||
macro_rules! skip_check_if_is_permission_fully_granted {
|
||||
($this:ident) => {
|
||||
if $this.is_allow_all() {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn resolve_from_cwd(path: &Path) -> Result<PathBuf, AnyError> {
|
||||
if path.is_absolute() {
|
||||
|
@ -238,6 +249,31 @@ impl UnitPermission {
|
|||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn create_child_permissions(
|
||||
&mut self,
|
||||
flag: ChildUnitPermissionArg,
|
||||
) -> Result<Self, AnyError> {
|
||||
let mut perm = self.clone();
|
||||
match flag {
|
||||
ChildUnitPermissionArg::Inherit => {
|
||||
// copy
|
||||
}
|
||||
ChildUnitPermissionArg::Granted => {
|
||||
if self.check().is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
perm.state = PermissionState::Granted;
|
||||
}
|
||||
ChildUnitPermissionArg::NotGranted => {
|
||||
perm.state = PermissionState::Prompt;
|
||||
}
|
||||
}
|
||||
if self.state == PermissionState::Denied {
|
||||
perm.state = PermissionState::Denied;
|
||||
}
|
||||
Ok(perm)
|
||||
}
|
||||
}
|
||||
|
||||
/// A normalized environment variable name. On Windows this will
|
||||
|
@ -265,9 +301,20 @@ impl AsRef<str> for EnvVarName {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Descriptor: Eq + Clone {
|
||||
type Arg;
|
||||
pub trait Descriptor: Eq + Clone + Hash {
|
||||
type Arg: From<String>;
|
||||
|
||||
/// 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>;
|
||||
|
||||
/// Generic check function to check this descriptor against a `UnaryPermission`.
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError>;
|
||||
|
||||
fn flag_name() -> &'static str;
|
||||
fn name(&self) -> Cow<str>;
|
||||
// By default, specifies no-stronger-than relationship.
|
||||
|
@ -282,13 +329,13 @@ pub trait Descriptor: Eq + Clone {
|
|||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct UnaryPermission<T: Descriptor + Hash> {
|
||||
pub granted_global: bool,
|
||||
pub granted_list: HashSet<T>,
|
||||
pub flag_denied_global: bool,
|
||||
pub flag_denied_list: HashSet<T>,
|
||||
pub prompt_denied_global: bool,
|
||||
pub prompt_denied_list: HashSet<T>,
|
||||
pub prompt: bool,
|
||||
granted_global: bool,
|
||||
granted_list: HashSet<T>,
|
||||
flag_denied_global: bool,
|
||||
flag_denied_list: HashSet<T>,
|
||||
prompt_denied_global: bool,
|
||||
prompt_denied_list: HashSet<T>,
|
||||
prompt: bool,
|
||||
}
|
||||
|
||||
impl<T: Descriptor + Hash> Default for UnaryPermission<T> {
|
||||
|
@ -313,6 +360,20 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_allow_all(&self) -> bool {
|
||||
self.granted_global
|
||||
&& self.flag_denied_list.is_empty()
|
||||
&& self.prompt_denied_list.is_empty()
|
||||
}
|
||||
|
||||
pub fn check_all_api(
|
||||
&mut self,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, api_name, || None)
|
||||
}
|
||||
|
||||
fn check_desc(
|
||||
&mut self,
|
||||
desc: &Option<T>,
|
||||
|
@ -320,6 +381,7 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
|
|||
api_name: Option<&str>,
|
||||
get_display_name: impl Fn() -> Option<String>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let (result, prompted, is_allow_all) = self
|
||||
.query_desc(desc, AllowPartial::from(!assert_non_partial))
|
||||
.check2(
|
||||
|
@ -517,6 +579,45 @@ impl<T: Descriptor + Hash> UnaryPermission<T> {
|
|||
None => *list_global = true,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_child_permissions(
|
||||
&mut self,
|
||||
flag: ChildUnaryPermissionArg,
|
||||
) -> Result<UnaryPermission<T>, AnyError> {
|
||||
let mut perms = Self::default();
|
||||
|
||||
match flag {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
perms = self.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if self.check_all_api(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
perms.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
let granted: Vec<T::Arg> =
|
||||
granted_list.into_iter().map(From::from).collect();
|
||||
perms.granted_list = T::parse(&Some(granted))?;
|
||||
if !perms
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| desc.check_in_permission(self, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
perms.flag_denied_global = self.flag_denied_global;
|
||||
perms.flag_denied_list = self.flag_denied_list.clone();
|
||||
perms.prompt_denied_global = self.prompt_denied_global;
|
||||
perms.prompt_denied_list = self.prompt_denied_list.clone();
|
||||
perms.prompt = self.prompt;
|
||||
|
||||
Ok(perms)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
|
@ -525,6 +626,14 @@ pub struct ReadDescriptor(pub PathBuf);
|
|||
impl Descriptor for ReadDescriptor {
|
||||
type Arg = PathBuf;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &self.0, api_name)
|
||||
}
|
||||
|
||||
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_path_list(args, ReadDescriptor)
|
||||
}
|
||||
|
@ -548,6 +657,14 @@ pub struct WriteDescriptor(pub PathBuf);
|
|||
impl Descriptor for WriteDescriptor {
|
||||
type Arg = PathBuf;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &self.0, api_name)
|
||||
}
|
||||
|
||||
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_path_list(args, WriteDescriptor)
|
||||
}
|
||||
|
@ -577,6 +694,14 @@ impl NetDescriptor {
|
|||
impl Descriptor for NetDescriptor {
|
||||
type Arg = String;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &(self.0.as_str(), self.1), api_name)
|
||||
}
|
||||
|
||||
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_net_list(args)
|
||||
}
|
||||
|
@ -632,6 +757,14 @@ impl EnvDescriptor {
|
|||
impl Descriptor for EnvDescriptor {
|
||||
type Arg = String;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &self.0.inner, api_name)
|
||||
}
|
||||
|
||||
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_env_list(list)
|
||||
}
|
||||
|
@ -664,6 +797,14 @@ pub enum RunDescriptor {
|
|||
impl Descriptor for RunDescriptor {
|
||||
type Arg = String;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &self.to_string(), api_name)
|
||||
}
|
||||
|
||||
fn parse(args: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_run_list(args)
|
||||
}
|
||||
|
@ -723,12 +864,29 @@ impl ToString for RunDescriptor {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsRef<Path> for RunDescriptor {
|
||||
fn as_ref(&self) -> &Path {
|
||||
match self {
|
||||
RunDescriptor::Name(s) => s.as_ref(),
|
||||
RunDescriptor::Path(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct SysDescriptor(pub String);
|
||||
|
||||
impl Descriptor for SysDescriptor {
|
||||
type Arg = String;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &self.0, api_name)
|
||||
}
|
||||
|
||||
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_sys_list(list)
|
||||
}
|
||||
|
@ -756,6 +914,14 @@ pub struct FfiDescriptor(pub PathBuf);
|
|||
impl Descriptor for FfiDescriptor {
|
||||
type Arg = PathBuf;
|
||||
|
||||
fn check_in_permission(
|
||||
&self,
|
||||
perm: &mut UnaryPermission<Self>,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
UnaryPermission::<Self>::check(perm, &self.0, api_name)
|
||||
}
|
||||
|
||||
fn parse(list: &Option<Vec<Self::Arg>>) -> Result<HashSet<Self>, AnyError> {
|
||||
parse_path_list(list, FfiDescriptor)
|
||||
}
|
||||
|
@ -798,6 +964,7 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(
|
||||
&Some(ReadDescriptor(resolve_from_cwd(path)?)),
|
||||
true,
|
||||
|
@ -812,6 +979,7 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let desc = ReadDescriptor(resolve_from_cwd(path)?);
|
||||
self.check_desc(&Some(desc), false, api_name, || {
|
||||
Some(format!("\"{}\"", path.display()))
|
||||
|
@ -826,6 +994,7 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let desc = ReadDescriptor(resolve_from_cwd(path)?);
|
||||
self.check_desc(&Some(desc), false, Some(api_name), || {
|
||||
Some(format!("<{display}>"))
|
||||
|
@ -833,6 +1002,7 @@ impl UnaryPermission<ReadDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, api_name, || None)
|
||||
}
|
||||
}
|
||||
|
@ -862,6 +1032,7 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(
|
||||
&Some(WriteDescriptor(resolve_from_cwd(path)?)),
|
||||
true,
|
||||
|
@ -876,6 +1047,7 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(
|
||||
&Some(WriteDescriptor(resolve_from_cwd(path)?)),
|
||||
false,
|
||||
|
@ -892,6 +1064,7 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
display: &str,
|
||||
api_name: &str,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let desc = WriteDescriptor(resolve_from_cwd(path)?);
|
||||
self.check_desc(&Some(desc), false, Some(api_name), || {
|
||||
Some(format!("<{display}>"))
|
||||
|
@ -899,6 +1072,7 @@ impl UnaryPermission<WriteDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, api_name, || None)
|
||||
}
|
||||
}
|
||||
|
@ -933,6 +1107,7 @@ impl UnaryPermission<NetDescriptor> {
|
|||
host: &(T, Option<u16>),
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&Some(NetDescriptor::new(&host)), false, api_name, || None)
|
||||
}
|
||||
|
||||
|
@ -941,6 +1116,7 @@ impl UnaryPermission<NetDescriptor> {
|
|||
url: &url::Url,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let hostname = url
|
||||
.host_str()
|
||||
.ok_or_else(|| uri_error("Missing host"))?
|
||||
|
@ -956,6 +1132,7 @@ impl UnaryPermission<NetDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, None, || None)
|
||||
}
|
||||
}
|
||||
|
@ -976,11 +1153,17 @@ impl UnaryPermission<EnvDescriptor> {
|
|||
self.revoke_desc(&env.map(EnvDescriptor::new))
|
||||
}
|
||||
|
||||
pub fn check(&mut self, env: &str) -> Result<(), AnyError> {
|
||||
self.check_desc(&Some(EnvDescriptor::new(env)), false, None, || None)
|
||||
pub fn check(
|
||||
&mut self,
|
||||
env: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&Some(EnvDescriptor::new(env)), false, api_name, || None)
|
||||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, None, || None)
|
||||
}
|
||||
}
|
||||
|
@ -1006,6 +1189,7 @@ impl UnaryPermission<SysDescriptor> {
|
|||
kind: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(
|
||||
&Some(SysDescriptor(kind.to_string())),
|
||||
false,
|
||||
|
@ -1015,6 +1199,7 @@ impl UnaryPermission<SysDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, None, || None)
|
||||
}
|
||||
}
|
||||
|
@ -1042,6 +1227,7 @@ impl UnaryPermission<RunDescriptor> {
|
|||
cmd: &str,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(
|
||||
&Some(RunDescriptor::from(cmd.to_string())),
|
||||
false,
|
||||
|
@ -1051,6 +1237,7 @@ impl UnaryPermission<RunDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_all(&mut self, api_name: Option<&str>) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, api_name, || None)
|
||||
}
|
||||
}
|
||||
|
@ -1079,6 +1266,7 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
path: &Path,
|
||||
api_name: Option<&str>,
|
||||
) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(
|
||||
&Some(FfiDescriptor(resolve_from_cwd(path)?)),
|
||||
true,
|
||||
|
@ -1088,6 +1276,7 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_partial(&mut self, path: Option<&Path>) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
let desc = match path {
|
||||
Some(path) => Some(FfiDescriptor(resolve_from_cwd(path)?)),
|
||||
None => None,
|
||||
|
@ -1098,6 +1287,7 @@ impl UnaryPermission<FfiDescriptor> {
|
|||
}
|
||||
|
||||
pub fn check_all(&mut self) -> Result<(), AnyError> {
|
||||
skip_check_if_is_permission_fully_granted!(self);
|
||||
self.check_desc(&None, false, Some("all"), || None)
|
||||
}
|
||||
}
|
||||
|
@ -1111,24 +1301,10 @@ pub struct Permissions {
|
|||
pub sys: UnaryPermission<SysDescriptor>,
|
||||
pub run: UnaryPermission<RunDescriptor>,
|
||||
pub ffi: UnaryPermission<FfiDescriptor>,
|
||||
pub all: UnitPermission,
|
||||
pub hrtime: UnitPermission,
|
||||
}
|
||||
|
||||
impl Default for Permissions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
read: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
write: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
net: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
env: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
sys: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
run: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
ffi: Permissions::new_unary(&None, &None, false).unwrap(),
|
||||
hrtime: Permissions::new_hrtime(false, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct PermissionsOptions {
|
||||
pub allow_all: bool,
|
||||
|
@ -1183,6 +1359,16 @@ impl Permissions {
|
|||
)
|
||||
}
|
||||
|
||||
pub const fn new_all(allow_state: bool) -> UnitPermission {
|
||||
unit_permission_from_flag_bools(
|
||||
allow_state,
|
||||
false,
|
||||
"all",
|
||||
"all",
|
||||
false, // never prompt for all
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from_options(opts: &PermissionsOptions) -> Result<Self, AnyError> {
|
||||
Ok(Self {
|
||||
read: Permissions::new_unary(
|
||||
|
@ -1220,10 +1406,12 @@ impl Permissions {
|
|||
&opts.deny_ffi,
|
||||
opts.prompt,
|
||||
)?,
|
||||
all: Permissions::new_all(opts.allow_all),
|
||||
hrtime: Permissions::new_hrtime(opts.allow_hrtime, opts.deny_hrtime),
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a set of permissions that explicitly allow everything.
|
||||
pub fn allow_all() -> Self {
|
||||
Self {
|
||||
read: UnaryPermission::allow_all(),
|
||||
|
@ -1233,10 +1421,35 @@ impl Permissions {
|
|||
sys: UnaryPermission::allow_all(),
|
||||
run: UnaryPermission::allow_all(),
|
||||
ffi: UnaryPermission::allow_all(),
|
||||
all: Permissions::new_all(true),
|
||||
hrtime: Permissions::new_hrtime(true, false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a set of permissions that enable nothing, but will allow prompting.
|
||||
pub fn none_with_prompt() -> Self {
|
||||
Self::none(true)
|
||||
}
|
||||
|
||||
/// Create a set of permissions that enable nothing, and will not allow prompting.
|
||||
pub fn none_without_prompt() -> Self {
|
||||
Self::none(false)
|
||||
}
|
||||
|
||||
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(),
|
||||
all: Permissions::new_all(false),
|
||||
hrtime: Permissions::new_hrtime(false, false),
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper function that determines if the module specifier is a local or
|
||||
/// remote, and performs a read or net check for the specifier.
|
||||
pub fn check_specifier(
|
||||
|
@ -1384,7 +1597,7 @@ impl PermissionsContainer {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn check_env(&mut self, var: &str) -> Result<(), AnyError> {
|
||||
self.0.lock().env.check(var)
|
||||
self.0.lock().env.check(var, None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -1798,237 +2011,35 @@ pub fn create_child_permissions(
|
|||
main_perms: &mut Permissions,
|
||||
child_permissions_arg: ChildPermissionsArg,
|
||||
) -> Result<Permissions, AnyError> {
|
||||
let mut worker_perms = Permissions::default();
|
||||
match child_permissions_arg.env {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.env = main_perms.env.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.env.check_all().is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.env.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.env.granted_list = parse_env_list(&Some(granted_list))?;
|
||||
if !worker_perms
|
||||
.env
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.env.check(desc.as_ref()).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.env.flag_denied_global = main_perms.env.flag_denied_global;
|
||||
worker_perms.env.flag_denied_list = main_perms.env.flag_denied_list.clone();
|
||||
worker_perms.env.prompt_denied_global = main_perms.env.prompt_denied_global;
|
||||
worker_perms.env.prompt_denied_list =
|
||||
main_perms.env.prompt_denied_list.clone();
|
||||
worker_perms.env.prompt = main_perms.env.prompt;
|
||||
match child_permissions_arg.sys {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.sys = main_perms.sys.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.sys.check_all().is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.sys.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.sys.granted_list = parse_sys_list(&Some(granted_list))?;
|
||||
if !worker_perms
|
||||
.sys
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.sys.check(&desc.0, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.sys.flag_denied_global = main_perms.sys.flag_denied_global;
|
||||
worker_perms.sys.flag_denied_list = main_perms.sys.flag_denied_list.clone();
|
||||
worker_perms.sys.prompt_denied_global = main_perms.sys.prompt_denied_global;
|
||||
worker_perms.sys.prompt_denied_list =
|
||||
main_perms.sys.prompt_denied_list.clone();
|
||||
worker_perms.sys.prompt = main_perms.sys.prompt;
|
||||
match child_permissions_arg.hrtime {
|
||||
ChildUnitPermissionArg::Inherit => {
|
||||
worker_perms.hrtime = main_perms.hrtime.clone();
|
||||
}
|
||||
ChildUnitPermissionArg::Granted => {
|
||||
if main_perms.hrtime.check().is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.hrtime.state = PermissionState::Granted;
|
||||
}
|
||||
ChildUnitPermissionArg::NotGranted => {}
|
||||
}
|
||||
if main_perms.hrtime.state == PermissionState::Denied {
|
||||
worker_perms.hrtime.state = PermissionState::Denied;
|
||||
}
|
||||
worker_perms.hrtime.prompt = main_perms.hrtime.prompt;
|
||||
match child_permissions_arg.net {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.net = main_perms.net.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.net.check_all().is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.net.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.net.granted_list = parse_net_list(&Some(granted_list))?;
|
||||
if !worker_perms
|
||||
.net
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.net.check(&(&desc.0, desc.1), None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.net.flag_denied_global = main_perms.net.flag_denied_global;
|
||||
worker_perms.net.flag_denied_list = main_perms.net.flag_denied_list.clone();
|
||||
worker_perms.net.prompt_denied_global = main_perms.net.prompt_denied_global;
|
||||
worker_perms.net.prompt_denied_list =
|
||||
main_perms.net.prompt_denied_list.clone();
|
||||
worker_perms.net.prompt = main_perms.net.prompt;
|
||||
match child_permissions_arg.ffi {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.ffi = main_perms.ffi.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.ffi.check_all().is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.ffi.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.ffi.granted_list = parse_path_list(
|
||||
&Some(granted_list.iter().map(PathBuf::from).collect()),
|
||||
FfiDescriptor,
|
||||
)?;
|
||||
if !worker_perms
|
||||
.ffi
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.ffi.check(&desc.0, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.ffi.flag_denied_global = main_perms.env.flag_denied_global;
|
||||
worker_perms.ffi.flag_denied_list = main_perms.ffi.flag_denied_list.clone();
|
||||
worker_perms.ffi.prompt_denied_global = main_perms.ffi.prompt_denied_global;
|
||||
worker_perms.ffi.prompt_denied_list =
|
||||
main_perms.ffi.prompt_denied_list.clone();
|
||||
worker_perms.ffi.prompt = main_perms.ffi.prompt;
|
||||
match child_permissions_arg.read {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.read = main_perms.read.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.read.check_all(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.read.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.read.granted_list = parse_path_list(
|
||||
&Some(granted_list.iter().map(PathBuf::from).collect()),
|
||||
ReadDescriptor,
|
||||
)?;
|
||||
if !worker_perms
|
||||
.read
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.read.check(&desc.0, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.read.flag_denied_global = main_perms.read.flag_denied_global;
|
||||
worker_perms.read.flag_denied_list = main_perms.read.flag_denied_list.clone();
|
||||
worker_perms.read.prompt_denied_global = main_perms.read.prompt_denied_global;
|
||||
worker_perms.read.prompt_denied_list =
|
||||
main_perms.read.prompt_denied_list.clone();
|
||||
worker_perms.read.prompt = main_perms.read.prompt;
|
||||
match child_permissions_arg.run {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.run = main_perms.run.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.run.check_all(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.run.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.run.granted_list = parse_run_list(&Some(granted_list))?;
|
||||
if !worker_perms
|
||||
.run
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.run.check(&desc.to_string(), None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.run.flag_denied_global = main_perms.run.flag_denied_global;
|
||||
worker_perms.run.flag_denied_list = main_perms.run.flag_denied_list.clone();
|
||||
worker_perms.run.prompt_denied_global = main_perms.run.prompt_denied_global;
|
||||
worker_perms.run.prompt_denied_list =
|
||||
main_perms.run.prompt_denied_list.clone();
|
||||
worker_perms.run.prompt = main_perms.run.prompt;
|
||||
match child_permissions_arg.write {
|
||||
ChildUnaryPermissionArg::Inherit => {
|
||||
worker_perms.write = main_perms.write.clone();
|
||||
}
|
||||
ChildUnaryPermissionArg::Granted => {
|
||||
if main_perms.write.check_all(None).is_err() {
|
||||
return Err(escalation_error());
|
||||
}
|
||||
worker_perms.write.granted_global = true;
|
||||
}
|
||||
ChildUnaryPermissionArg::NotGranted => {}
|
||||
ChildUnaryPermissionArg::GrantedList(granted_list) => {
|
||||
worker_perms.write.granted_list = parse_path_list(
|
||||
&Some(granted_list.iter().map(PathBuf::from).collect()),
|
||||
WriteDescriptor,
|
||||
)?;
|
||||
if !worker_perms
|
||||
.write
|
||||
.granted_list
|
||||
.iter()
|
||||
.all(|desc| main_perms.write.check(&desc.0, None).is_ok())
|
||||
{
|
||||
return Err(escalation_error());
|
||||
}
|
||||
}
|
||||
}
|
||||
worker_perms.write.flag_denied_global = main_perms.write.flag_denied_global;
|
||||
worker_perms.write.flag_denied_list =
|
||||
main_perms.write.flag_denied_list.clone();
|
||||
worker_perms.write.prompt_denied_global =
|
||||
main_perms.write.prompt_denied_global;
|
||||
worker_perms.write.prompt_denied_list =
|
||||
main_perms.write.prompt_denied_list.clone();
|
||||
worker_perms.write.prompt = main_perms.write.prompt;
|
||||
let mut worker_perms = Permissions::none_without_prompt();
|
||||
worker_perms.read = main_perms
|
||||
.read
|
||||
.create_child_permissions(child_permissions_arg.read)?;
|
||||
worker_perms.write = main_perms
|
||||
.write
|
||||
.create_child_permissions(child_permissions_arg.write)?;
|
||||
worker_perms.net = main_perms
|
||||
.net
|
||||
.create_child_permissions(child_permissions_arg.net)?;
|
||||
worker_perms.env = main_perms
|
||||
.env
|
||||
.create_child_permissions(child_permissions_arg.env)?;
|
||||
worker_perms.sys = main_perms
|
||||
.sys
|
||||
.create_child_permissions(child_permissions_arg.sys)?;
|
||||
worker_perms.run = main_perms
|
||||
.run
|
||||
.create_child_permissions(child_permissions_arg.run)?;
|
||||
worker_perms.ffi = main_perms
|
||||
.ffi
|
||||
.create_child_permissions(child_permissions_arg.ffi)?;
|
||||
worker_perms.hrtime = main_perms
|
||||
.hrtime
|
||||
.create_child_permissions(child_permissions_arg.hrtime)?;
|
||||
worker_perms.all = main_perms
|
||||
.all
|
||||
.create_child_permissions(ChildUnitPermissionArg::Inherit)?;
|
||||
|
||||
Ok(worker_perms)
|
||||
}
|
||||
|
||||
|
@ -2436,6 +2447,7 @@ mod tests {
|
|||
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),
|
||||
hrtime: Permissions::new_hrtime(false, false),
|
||||
};
|
||||
let perms3 = Permissions {
|
||||
|
@ -2463,6 +2475,7 @@ mod tests {
|
|||
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),
|
||||
hrtime: Permissions::new_hrtime(false, true),
|
||||
};
|
||||
let perms4 = Permissions {
|
||||
|
@ -2500,6 +2513,7 @@ mod tests {
|
|||
.unwrap(),
|
||||
run: Permissions::new_unary(&Some(vec![]), &Some(svec!["deno"]), false)
|
||||
.unwrap(),
|
||||
all: Permissions::new_all(false),
|
||||
hrtime: Permissions::new_hrtime(true, true),
|
||||
};
|
||||
#[rustfmt::skip]
|
||||
|
@ -2586,7 +2600,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_request() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
let mut perms: Permissions = Default::default();
|
||||
let mut perms: Permissions = Permissions::none_without_prompt();
|
||||
#[rustfmt::skip]
|
||||
{
|
||||
let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
|
||||
|
@ -2663,6 +2677,7 @@ mod tests {
|
|||
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),
|
||||
hrtime: Permissions::new_hrtime(false, true),
|
||||
};
|
||||
#[rustfmt::skip]
|
||||
|
@ -2689,17 +2704,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_check() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
let mut perms = Permissions {
|
||||
read: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
write: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
net: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
env: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
sys: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
run: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
ffi: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
hrtime: Permissions::new_hrtime(false, false),
|
||||
};
|
||||
|
||||
let mut perms = Permissions::none_with_prompt();
|
||||
let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
|
||||
|
||||
prompt_value.set(true);
|
||||
|
@ -2736,16 +2741,16 @@ mod tests {
|
|||
assert!(perms.run.check("ls", None).is_err());
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.env.check("HOME").is_ok());
|
||||
assert!(perms.env.check("HOME", None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.env.check("HOME").is_ok());
|
||||
assert!(perms.env.check("PATH").is_err());
|
||||
assert!(perms.env.check("HOME", None).is_ok());
|
||||
assert!(perms.env.check("PATH", None).is_err());
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.env.check("hostname").is_ok());
|
||||
assert!(perms.env.check("hostname", None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.env.check("hostname").is_ok());
|
||||
assert!(perms.env.check("osRelease").is_err());
|
||||
assert!(perms.env.check("hostname", None).is_ok());
|
||||
assert!(perms.env.check("osRelease", None).is_err());
|
||||
|
||||
assert!(perms.hrtime.check().is_err());
|
||||
}
|
||||
|
@ -2753,16 +2758,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_check_fail() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
let mut perms = Permissions {
|
||||
read: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
write: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
net: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
env: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
sys: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
run: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
ffi: Permissions::new_unary(&None, &None, true).unwrap(),
|
||||
hrtime: Permissions::new_hrtime(false, false),
|
||||
};
|
||||
let mut perms = Permissions::none_with_prompt();
|
||||
|
||||
let prompt_value = PERMISSION_PROMPT_STUB_VALUE_SETTER.lock();
|
||||
|
||||
|
@ -2809,12 +2805,12 @@ mod tests {
|
|||
assert!(perms.run.check("ls", None).is_ok());
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.env.check("HOME").is_err());
|
||||
assert!(perms.env.check("HOME", None).is_err());
|
||||
prompt_value.set(true);
|
||||
assert!(perms.env.check("HOME").is_err());
|
||||
assert!(perms.env.check("PATH").is_ok());
|
||||
assert!(perms.env.check("HOME", None).is_err());
|
||||
assert!(perms.env.check("PATH", None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.env.check("PATH").is_ok());
|
||||
assert!(perms.env.check("PATH", None).is_ok());
|
||||
|
||||
prompt_value.set(false);
|
||||
assert!(perms.sys.check("hostname", None).is_err());
|
||||
|
@ -2842,10 +2838,10 @@ mod tests {
|
|||
};
|
||||
|
||||
prompt_value.set(true);
|
||||
assert!(perms.env.check("HOME").is_ok());
|
||||
assert!(perms.env.check("HOME", None).is_ok());
|
||||
prompt_value.set(false);
|
||||
assert!(perms.env.check("HOME").is_ok());
|
||||
assert!(perms.env.check("hOmE").is_ok());
|
||||
assert!(perms.env.check("HOME", None).is_ok());
|
||||
assert!(perms.env.check("hOmE", None).is_ok());
|
||||
|
||||
assert_eq!(perms.env.revoke(Some("HomE")), PermissionState::Prompt);
|
||||
}
|
||||
|
@ -2865,7 +2861,7 @@ mod tests {
|
|||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
..Default::default()
|
||||
..Permissions::none_without_prompt()
|
||||
};
|
||||
|
||||
perms.read.check_partial(Path::new("/foo"), None).unwrap();
|
||||
|
@ -3038,7 +3034,7 @@ mod tests {
|
|||
hrtime: Permissions::new_hrtime(true, false),
|
||||
net: Permissions::new_unary(&Some(svec!["foo", "bar"]), &None, false)
|
||||
.unwrap(),
|
||||
..Default::default()
|
||||
..Permissions::none_without_prompt()
|
||||
};
|
||||
assert_eq!(
|
||||
create_child_permissions(
|
||||
|
@ -3055,7 +3051,7 @@ mod tests {
|
|||
Permissions {
|
||||
env: Permissions::new_unary(&Some(vec![]), &None, false).unwrap(),
|
||||
net: Permissions::new_unary(&Some(svec!["foo"]), &None, false).unwrap(),
|
||||
..Default::default()
|
||||
..Permissions::none_without_prompt()
|
||||
}
|
||||
);
|
||||
assert!(create_child_permissions(
|
||||
|
@ -3104,6 +3100,13 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
assert_eq!(main_perms, worker_perms);
|
||||
assert_eq!(
|
||||
main_perms.run.granted_list,
|
||||
HashSet::from([
|
||||
RunDescriptor::Name("bar".to_owned()),
|
||||
RunDescriptor::Name("foo".to_owned())
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -3131,14 +3134,21 @@ mod tests {
|
|||
#[test]
|
||||
fn test_handle_empty_value() {
|
||||
set_prompter(Box::new(TestPrompter));
|
||||
|
||||
assert!(Permissions::new_unary::<ReadDescriptor>(
|
||||
&Some(vec![PathBuf::new()]),
|
||||
&Some(vec![Default::default()]),
|
||||
&None,
|
||||
false
|
||||
)
|
||||
.is_err());
|
||||
assert!(Permissions::new_unary::<EnvDescriptor>(
|
||||
&Some(vec![String::new()]),
|
||||
&Some(vec![Default::default()]),
|
||||
&None,
|
||||
false
|
||||
)
|
||||
.is_err());
|
||||
assert!(Permissions::new_unary::<NetDescriptor>(
|
||||
&Some(vec![Default::default()]),
|
||||
&None,
|
||||
false
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue