diff --git a/cli/tests/testdata/bench/allow_all.ts b/cli/tests/testdata/bench/allow_all.ts index 110e4621fe..d7dde3a855 100644 --- a/cli/tests/testdata/bench/allow_all.ts +++ b/cli/tests/testdata/bench/allow_all.ts @@ -17,8 +17,10 @@ for (const name of permissions) { [name]: false, }, async fn() { - const status = await Deno.permissions.query({ name }); - assertEquals(status.state, "prompt"); + for await (const n of permissions) { + const status = await Deno.permissions.query({ name: n }); + assertEquals(status.state, "prompt"); + } }, }); @@ -28,8 +30,14 @@ for (const name of permissions) { [name]: true, }, async fn() { - const status = await Deno.permissions.query({ name }); - assertEquals(status.state, "granted"); + for await (const n of permissions) { + const status = await Deno.permissions.query({ name: n }); + if (n === name) { + assertEquals(status.state, "granted"); + } else { + assertEquals(status.state, "prompt"); + } + } }, }); } diff --git a/cli/tests/testdata/test/allow_all.ts b/cli/tests/testdata/test/allow_all.ts index e70ac46b02..c7a2381300 100644 --- a/cli/tests/testdata/test/allow_all.ts +++ b/cli/tests/testdata/test/allow_all.ts @@ -17,8 +17,10 @@ for (const name of permissions) { [name]: false, }, async fn() { - const status = await Deno.permissions.query({ name }); - assertEquals(status.state, "prompt"); + for await (const n of permissions) { + const status = await Deno.permissions.query({ name: n }); + assertEquals(status.state, "prompt"); + } }, }); @@ -28,8 +30,14 @@ for (const name of permissions) { [name]: true, }, async fn() { - const status = await Deno.permissions.query({ name }); - assertEquals(status.state, "granted"); + for await (const n of permissions) { + const status = await Deno.permissions.query({ name: n }); + if (n === name) { + assertEquals(status.state, "granted"); + } else { + assertEquals(status.state, "prompt"); + } + } }, }); } diff --git a/cli/tests/testdata/workers/permission_echo.js b/cli/tests/testdata/workers/permission_echo.js new file mode 100644 index 0000000000..f492a25f26 --- /dev/null +++ b/cli/tests/testdata/workers/permission_echo.js @@ -0,0 +1,19 @@ +self.onmessage = async () => { + const env = await Deno.permissions.query({ name: "env" }); + const ffi = await Deno.permissions.query({ name: "ffi" }); + const hrtime = await Deno.permissions.query({ name: "hrtime" }); + const net = await Deno.permissions.query({ name: "net" }); + const read = await Deno.permissions.query({ name: "read" }); + const run = await Deno.permissions.query({ name: "run" }); + const write = await Deno.permissions.query({ name: "write" }); + self.postMessage({ + env: env.state, + ffi: ffi.state, + hrtime: hrtime.state, + net: net.state, + read: read.state, + run: run.state, + write: write.state, + }); + self.close(); +}; diff --git a/cli/tests/testdata/workers/test.ts b/cli/tests/testdata/workers/test.ts index b9204adee3..d75ca499bd 100644 --- a/cli/tests/testdata/workers/test.ts +++ b/cli/tests/testdata/workers/test.ts @@ -584,6 +584,68 @@ Deno.test("Worker with disabled permissions", async function () { worker.terminate(); }); +Deno.test("Worker permissions are not inherited with empty permission object", async function () { + const worker = new Worker( + new URL("./permission_echo.js", import.meta.url).href, + { + type: "module", + deno: { + namespace: true, + permissions: {}, + }, + }, + ); + + const promise = deferred(); + worker.onmessage = (e) => { + promise.resolve(e.data); + }; + + worker.postMessage(null); + assertEquals(await promise, { + env: "prompt", + hrtime: "prompt", + net: "prompt", + ffi: "prompt", + read: "prompt", + run: "prompt", + write: "prompt", + }); + worker.terminate(); +}); + +Deno.test("Worker permissions are not inherited with single specified permission", async function () { + const worker = new Worker( + new URL("./permission_echo.js", import.meta.url).href, + { + type: "module", + deno: { + namespace: true, + permissions: { + net: true, + }, + }, + }, + ); + + const promise = deferred(); + worker.onmessage = (e) => { + promise.resolve(e.data); + }; + + worker.postMessage(null); + assertEquals(await promise, { + env: "prompt", + hrtime: "prompt", + net: "granted", + ffi: "prompt", + read: "prompt", + run: "prompt", + write: "prompt", + }); + worker.terminate(); +}); + Deno.test("Worker with invalid permission arg", function () { assertThrows( () => diff --git a/cli/tests/unit/http_test.ts b/cli/tests/unit/http_test.ts index e8976c06dd..83fa6116c7 100644 --- a/cli/tests/unit/http_test.ts +++ b/cli/tests/unit/http_test.ts @@ -1180,7 +1180,7 @@ const decoder = new TextDecoder(); Deno.test({ name: "http server compresses body", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1231,7 +1231,7 @@ Deno.test({ Deno.test({ name: "http server doesn't compress small body", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1282,7 +1282,7 @@ Deno.test({ Deno.test({ name: "http server respects accept-encoding weights", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1336,7 +1336,7 @@ Deno.test({ Deno.test({ name: "http server augments vary header", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1387,7 +1387,7 @@ Deno.test({ Deno.test({ name: "http server weakens etag header", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1444,7 +1444,7 @@ Deno.test({ Deno.test({ name: "http server passes through weak etag header", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1501,7 +1501,7 @@ Deno.test({ Deno.test({ name: "http server doesn't compress body when no-transform is set", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1555,7 +1555,7 @@ Deno.test({ Deno.test({ name: "http server doesn't compress body when content-range is set", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1609,7 +1609,7 @@ Deno.test({ Deno.test({ name: "http server doesn't compress streamed bodies", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; @@ -1675,7 +1675,7 @@ Deno.test({ Deno.test({ name: "http server updates content-length header if compression is applied", - permissions: { net: true }, + permissions: { net: true, run: true }, async fn() { const hostname = "localhost"; const port = 4501; diff --git a/cli/tests/unit/net_test.ts b/cli/tests/unit/net_test.ts index 29e823b104..6769f6301a 100644 --- a/cli/tests/unit/net_test.ts +++ b/cli/tests/unit/net_test.ts @@ -380,7 +380,7 @@ Deno.test( ); Deno.test( - { permissions: { net: true } }, + { permissions: { net: true }, ignore: true }, async function netUdpSendReceiveBroadcast() { // Must bind sender to an address that can send to the broadcast address on MacOS. // Macos will give us error 49 when sending the broadcast packet if we omit hostname here. diff --git a/cli/tests/unit/timers_test.ts b/cli/tests/unit/timers_test.ts index 5b9e1fa482..ef7dc9eef3 100644 --- a/cli/tests/unit/timers_test.ts +++ b/cli/tests/unit/timers_test.ts @@ -579,7 +579,7 @@ Deno.test( Deno.test({ name: "unrefTimer", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const timer = setTimeout(() => console.log("1")); @@ -592,7 +592,7 @@ Deno.test({ Deno.test({ name: "unrefTimer - mix ref and unref 1", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const timer1 = setTimeout(() => console.log("1"), 200); @@ -607,7 +607,7 @@ Deno.test({ Deno.test({ name: "unrefTimer - mix ref and unref 2", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const timer1 = setTimeout(() => console.log("1"), 200); @@ -623,7 +623,7 @@ Deno.test({ Deno.test({ name: "unrefTimer - unref interval", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` let i = 0; @@ -642,7 +642,7 @@ Deno.test({ Deno.test({ name: "unrefTimer - unref then ref 1", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const timer1 = setTimeout(() => console.log("1"), 10); @@ -656,7 +656,7 @@ Deno.test({ Deno.test({ name: "unrefTimer - unref then ref", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const timer1 = setTimeout(() => { @@ -673,7 +673,6 @@ Deno.test({ Deno.test({ name: "unrefTimer - invalid calls do nothing", - permissions: { run: true }, fn: () => { Deno.unrefTimer(NaN); Deno.refTimer(NaN); @@ -682,7 +681,7 @@ Deno.test({ Deno.test({ name: "AbortSignal.timeout() with no listeners", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const signal = AbortSignal.timeout(2000); @@ -699,7 +698,7 @@ Deno.test({ Deno.test({ name: "AbortSignal.timeout() with listeners", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const signal = AbortSignal.timeout(1000); @@ -712,7 +711,7 @@ Deno.test({ Deno.test({ name: "AbortSignal.timeout() with removed listeners", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const signal = AbortSignal.timeout(2000); @@ -736,7 +735,7 @@ Deno.test({ Deno.test({ name: "AbortSignal.timeout() with listener for a non-abort event", - permissions: { run: true }, + permissions: { run: true, read: true }, fn: async () => { const [statusCode, output] = await execCode(` const signal = AbortSignal.timeout(2000); diff --git a/cli/tests/unit/tty_color_test.ts b/cli/tests/unit/tty_color_test.ts index d64c278bf2..c10c9ff1ef 100644 --- a/cli/tests/unit/tty_color_test.ts +++ b/cli/tests/unit/tty_color_test.ts @@ -3,12 +3,15 @@ import { assertEquals } from "./test_util.ts"; // Note tests for Deno.setRaw is in integration tests. -Deno.test({ permissions: { run: true } }, async function noColorIfNotTty() { - const p = Deno.run({ - cmd: [Deno.execPath(), "eval", "console.log(1)"], - stdout: "piped", - }); - const output = new TextDecoder().decode(await p.output()); - assertEquals(output, "1\n"); - p.close(); -}); +Deno.test( + { permissions: { run: true, read: true } }, + async function noColorIfNotTty() { + const p = Deno.run({ + cmd: [Deno.execPath(), "eval", "console.log(1)"], + stdout: "piped", + }); + const output = new TextDecoder().decode(await p.output()); + assertEquals(output, "1\n"); + p.close(); + }, +); diff --git a/runtime/permissions.rs b/runtime/permissions.rs index 707c9647ef..095e67467c 100644 --- a/runtime/permissions.rs +++ b/runtime/permissions.rs @@ -1432,12 +1432,6 @@ pub enum ChildUnitPermissionArg { NotGranted, } -impl Default for ChildUnitPermissionArg { - fn default() -> Self { - ChildUnitPermissionArg::Inherit - } -} - impl<'de> Deserialize<'de> for ChildUnitPermissionArg { fn deserialize(deserializer: D) -> Result where @@ -1491,12 +1485,6 @@ pub enum ChildUnaryPermissionArg { GrantedList(Vec), } -impl Default for ChildUnaryPermissionArg { - fn default() -> Self { - ChildUnaryPermissionArg::Inherit - } -} - impl<'de> Deserialize<'de> for ChildUnaryPermissionArg { fn deserialize(deserializer: D) -> Result where @@ -1557,7 +1545,7 @@ impl<'de> Deserialize<'de> for ChildUnaryPermissionArg { } /// Directly deserializable from JS worker and test permission options. -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, PartialEq)] pub struct ChildPermissionsArg { env: ChildUnaryPermissionArg, hrtime: ChildUnitPermissionArg, @@ -1568,6 +1556,32 @@ pub struct ChildPermissionsArg { write: ChildUnaryPermissionArg, } +impl ChildPermissionsArg { + pub fn inherit() -> Self { + ChildPermissionsArg { + env: ChildUnaryPermissionArg::Inherit, + hrtime: ChildUnitPermissionArg::Inherit, + net: ChildUnaryPermissionArg::Inherit, + ffi: ChildUnaryPermissionArg::Inherit, + read: ChildUnaryPermissionArg::Inherit, + run: ChildUnaryPermissionArg::Inherit, + write: ChildUnaryPermissionArg::Inherit, + } + } + + pub fn none() -> Self { + ChildPermissionsArg { + env: ChildUnaryPermissionArg::NotGranted, + hrtime: ChildUnitPermissionArg::NotGranted, + net: ChildUnaryPermissionArg::NotGranted, + ffi: ChildUnaryPermissionArg::NotGranted, + read: ChildUnaryPermissionArg::NotGranted, + run: ChildUnaryPermissionArg::NotGranted, + write: ChildUnaryPermissionArg::NotGranted, + } + } +} + impl<'de> Deserialize<'de> for ChildPermissionsArg { fn deserialize(deserializer: D) -> Result where @@ -1585,7 +1599,7 @@ impl<'de> Deserialize<'de> for ChildPermissionsArg { where E: de::Error, { - Ok(ChildPermissionsArg::default()) + Ok(ChildPermissionsArg::inherit()) } fn visit_str(self, v: &str) -> Result @@ -1593,17 +1607,9 @@ impl<'de> Deserialize<'de> for ChildPermissionsArg { E: de::Error, { if v == "inherit" { - Ok(ChildPermissionsArg::default()) + Ok(ChildPermissionsArg::inherit()) } else if v == "none" { - Ok(ChildPermissionsArg { - env: ChildUnaryPermissionArg::NotGranted, - hrtime: ChildUnitPermissionArg::NotGranted, - net: ChildUnaryPermissionArg::NotGranted, - ffi: ChildUnaryPermissionArg::NotGranted, - read: ChildUnaryPermissionArg::NotGranted, - run: ChildUnaryPermissionArg::NotGranted, - write: ChildUnaryPermissionArg::NotGranted, - }) + Ok(ChildPermissionsArg::none()) } else { Err(de::Error::invalid_value(de::Unexpected::Str(v), &self)) } @@ -1613,7 +1619,7 @@ impl<'de> Deserialize<'de> for ChildPermissionsArg { where V: de::MapAccess<'de>, { - let mut child_permissions_arg = ChildPermissionsArg::default(); + let mut child_permissions_arg = ChildPermissionsArg::none(); while let Some((key, value)) = v.next_entry::()? { @@ -2647,7 +2653,7 @@ mod tests { #[test] fn test_deserialize_child_permissions_arg() { assert_eq!( - ChildPermissionsArg::default(), + ChildPermissionsArg::inherit(), ChildPermissionsArg { env: ChildUnaryPermissionArg::Inherit, hrtime: ChildUnitPermissionArg::Inherit, @@ -2659,11 +2665,7 @@ mod tests { } ); assert_eq!( - serde_json::from_value::(json!("inherit")).unwrap(), - ChildPermissionsArg::default() - ); - assert_eq!( - serde_json::from_value::(json!("none")).unwrap(), + ChildPermissionsArg::none(), ChildPermissionsArg { env: ChildUnaryPermissionArg::NotGranted, hrtime: ChildUnitPermissionArg::NotGranted, @@ -2674,9 +2676,17 @@ mod tests { write: ChildUnaryPermissionArg::NotGranted, } ); + assert_eq!( + serde_json::from_value::(json!("inherit")).unwrap(), + ChildPermissionsArg::inherit() + ); + assert_eq!( + serde_json::from_value::(json!("none")).unwrap(), + ChildPermissionsArg::none() + ); assert_eq!( serde_json::from_value::(json!({})).unwrap(), - ChildPermissionsArg::default() + ChildPermissionsArg::none() ); assert_eq!( serde_json::from_value::(json!({ @@ -2685,7 +2695,7 @@ mod tests { .unwrap(), ChildPermissionsArg { env: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]), - ..Default::default() + ..ChildPermissionsArg::none() } ); assert_eq!( @@ -2695,7 +2705,7 @@ mod tests { .unwrap(), ChildPermissionsArg { hrtime: ChildUnitPermissionArg::Granted, - ..Default::default() + ..ChildPermissionsArg::none() } ); assert_eq!( @@ -2705,7 +2715,7 @@ mod tests { .unwrap(), ChildPermissionsArg { hrtime: ChildUnitPermissionArg::NotGranted, - ..Default::default() + ..ChildPermissionsArg::none() } ); assert_eq!( @@ -2725,7 +2735,7 @@ mod tests { read: ChildUnaryPermissionArg::Granted, run: ChildUnaryPermissionArg::Granted, write: ChildUnaryPermissionArg::Granted, - ..Default::default() + ..ChildPermissionsArg::none() } ); assert_eq!( @@ -2745,7 +2755,7 @@ mod tests { read: ChildUnaryPermissionArg::NotGranted, run: ChildUnaryPermissionArg::NotGranted, write: ChildUnaryPermissionArg::NotGranted, - ..Default::default() + ..ChildPermissionsArg::none() } ); assert_eq!( @@ -2778,7 +2788,7 @@ mod tests { "foo", "file:///bar/baz" ]), - ..Default::default() + ..ChildPermissionsArg::none() } ); } @@ -2799,7 +2809,7 @@ mod tests { hrtime: ChildUnitPermissionArg::NotGranted, net: ChildUnaryPermissionArg::GrantedList(svec!["foo"]), ffi: ChildUnaryPermissionArg::NotGranted, - ..Default::default() + ..ChildPermissionsArg::none() } ) .unwrap(), @@ -2813,7 +2823,7 @@ mod tests { &mut main_perms.clone(), ChildPermissionsArg { net: ChildUnaryPermissionArg::Granted, - ..Default::default() + ..ChildPermissionsArg::none() } ) .is_err()); @@ -2821,7 +2831,7 @@ mod tests { &mut main_perms.clone(), ChildPermissionsArg { net: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar", "baz"]), - ..Default::default() + ..ChildPermissionsArg::none() } ) .is_err()); @@ -2829,7 +2839,7 @@ mod tests { &mut main_perms, ChildPermissionsArg { ffi: ChildUnaryPermissionArg::GrantedList(svec!["foo"]), - ..Default::default() + ..ChildPermissionsArg::none() } ) .is_err()); @@ -2848,7 +2858,7 @@ mod tests { ChildPermissionsArg { read: ChildUnaryPermissionArg::Granted, run: ChildUnaryPermissionArg::GrantedList(svec!["foo", "bar"]), - ..Default::default() + ..ChildPermissionsArg::none() }, ) .unwrap(); @@ -2866,7 +2876,7 @@ mod tests { assert!(main_perms.write.check(&PathBuf::from("foo")).is_err()); let worker_perms = create_child_permissions( &mut main_perms.clone(), - ChildPermissionsArg::default(), + ChildPermissionsArg::none(), ) .unwrap(); assert_eq!(worker_perms.write.denied_list, main_perms.write.denied_list);