Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Daemon: Change unsafe import formula from path to specifier #2067

Merged
merged 1 commit into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/cli/src/commands/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os from 'os';
import path from 'path';
import url from 'url';

import bundleSource from '@endo/bundle-source';
import { makeReaderRef } from '@endo/daemon';
Expand Down Expand Up @@ -65,7 +66,7 @@ export const makeCommand = async ({
importPath !== undefined
? E(party).makeUnconfined(
workerName,
path.resolve(importPath),
url.pathToFileURL(path.resolve(importPath)).href,
powersName,
resultName,
)
Expand Down
4 changes: 1 addition & 3 deletions packages/daemon/src/daemon-node-powers.js
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,7 @@ export const makeDaemonicPersistencePowers = (
type: /** @type {'make-unconfined'} */ ('make-unconfined'),
worker: `worker-id512:${zero512}`,
powers: `host-id512:${zero512}`,
importPath: fileURLToPath(
new URL('web-page-bundler.js', import.meta.url).href,
),
specifier: new URL('web-page-bundler.js', import.meta.url).href,
}
: undefined;

Expand Down
8 changes: 4 additions & 4 deletions packages/daemon/src/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,13 @@ const makeEndoBootstrap = (
/**
* @param {string} workerFormulaIdentifier
* @param {string} guestFormulaIdentifier
* @param {string} importPath
* @param {string} specifier
* @param {import('./types.js').Terminator} terminator
*/
const makeControllerForUnconfinedPlugin = async (
workerFormulaIdentifier,
guestFormulaIdentifier,
importPath,
specifier,
terminator,
) => {
terminator.thisDiesIfThatDies(workerFormulaIdentifier);
Expand All @@ -279,7 +279,7 @@ const makeEndoBootstrap = (
// eslint-disable-next-line no-use-before-define
provideValueForFormulaIdentifier(guestFormulaIdentifier)
);
const external = E(workerDaemonFacet).makeUnconfined(importPath, guestP);
const external = E(workerDaemonFacet).makeUnconfined(specifier, guestP);
return { external, internal: undefined };
};

Expand Down Expand Up @@ -352,7 +352,7 @@ const makeEndoBootstrap = (
return makeControllerForUnconfinedPlugin(
formula.worker,
formula.powers,
formula.importPath,
formula.specifier,
terminator,
);
} else if (formula.type === 'make-bundle') {
Expand Down
11 changes: 3 additions & 8 deletions packages/daemon/src/host.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,10 @@ export const makeHostMaker = ({
return value;
};

/**
* @param {string | 'NEW' | 'MAIN'} workerName
* @param {string} importPath
* @param {string | 'NONE' | 'SELF' | 'ENDO'} powersName
* @param {string} resultName
*/
/** @type {import('./types.js').EndoHost['makeUnconfined']} */
const makeUnconfined = async (
workerName,
importPath,
specifier,
powersName,
resultName,
) => {
Expand All @@ -318,7 +313,7 @@ export const makeHostMaker = ({
type: 'make-unconfined',
worker: workerFormulaIdentifier,
powers: powersFormulaIdentifier,
importPath,
specifier,
};

// Behold, recursion:
Expand Down
9 changes: 4 additions & 5 deletions packages/daemon/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export type HttpConnect = (
) => void;

export type MignonicPowers = {
pathToFileURL: (path: string) => string;
connection: {
reader: Reader<Uint8Array>;
writer: Writer<Uint8Array>;
Expand Down Expand Up @@ -91,7 +90,7 @@ type MakeUnconfinedFormula = {
type: 'make-unconfined';
worker: string;
powers: string;
importPath: string;
specifier: string;
// TODO formula slots
};

Expand Down Expand Up @@ -260,9 +259,9 @@ export interface EndoHost {
resultName?: string,
);
makeUnconfined(
workerPetName: string | undefined,
importPath: string,
powersName: string,
workerName: string | 'NEW' | 'MAIN',
specifier: string,
powersName: string | 'NONE' | 'SELF' | 'ENDO',
resultName?: string,
): Promise<unknown>;
makeBundle(
Expand Down
32 changes: 23 additions & 9 deletions packages/daemon/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,30 @@ const endowments = harden({
URL,
});

const normalizeFilePath = path => {
// Check if the path is already a file URL.
if (path.startsWith('file://')) {
return path;
}
// Windows path detection and conversion (look for a drive letter at the start).
const isWindowsPath = /^[a-zA-Z]:/.test(path);
if (isWindowsPath) {
Comment on lines +23 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably replace this with os.platform instead.

// Correctly format the Windows path with three slashes.
return `file:///${path}`;
}
// For non-Windows paths, prepend the file protocol.
return `file://${path}`;
};

/**
* @typedef {ReturnType<makeWorkerFacet>} WorkerBootstrap
*/

/**
* @param {object} args
* @param {(error: Error) => void} args.cancel
* @param {(path: string) => string} args.pathToFileURL
*/
export const makeWorkerFacet = ({ pathToFileURL, cancel }) => {
export const makeWorkerFacet = ({ cancel }) => {
return Far('EndoWorkerFacet', {
terminate: async () => {
console.error('Endo worker received terminate request');
Expand All @@ -50,12 +64,15 @@ export const makeWorkerFacet = ({ pathToFileURL, cancel }) => {
},

/**
* @param {string} path
* @param {string} specifier
* @param {unknown} powersP
*/
makeUnconfined: async (path, powersP) => {
const url = pathToFileURL(path);
const namespace = await import(url);
makeUnconfined: async (specifier, powersP) => {
// Windows absolute path includes drive letter which is confused for
// protocol specifier. So, we reformat the specifier to include the
// file protocol.
const specifierUrl = normalizeFilePath(specifier);
const namespace = await import(specifierUrl);
return namespace.make(powersP);
},

Expand Down Expand Up @@ -92,12 +109,9 @@ export const main = async (powers, locator, uuid, pid, cancel, cancelled) => {
console.error(`Endo worker exiting on pid ${pid}`);
});

const { pathToFileURL } = powers;

const { reader, writer } = powers.connection;

const workerFacet = makeWorkerFacet({
pathToFileURL,
cancel,
});

Expand Down
12 changes: 8 additions & 4 deletions packages/daemon/test/test-endo.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ test('persist unconfined services and their requests', async t => {
await E(host).makeWorker('w1');
await E(host).provideGuest('o1');
const servicePath = path.join(dirname, 'test', 'service.js');
await E(host).makeUnconfined('w1', servicePath, 'o1', 's1');
const serviceLocation = url.pathToFileURL(servicePath).href;
await E(host).makeUnconfined('w1', serviceLocation, 'o1', 's1');

await E(host).makeWorker('w2');
const answer = await E(host).evaluate(
Expand Down Expand Up @@ -579,7 +580,8 @@ test('direct termination', async t => {
await E(host).provideWorker('worker');

const counterPath = path.join(dirname, 'test', 'counter.js');
await E(host).makeUnconfined('worker', counterPath, 'NONE', 'counter');
const counterLocation = url.pathToFileURL(counterPath).href;
await E(host).makeUnconfined('worker', counterLocation, 'NONE', 'counter');
t.is(
1,
await E(host).evaluate(
Expand Down Expand Up @@ -659,7 +661,8 @@ test('indirect termination', async t => {
await E(host).provideWorker('worker');

const counterPath = path.join(dirname, 'test', 'counter.js');
await E(host).makeUnconfined('worker', counterPath, 'SELF', 'counter');
const counterLocation = url.pathToFileURL(counterPath).href;
await E(host).makeUnconfined('worker', counterLocation, 'SELF', 'counter');
t.is(
1,
await E(host).evaluate(
Expand Down Expand Up @@ -741,7 +744,8 @@ test('terminate because of requested capability', async t => {
const messages = E(host).followMessages();

const counterPath = path.join(dirname, 'test', 'counter-party.js');
E(host).makeUnconfined('worker', counterPath, 'guest', 'counter');
const counterLocation = url.pathToFileURL(counterPath).href;
E(host).makeUnconfined('worker', counterLocation, 'guest', 'counter');

await E(host).evaluate('worker', '0', [], [], 'zero');
await E(messages).next();
Expand Down
Loading