summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
Diffstat (limited to 'cli')
-rw-r--r--cli/dts/lib.deno.shared_globals.d.ts56
-rw-r--r--cli/main.rs5
-rw-r--r--cli/module_loader.rs22
-rw-r--r--cli/tests/unstable_worker.ts6
-rw-r--r--cli/tests/workers/bench_worker.ts (renamed from cli/tests/subdir/bench_worker.ts)0
-rw-r--r--cli/tests/workers/busy_worker.js (renamed from cli/tests/subdir/busy_worker.js)0
-rw-r--r--cli/tests/workers/deno_worker.ts (renamed from cli/tests/subdir/deno_worker.ts)0
-rw-r--r--cli/tests/workers/event_worker.js (renamed from cli/tests/subdir/event_worker.js)0
-rw-r--r--cli/tests/workers/event_worker_scope.js (renamed from cli/tests/subdir/event_worker_scope.js)0
-rw-r--r--cli/tests/workers/fetching_worker.js (renamed from cli/tests/subdir/fetching_worker.js)2
-rw-r--r--cli/tests/workers/immediately_close_worker.js (renamed from cli/tests/immediately_close_worker.js)0
-rw-r--r--cli/tests/workers/nested_worker.js (renamed from cli/tests/subdir/nested_worker.js)0
-rw-r--r--cli/tests/workers/no_permissions_worker.js17
-rw-r--r--cli/tests/workers/non_deno_worker.js (renamed from cli/tests/subdir/non_deno_worker.js)0
-rw-r--r--cli/tests/workers/parent_read_check_granular_worker.js43
-rw-r--r--cli/tests/workers/parent_read_check_worker.js27
-rw-r--r--cli/tests/workers/racy_worker.js (renamed from cli/tests/subdir/racy_worker.js)0
-rw-r--r--cli/tests/workers/read_check_granular_worker.js13
-rw-r--r--cli/tests/workers/read_check_worker.js7
-rw-r--r--cli/tests/workers/sibling_worker.js (renamed from cli/tests/subdir/sibling_worker.js)0
-rw-r--r--cli/tests/workers/test_worker.js (renamed from cli/tests/subdir/test_worker.js)0
-rw-r--r--cli/tests/workers/test_worker.ts (renamed from cli/tests/subdir/test_worker.ts)0
-rw-r--r--cli/tests/workers/throwing_worker.js (renamed from cli/tests/subdir/throwing_worker.js)0
-rw-r--r--cli/tests/workers/worker_crypto.js (renamed from cli/tests/subdir/worker_crypto.js)0
-rw-r--r--cli/tests/workers/worker_globals.ts (renamed from cli/tests/subdir/worker_globals.ts)0
-rw-r--r--cli/tests/workers/worker_unstable.ts (renamed from cli/tests/subdir/worker_unstable.ts)0
-rw-r--r--cli/tests/workers_round_robin_bench.ts2
-rw-r--r--cli/tests/workers_startup_bench.ts2
-rw-r--r--cli/tests/workers_test.ts280
29 files changed, 440 insertions, 42 deletions
diff --git a/cli/dts/lib.deno.shared_globals.d.ts b/cli/dts/lib.deno.shared_globals.d.ts
index e4d763ec0..74abbc95b 100644
--- a/cli/dts/lib.deno.shared_globals.d.ts
+++ b/cli/dts/lib.deno.shared_globals.d.ts
@@ -662,24 +662,33 @@ declare class Worker extends EventTarget {
options?: {
type?: "classic" | "module";
name?: string;
- /** UNSTABLE: New API. Expect many changes; most likely this
- * field will be made into an object for more granular
- * configuration of worker thread (permissions, import map, etc.).
+ /** UNSTABLE: New API.
*
- * Set to `true` to make `Deno` namespace and all of its methods
- * available to worker thread.
- *
- * Currently worker inherits permissions from main thread (permissions
- * given using `--allow-*` flags).
- * Configurable permissions are on the roadmap to be implemented.
+ * Set deno.namespace to `true` to make `Deno` namespace and all of its methods
+ * available to worker thread. The namespace is disabled by default.
+ *
+ * Configure deno.permissions options to change the level of access the worker will
+ * have. By default it will inherit the permissions of its parent thread. The permissions
+ * of a worker can't be extended beyond its parent's permissions reach.
+ * - "inherit" will take the permissions of the thread the worker is created in
+ * - You can disable/enable permissions all together by passing a boolean
+ * - You can provide a list of routes relative to the file the worker
+ * is created in to limit the access of the worker (read/write permissions only)
*
* Example:
*
* ```ts
* // mod.ts
* const worker = new Worker(
- * new URL("deno_worker.ts", import.meta.url).href,
- * { type: "module", deno: true }
+ * new URL("deno_worker.ts", import.meta.url).href, {
+ * type: "module",
+ * deno: {
+ * namespace: true,
+ * permissions: {
+ * read: true,
+ * },
+ * },
+ * }
* );
* worker.postMessage({ cmd: "readFile", fileName: "./log.txt" });
*
@@ -707,7 +716,30 @@ declare class Worker extends EventTarget {
* hello world2
*
*/
- deno?: boolean;
+ // TODO(Soremwar)
+ // `deno: true` is kept for backwards compatibility with the previous worker
+ // options implementation. Remove for 2.0
+ deno?: true | {
+ namespace?: boolean;
+ /** Set to false to disable all the permissions in the worker */
+ permissions?: "inherit" | false | {
+ env?: "inherit" | boolean;
+ hrtime?: "inherit" | boolean;
+ /**
+ * The format of the net access list must be `hostname[:port]`
+ * in order to be resolved
+ *
+ * ```
+ * net: ["https://deno.land", "localhost:8080"],
+ * ```
+ * */
+ net?: "inherit" | boolean | string[];
+ plugin?: "inherit" | boolean;
+ read?: "inherit" | boolean | Array<string | URL>;
+ run?: "inherit" | boolean;
+ write?: "inherit" | boolean | Array<string | URL>;
+ };
+ };
},
);
postMessage(message: any, transfer: ArrayBuffer[]): void;
diff --git a/cli/main.rs b/cli/main.rs
index b622cccf3..a247389d9 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -100,7 +100,10 @@ fn create_web_worker_callback(
|| program_state.coverage_dir.is_some();
let maybe_inspector_server = program_state.maybe_inspector_server.clone();
- let module_loader = CliModuleLoader::new_for_worker(program_state.clone());
+ let module_loader = CliModuleLoader::new_for_worker(
+ program_state.clone(),
+ args.parent_permissions.clone(),
+ );
let create_web_worker_cb =
create_web_worker_callback(program_state.clone());
diff --git a/cli/module_loader.rs b/cli/module_loader.rs
index aab951c4a..c91a2336b 100644
--- a/cli/module_loader.rs
+++ b/cli/module_loader.rs
@@ -22,6 +22,10 @@ pub struct CliModuleLoader {
/// import map file will be resolved and set.
pub import_map: Option<ImportMap>,
pub lib: TypeLib,
+ /// The initial set of permissions used to resolve the imports in the worker.
+ /// They are decoupled from the worker permissions since read access errors
+ /// must be raised based on the parent thread permissions
+ pub initial_permissions: Rc<RefCell<Option<Permissions>>>,
pub program_state: Arc<ProgramState>,
}
@@ -38,11 +42,15 @@ impl CliModuleLoader {
Rc::new(CliModuleLoader {
import_map,
lib,
+ initial_permissions: Rc::new(RefCell::new(None)),
program_state,
})
}
- pub fn new_for_worker(program_state: Arc<ProgramState>) -> Rc<Self> {
+ pub fn new_for_worker(
+ program_state: Arc<ProgramState>,
+ permissions: Permissions,
+ ) -> Rc<Self> {
let lib = if program_state.flags.unstable {
TypeLib::UnstableDenoWorker
} else {
@@ -52,6 +60,7 @@ impl CliModuleLoader {
Rc::new(CliModuleLoader {
import_map: None,
lib,
+ initial_permissions: Rc::new(RefCell::new(Some(permissions))),
program_state,
})
}
@@ -118,7 +127,16 @@ impl ModuleLoader for CliModuleLoader {
let state = op_state.borrow();
// The permissions that should be applied to any dynamically imported module
- let dynamic_permissions = state.borrow::<Permissions>().clone();
+ let dynamic_permissions =
+ // If there are initial permissions assigned to the loader take them
+ // and use only once for top level module load.
+ // Otherwise use permissions assigned to the current worker.
+ if let Some(permissions) = self.initial_permissions.borrow_mut().take() {
+ permissions
+ } else {
+ state.borrow::<Permissions>().clone()
+ };
+
let lib = self.lib.clone();
drop(state);
diff --git a/cli/tests/unstable_worker.ts b/cli/tests/unstable_worker.ts
index 6b5304edf..429754dfe 100644
--- a/cli/tests/unstable_worker.ts
+++ b/cli/tests/unstable_worker.ts
@@ -1,8 +1,10 @@
const w = new Worker(
- new URL("subdir/worker_unstable.ts", import.meta.url).href,
+ new URL("workers/worker_unstable.ts", import.meta.url).href,
{
type: "module",
- deno: true,
+ deno: {
+ namespace: true,
+ },
name: "Unstable Worker",
},
);
diff --git a/cli/tests/subdir/bench_worker.ts b/cli/tests/workers/bench_worker.ts
index 7e85eed03..7e85eed03 100644
--- a/cli/tests/subdir/bench_worker.ts
+++ b/cli/tests/workers/bench_worker.ts
diff --git a/cli/tests/subdir/busy_worker.js b/cli/tests/workers/busy_worker.js
index 7deba0321..7deba0321 100644
--- a/cli/tests/subdir/busy_worker.js
+++ b/cli/tests/workers/busy_worker.js
diff --git a/cli/tests/subdir/deno_worker.ts b/cli/tests/workers/deno_worker.ts
index 6a57c47f0..6a57c47f0 100644
--- a/cli/tests/subdir/deno_worker.ts
+++ b/cli/tests/workers/deno_worker.ts
diff --git a/cli/tests/subdir/event_worker.js b/cli/tests/workers/event_worker.js
index 849b6026c..849b6026c 100644
--- a/cli/tests/subdir/event_worker.js
+++ b/cli/tests/workers/event_worker.js
diff --git a/cli/tests/subdir/event_worker_scope.js b/cli/tests/workers/event_worker_scope.js
index 0381801a8..0381801a8 100644
--- a/cli/tests/subdir/event_worker_scope.js
+++ b/cli/tests/workers/event_worker_scope.js
diff --git a/cli/tests/subdir/fetching_worker.js b/cli/tests/workers/fetching_worker.js
index 3e33d1c9e..e1bcdf911 100644
--- a/cli/tests/subdir/fetching_worker.js
+++ b/cli/tests/workers/fetching_worker.js
@@ -1,5 +1,5 @@
const r = await fetch(
- "http://localhost:4545/cli/tests/subdir/fetching_worker.js",
+ "http://localhost:4545/cli/tests/workers/fetching_worker.js",
);
await r.text();
postMessage("Done!");
diff --git a/cli/tests/immediately_close_worker.js b/cli/tests/workers/immediately_close_worker.js
index 8fd27343a..8fd27343a 100644
--- a/cli/tests/immediately_close_worker.js
+++ b/cli/tests/workers/immediately_close_worker.js
diff --git a/cli/tests/subdir/nested_worker.js b/cli/tests/workers/nested_worker.js
index 4b51b8763..4b51b8763 100644
--- a/cli/tests/subdir/nested_worker.js
+++ b/cli/tests/workers/nested_worker.js
diff --git a/cli/tests/workers/no_permissions_worker.js b/cli/tests/workers/no_permissions_worker.js
new file mode 100644
index 000000000..8a4f79d57
--- /dev/null
+++ b/cli/tests/workers/no_permissions_worker.js
@@ -0,0 +1,17 @@
+self.onmessage = async () => {
+ const hrtime = await Deno.permissions.query({ name: "hrtime" });
+ const net = await Deno.permissions.query({ name: "net" });
+ const plugin = await Deno.permissions.query({ name: "plugin" });
+ 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(
+ hrtime.state === "denied" &&
+ net.state === "denied" &&
+ plugin.state === "denied" &&
+ read.state === "denied" &&
+ run.state === "denied" &&
+ write.state === "denied",
+ );
+ self.close();
+};
diff --git a/cli/tests/subdir/non_deno_worker.js b/cli/tests/workers/non_deno_worker.js
index 773721560..773721560 100644
--- a/cli/tests/subdir/non_deno_worker.js
+++ b/cli/tests/workers/non_deno_worker.js
diff --git a/cli/tests/workers/parent_read_check_granular_worker.js b/cli/tests/workers/parent_read_check_granular_worker.js
new file mode 100644
index 000000000..1a7182e17
--- /dev/null
+++ b/cli/tests/workers/parent_read_check_granular_worker.js
@@ -0,0 +1,43 @@
+import { fromFileUrl } from "../../../std/path/mod.ts";
+
+const worker = new Worker(
+ new URL("./read_check_granular_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: {
+ read: [],
+ },
+ },
+ },
+);
+
+let received = 0;
+const messages = [];
+
+worker.onmessage = ({ data: childResponse }) => {
+ received++;
+ postMessage({
+ childHasPermission: childResponse.hasPermission,
+ index: childResponse.index,
+ parentHasPermission: messages[childResponse.index],
+ });
+ if (received === messages.length) {
+ worker.terminate();
+ }
+};
+
+onmessage = async ({ data }) => {
+ const { state } = await Deno.permissions.query({
+ name: "read",
+ path: fromFileUrl(new URL(data.route, import.meta.url)),
+ });
+
+ messages[data.index] = state === "granted";
+
+ worker.postMessage({
+ index: data.index,
+ route: data.route,
+ });
+};
diff --git a/cli/tests/workers/parent_read_check_worker.js b/cli/tests/workers/parent_read_check_worker.js
new file mode 100644
index 000000000..ec92cca3f
--- /dev/null
+++ b/cli/tests/workers/parent_read_check_worker.js
@@ -0,0 +1,27 @@
+onmessage = async () => {
+ const { state } = await Deno.permissions.query({
+ name: "read",
+ });
+
+ const worker = new Worker(
+ new URL("./read_check_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: {
+ read: false,
+ },
+ },
+ },
+ );
+
+ worker.onmessage = ({ data: childHasPermission }) => {
+ postMessage({
+ parentHasPermission: state === "granted",
+ childHasPermission,
+ });
+ close();
+ };
+ worker.postMessage(null);
+};
diff --git a/cli/tests/subdir/racy_worker.js b/cli/tests/workers/racy_worker.js
index 83756b791..83756b791 100644
--- a/cli/tests/subdir/racy_worker.js
+++ b/cli/tests/workers/racy_worker.js
diff --git a/cli/tests/workers/read_check_granular_worker.js b/cli/tests/workers/read_check_granular_worker.js
new file mode 100644
index 000000000..4eddb7a75
--- /dev/null
+++ b/cli/tests/workers/read_check_granular_worker.js
@@ -0,0 +1,13 @@
+import { fromFileUrl } from "../../../std/path/mod.ts";
+
+onmessage = async ({ data }) => {
+ const { state } = await Deno.permissions.query({
+ name: "read",
+ path: fromFileUrl(new URL(data.route, import.meta.url)),
+ });
+
+ postMessage({
+ hasPermission: state === "granted",
+ index: data.index,
+ });
+};
diff --git a/cli/tests/workers/read_check_worker.js b/cli/tests/workers/read_check_worker.js
new file mode 100644
index 000000000..2ad01bf5b
--- /dev/null
+++ b/cli/tests/workers/read_check_worker.js
@@ -0,0 +1,7 @@
+onmessage = async () => {
+ const { state } = await Deno.permissions.query({
+ name: "read",
+ });
+ postMessage(state === "granted");
+ close();
+};
diff --git a/cli/tests/subdir/sibling_worker.js b/cli/tests/workers/sibling_worker.js
index 99707e5d6..99707e5d6 100644
--- a/cli/tests/subdir/sibling_worker.js
+++ b/cli/tests/workers/sibling_worker.js
diff --git a/cli/tests/subdir/test_worker.js b/cli/tests/workers/test_worker.js
index 4260975a6..4260975a6 100644
--- a/cli/tests/subdir/test_worker.js
+++ b/cli/tests/workers/test_worker.js
diff --git a/cli/tests/subdir/test_worker.ts b/cli/tests/workers/test_worker.ts
index ca79dcfe4..ca79dcfe4 100644
--- a/cli/tests/subdir/test_worker.ts
+++ b/cli/tests/workers/test_worker.ts
diff --git a/cli/tests/subdir/throwing_worker.js b/cli/tests/workers/throwing_worker.js
index 56ee4ff88..56ee4ff88 100644
--- a/cli/tests/subdir/throwing_worker.js
+++ b/cli/tests/workers/throwing_worker.js
diff --git a/cli/tests/subdir/worker_crypto.js b/cli/tests/workers/worker_crypto.js
index a86340005..a86340005 100644
--- a/cli/tests/subdir/worker_crypto.js
+++ b/cli/tests/workers/worker_crypto.js
diff --git a/cli/tests/subdir/worker_globals.ts b/cli/tests/workers/worker_globals.ts
index a9e7efd85..a9e7efd85 100644
--- a/cli/tests/subdir/worker_globals.ts
+++ b/cli/tests/workers/worker_globals.ts
diff --git a/cli/tests/subdir/worker_unstable.ts b/cli/tests/workers/worker_unstable.ts
index a5b5f7ba2..a5b5f7ba2 100644
--- a/cli/tests/subdir/worker_unstable.ts
+++ b/cli/tests/workers/worker_unstable.ts
diff --git a/cli/tests/workers_round_robin_bench.ts b/cli/tests/workers_round_robin_bench.ts
index 8467480b8..461e86f91 100644
--- a/cli/tests/workers_round_robin_bench.ts
+++ b/cli/tests/workers_round_robin_bench.ts
@@ -22,7 +22,7 @@ async function main(): Promise<void> {
const workers: Array<[Map<number, Deferred<string>>, Worker]> = [];
for (let i = 1; i <= workerCount; ++i) {
const worker = new Worker(
- new URL("subdir/bench_worker.ts", import.meta.url).href,
+ new URL("workers/bench_worker.ts", import.meta.url).href,
{ type: "module" },
);
const promise = deferred();
diff --git a/cli/tests/workers_startup_bench.ts b/cli/tests/workers_startup_bench.ts
index 0d58b7912..f85bd13a1 100644
--- a/cli/tests/workers_startup_bench.ts
+++ b/cli/tests/workers_startup_bench.ts
@@ -5,7 +5,7 @@ async function bench(): Promise<void> {
const workers: Worker[] = [];
for (let i = 1; i <= workerCount; ++i) {
const worker = new Worker(
- new URL("subdir/bench_worker.ts", import.meta.url).href,
+ new URL("workers/bench_worker.ts", import.meta.url).href,
{ type: "module" },
);
const promise = new Promise<void>((resolve): void => {
diff --git a/cli/tests/workers_test.ts b/cli/tests/workers_test.ts
index 3bfe0181a..2dfc7e26b 100644
--- a/cli/tests/workers_test.ts
+++ b/cli/tests/workers_test.ts
@@ -2,12 +2,12 @@
// Requires to be run with `--allow-net` flag
-// FIXME(bartlomieju): this file is an integration test only because
-// workers are leaking ops at the moment - `worker.terminate()` is not
-// yet implemented. Once it gets implemented this file should be
-// again moved to `cli/js/` as an unit test file.
-
-import { assert, assertEquals } from "../../std/testing/asserts.ts";
+import {
+ assert,
+ assertEquals,
+ assertThrows,
+ fail,
+} from "../../std/testing/asserts.ts";
import { deferred } from "../../std/async/deferred.ts";
Deno.test({
@@ -16,11 +16,11 @@ Deno.test({
const promise = deferred();
const jsWorker = new Worker(
- new URL("subdir/test_worker.js", import.meta.url).href,
+ new URL("workers/test_worker.js", import.meta.url).href,
{ type: "module" },
);
const tsWorker = new Worker(
- new URL("subdir/test_worker.ts", import.meta.url).href,
+ new URL("workers/test_worker.ts", import.meta.url).href,
{ type: "module", name: "tsWorker" },
);
@@ -73,7 +73,7 @@ Deno.test({
const promise = deferred();
const nestedWorker = new Worker(
- new URL("subdir/nested_worker.js", import.meta.url).href,
+ new URL("workers/nested_worker.js", import.meta.url).href,
{ type: "module", name: "nested" },
);
@@ -93,7 +93,7 @@ Deno.test({
fn: async function (): Promise<void> {
const promise = deferred();
const throwingWorker = new Worker(
- new URL("subdir/throwing_worker.js", import.meta.url).href,
+ new URL("workers/throwing_worker.js", import.meta.url).href,
{ type: "module" },
);
@@ -114,7 +114,7 @@ Deno.test({
fn: async function (): Promise<void> {
const promise = deferred();
const w = new Worker(
- new URL("subdir/worker_globals.ts", import.meta.url).href,
+ new URL("workers/worker_globals.ts", import.meta.url).href,
{ type: "module" },
);
w.onmessage = (e): void => {
@@ -133,7 +133,7 @@ Deno.test({
const promise = deferred();
const fetchingWorker = new Worker(
- new URL("subdir/fetching_worker.js", import.meta.url).href,
+ new URL("workers/fetching_worker.js", import.meta.url).href,
{ type: "module" },
);
@@ -160,7 +160,7 @@ Deno.test({
const promise = deferred();
const busyWorker = new Worker(
- new URL("subdir/busy_worker.js", import.meta.url).href,
+ new URL("workers/busy_worker.js", import.meta.url).href,
{ type: "module" },
);
@@ -193,7 +193,7 @@ Deno.test({
const promise = deferred();
const racyWorker = new Worker(
- new URL("subdir/racy_worker.js", import.meta.url).href,
+ new URL("workers/racy_worker.js", import.meta.url).href,
{ type: "module" },
);
@@ -221,7 +221,7 @@ Deno.test({
const promise2 = deferred();
const worker = new Worker(
- new URL("subdir/event_worker.js", import.meta.url).href,
+ new URL("workers/event_worker.js", import.meta.url).href,
{ type: "module" },
);
@@ -265,7 +265,7 @@ Deno.test({
const promise1 = deferred();
const worker = new Worker(
- new URL("subdir/event_worker_scope.js", import.meta.url).href,
+ new URL("workers/event_worker_scope.js", import.meta.url).href,
{ type: "module" },
);
@@ -294,12 +294,18 @@ Deno.test({
const promise2 = deferred();
const regularWorker = new Worker(
- new URL("subdir/non_deno_worker.js", import.meta.url).href,
+ new URL("workers/non_deno_worker.js", import.meta.url).href,
{ type: "module" },
);
const denoWorker = new Worker(
- new URL("subdir/deno_worker.ts", import.meta.url).href,
- { type: "module", deno: true },
+ new URL("workers/deno_worker.ts", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: "inherit",
+ },
+ },
);
regularWorker.onmessage = (e): void => {
@@ -326,7 +332,7 @@ Deno.test({
fn: async function (): Promise<void> {
const promise = deferred();
const w = new Worker(
- new URL("subdir/worker_crypto.js", import.meta.url).href,
+ new URL("workers/worker_crypto.js", import.meta.url).href,
{ type: "module" },
);
w.onmessage = (e): void => {
@@ -344,7 +350,7 @@ Deno.test({
fn: async function (): Promise<void> {
const promise = deferred();
const w = new Worker(
- new URL("subdir/test_worker.ts", import.meta.url).href,
+ new URL("workers/test_worker.ts", import.meta.url).href,
{ type: "module", name: "tsWorker" },
);
const arr: number[] = [];
@@ -368,7 +374,7 @@ Deno.test({
fn: async function (): Promise<void> {
const promise = deferred();
const w = new Worker(
- new URL("./immediately_close_worker.js", import.meta.url).href,
+ new URL("./workers/immediately_close_worker.js", import.meta.url).href,
{ type: "module" },
);
setTimeout(() => {
@@ -378,3 +384,233 @@ Deno.test({
w.terminate();
},
});
+
+Deno.test("Worker inherits permissions", async function () {
+ const promise = deferred();
+ const worker = new Worker(
+ new URL("./workers/read_check_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: "inherit",
+ },
+ },
+ );
+
+ worker.onmessage = ({ data: hasPermission }) => {
+ assert(hasPermission);
+ promise.resolve();
+ };
+
+ worker.postMessage(null);
+
+ await promise;
+ worker.terminate();
+});
+
+Deno.test("Worker limit children permissions", async function () {
+ const promise = deferred();
+ const worker = new Worker(
+ new URL("./workers/read_check_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: {
+ read: false,
+ },
+ },
+ },
+ );
+
+ worker.onmessage = ({ data: hasPermission }) => {
+ assert(!hasPermission);
+ promise.resolve();
+ };
+
+ worker.postMessage(null);
+
+ await promise;
+ worker.terminate();
+});
+
+Deno.test("Worker limit children permissions granularly", async function () {
+ const promise = deferred();
+ const worker = new Worker(
+ new URL("./workers/read_check_granular_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: {
+ read: [
+ new URL("./workers/read_check_worker.js", import.meta.url),
+ ],
+ },
+ },
+ },
+ );
+
+ //Routes are relative to the spawned worker location
+ const routes = [
+ { permission: false, route: "read_check_granular_worker.js" },
+ { permission: true, route: "read_check_worker.js" },
+ ];
+
+ let checked = 0;
+ worker.onmessage = ({ data }) => {
+ checked++;
+ assertEquals(data.hasPermission, routes[data.index].permission);
+ routes.shift();
+ if (checked === routes.length) {
+ promise.resolve();
+ }
+ };
+
+ routes.forEach(({ route }, index) =>
+ worker.postMessage({
+ index,
+ route,
+ })
+ );
+
+ await promise;
+ worker.terminate();
+});
+
+Deno.test("Nested worker limit children permissions", async function () {
+ const promise = deferred();
+
+ /** This worker has read permissions but doesn't grant them to its children */
+ const worker = new Worker(
+ new URL("./workers/parent_read_check_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: "inherit",
+ },
+ },
+ );
+
+ worker.onmessage = ({ data }) => {
+ assert(data.parentHasPermission);
+ assert(!data.childHasPermission);
+ promise.resolve();
+ };
+
+ worker.postMessage(null);
+
+ await promise;
+ worker.terminate();
+});
+
+Deno.test("Nested worker limit children permissions granularly", async function () {
+ const promise = deferred();
+
+ /** This worker has read permissions but doesn't grant them to its children */
+ const worker = new Worker(
+ new URL("./workers/parent_read_check_granular_worker.js", import.meta.url)
+ .href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: {
+ read: [
+ new URL("./workers/read_check_granular_worker.js", import.meta.url),
+ ],
+ },
+ },
+ },
+ );
+
+ //Routes are relative to the spawned worker location
+ const routes = [
+ {
+ childHasPermission: false,
+ parentHasPermission: true,
+ route: "read_check_granular_worker.js",
+ },
+ {
+ childHasPermission: false,
+ parentHasPermission: false,
+ route: "read_check_worker.js",
+ },
+ ];
+
+ let checked = 0;
+ worker.onmessage = ({ data }) => {
+ checked++;
+ assertEquals(
+ data.childHasPermission,
+ routes[data.index].childHasPermission,
+ );
+ assertEquals(
+ data.parentHasPermission,
+ routes[data.index].parentHasPermission,
+ );
+ if (checked === routes.length) {
+ promise.resolve();
+ }
+ };
+
+ // Index needed cause requests will be handled asynchronously
+ routes.forEach(({ route }, index) =>
+ worker.postMessage({
+ index,
+ route,
+ })
+ );
+
+ await promise;
+ worker.terminate();
+});
+
+// This test relies on env permissions not being granted on main thread
+Deno.test("Worker initialization throws on worker permissions greater than parent thread permissions", function () {
+ assertThrows(
+ () => {
+ const worker = new Worker(
+ new URL("./workers/deno_worker.ts", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: {
+ env: true,
+ },
+ },
+ },
+ );
+ worker.terminate();
+ },
+ Deno.errors.PermissionDenied,
+ "Can't escalate parent thread permissions",
+ );
+});
+
+Deno.test("Worker with disabled permissions", async function () {
+ const promise = deferred();
+
+ const worker = new Worker(
+ new URL("./workers/no_permissions_worker.js", import.meta.url).href,
+ {
+ type: "module",
+ deno: {
+ namespace: true,
+ permissions: false,
+ },
+ },
+ );
+
+ worker.onmessage = ({ data: sandboxed }) => {
+ assert(sandboxed);
+ promise.resolve();
+ };
+
+ worker.postMessage(null);
+ await promise;
+ worker.terminate();
+});