Skip to content

Commit

Permalink
Further restrict web worker permissions
Browse files Browse the repository at this point in the history
  • Loading branch information
stwiname committed Oct 14, 2024
1 parent da6e8a0 commit 45f796a
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ export async function runApp(config: {
forceReload?: boolean;
}): Promise<void> {
const model = new Ollama({ host: config.host });
const projectPath = await loadProject(
const [projectPath, source] = await loadProject(
config.projectPath,
config.ipfs,
undefined,
config.forceReload,
);
const sandbox = await getDefaultSandbox(resolve(projectPath));
const sandbox = await getDefaultSandbox(resolve(projectPath), source);

const pendingCtx = makeContext(
sandbox,
Expand Down
8 changes: 5 additions & 3 deletions src/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import type { IProject } from "./project/project.ts";
import type { TSchema } from "@sinclair/typebox";
import type { IPFSClient } from "./ipfs.ts";
import { loadProject } from "./loader.ts";
import type { ProjectSource } from "./util.ts";

export async function getProjectJson(
projectPath: string,
source: ProjectSource,
sandboxFactory = getDefaultSandbox,
): Promise<Omit<IProject, "tools"> & { tools: string[]; config?: TSchema }> {
const sandbox = await sandboxFactory(resolve(projectPath));
const sandbox = await sandboxFactory(resolve(projectPath), source);

return {
model: sandbox.model,
Expand All @@ -26,8 +28,8 @@ export async function projectInfo(
ipfs: IPFSClient,
json = false,
): Promise<void> {
const loadedPath = await loadProject(projectPath, ipfs);
const projectJson = await getProjectJson(loadedPath);
const [loadedPath, source] = await loadProject(projectPath, ipfs);
const projectJson = await getProjectJson(loadedPath, source);

if (json) {
console.log(JSON.stringify(
Expand Down
10 changes: 5 additions & 5 deletions src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CIDReg, type IPFSClient } from "./ipfs.ts";
import { resolve } from "@std/path/resolve";
import { UntarStream } from "@std/tar";
import { ensureDir, exists } from "@std/fs";
import { getSpinner } from "./util.ts";
import { getSpinner, type ProjectSource } from "./util.ts";

export const getOSTempDir = () =>
Deno.env.get("TMPDIR") || Deno.env.get("TMP") || Deno.env.get("TEMP") ||
Expand All @@ -14,7 +14,7 @@ export async function loadProject(
ipfs: IPFSClient,
tmpDir?: string,
forceReload?: boolean,
): Promise<string> {
): Promise<[string, ProjectSource]> {
if (CIDReg.test(projectPath)) {
const spinner = getSpinner().start("Loading project from IPFS");
try {
Expand All @@ -25,7 +25,7 @@ export async function loadProject(
// Early exit if the file has already been fetched
if (!forceReload && (await exists(filePath))) {
spinner.succeed("Loaded project from IPFS");
return filePath;
return [filePath, "ipfs"];
}
await ensureDir(tmp);

Expand All @@ -36,14 +36,14 @@ export async function loadProject(

spinner.succeed("Loaded project from IPFS");

return filePath;
return [filePath, "ipfs"];
} catch (e) {
spinner.fail("Failed to load project");
throw e;
}
}

return resolve(projectPath);
return [resolve(projectPath), "local"];
}

export async function loadVectorStoragePath(
Expand Down
37 changes: 34 additions & 3 deletions src/sandbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,44 @@
import type { ProjectSource } from "../util.ts";
import type { ISandbox } from "./sandbox.ts";
import { WebWorkerSandbox } from "./webWorker/webWorkerSandbox.ts";
import {
type Permissions,
WebWorkerSandbox,
} from "./webWorker/webWorkerSandbox.ts";

export * from "./sandbox.ts";
export * from "./mockSandbox.ts";
export * from "./unsafeSandbox.ts";

export function getDefaultSandbox(path: string): Promise<ISandbox> {
const IPFS_PERMISSIONS: Permissions = {
allowRead: false,
allowFFI: false,
};

const LOCAL_PERMISSIONS: Permissions = {
allowRead: true,
allowFFI: true,
};

function getPermisionsForSource(source: ProjectSource): Permissions {
switch (source) {
case "local":
return LOCAL_PERMISSIONS;
case "ipfs":
return IPFS_PERMISSIONS;
default:
throw new Error(
`Unable to set permissions for unknown source: ${source}`,
);
}
}

export function getDefaultSandbox(
path: string,
source: ProjectSource,
): Promise<ISandbox> {
// return UnsafeSandbox.create(path);
return WebWorkerSandbox.create(path);
const permissions = getPermisionsForSource(source);
return WebWorkerSandbox.create(path, permissions);
}

export { WebWorkerSandbox };
20 changes: 16 additions & 4 deletions src/sandbox/webWorker/webWorkerSandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,36 @@ import { loadConfigFromEnv } from "../../util.ts";
import { FromSchema } from "../../fromSchema.ts";
import type { IContext } from "../../context/context.ts";
import type { IVectorConfig } from "../../project/project.ts";
import { dirname } from "@std/path/dirname";

export type Permissions = {
/**
* For local projects allow reading all locations for imports to work.
* TODO: This could be limited to the project dir + DENO_DIR cache but DENO_DIR doesn't provide the default currently
*/
allowRead?: boolean;
allowFFI?: boolean;
};

export class WebWorkerSandbox implements ISandbox {
#connection: rpc.MessageConnection;
#config: TSchema | undefined;
#tools: Tool[];

public static async create(path: string): Promise<WebWorkerSandbox> {
public static async create(
path: string,
permissions?: Permissions,
): Promise<WebWorkerSandbox> {
const w = new Worker(
import.meta.resolve("./webWorker.ts"),
{
type: "module",
deno: {
permissions: {
env: false, // Should be passed through in loadConfigFromEnv below
// hrtime: false,
net: "inherit", // TODO remove localhost
ffi: true, // Needed for node js ffi
read: true, // Needed for imports to node modules
ffi: permissions?.allowFFI ?? false, // Needed for node js ffi, TODO this could be the same as read permissions
read: permissions?.allowRead ? true : [dirname(path)],
run: false,
write: false,
},
Expand Down
3 changes: 3 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ export function getPrompt(): string | null {

return response;
}

// Possible sources where projects can be loaded from
export type ProjectSource = "local" | "ipfs";

0 comments on commit 45f796a

Please sign in to comment.