Skip to content

Latest commit

 

History

History
137 lines (113 loc) · 3.43 KB

File metadata and controls

137 lines (113 loc) · 3.43 KB
title Permissions
description Control what sandboxed code can access on the host.
icon lock
Runnable example for permission configuration.

All host capabilities are deny-by-default. Sandboxed code cannot access the filesystem, network, child processes, or environment variables unless you explicitly allow it.

Runnable example

import {
	NodeRuntime,
	createInMemoryFileSystem,
	createNodeDriver,
	createNodeRuntimeDriverFactory,
} from "../../../packages/secure-exec/src/index.ts";

const filesystem = createInMemoryFileSystem();
await filesystem.writeFile("/secret.txt", "top secret");
const runtime = new NodeRuntime({
	systemDriver: createNodeDriver({
		filesystem,
		permissions: {
			fs: (request) => ({ allow: request.path.startsWith("/workspace") }),
		},
	}),
	runtimeDriverFactory: createNodeRuntimeDriverFactory(),
});

const result = await runtime.run<{
	message: string;
	blocked: boolean;
}>(
	`
  const fs = require("node:fs");

  fs.mkdirSync("/workspace", { recursive: true });
  fs.writeFileSync("/workspace/message.txt", "hello from permissions");

  let blocked = false;
  try {
    fs.readFileSync("/secret.txt", "utf8");
  } catch (error) {
    blocked = error && error.code === "EACCES";
  }

  module.exports = {
    message: fs.readFileSync("/workspace/message.txt", "utf8"),
    blocked,
  };
`,
);

console.log(
	JSON.stringify({
		ok:
			result.code === 0 &&
			result.exports?.message === "hello from permissions" &&
			result.exports?.blocked === true,
		message: result.exports?.message,
		blocked: result.exports?.blocked,
		summary: "filesystem access was allowed for /workspace and denied for /secret.txt",
	}),
);

Source: examples/features/src/permissions.ts

Permission helpers

Quick presets for common configurations:

import {
  createNodeDriver,
  allowAll,
  allowAllFs,
  allowAllNetwork,
} from "secure-exec";

// Allow everything
const driver = createNodeDriver({ permissions: allowAll });

// Allow only filesystem and network
const selective = createNodeDriver({
  permissions: {
    ...allowAllFs,
    ...allowAllNetwork,
  },
});
Export Allows
allowAll All operations across all domains
allowAllFs All filesystem reads and writes
allowAllNetwork All network requests and DNS lookups
allowAllChildProcess All child process spawning
allowAllEnv All environment variable access

Function-based checks

Each permission field accepts a function that inspects the request and returns a decision:

const driver = createNodeDriver({
  permissions: {
    fs: (req) => ({ allow: req.op === "read" }),
    network: (req) => ({ allow: !req.hostname?.endsWith(".internal") }),
    childProcess: (req) => ({ allow: ["node", "python3"].includes(req.command) }),
    env: (req) => ({ allow: ["PATH", "HOME"].includes(req.key) }),
  },
});

Permissions type

type PermissionDecision = {
  allow: boolean;
  reason?: string;
};

type PermissionCheck<T> = (request: T) => PermissionDecision;

type Permissions = {
  fs?: PermissionCheck<FsAccessRequest>;
  network?: PermissionCheck<NetworkAccessRequest>;
  childProcess?: PermissionCheck<ChildProcessAccessRequest>;
  env?: PermissionCheck<EnvAccessRequest>;
};