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

sham non-trapping shim and ponyfill for cross-repo testing #2683

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
16 changes: 14 additions & 2 deletions packages/captp/src/trap.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Lifted mostly from `@endo/eventual-send/src/E.js`.

const { freeze } = Object;

/**
* Default implementation of Trap for near objects.
*
@@ -62,11 +64,21 @@ const TrapProxyHandler = (x, trapImpl) => {
*/
export const makeTrap = trapImpl => {
const Trap = x => {
/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const target = freeze(() => {});
const handler = TrapProxyHandler(x, trapImpl);
return harden(new Proxy(() => {}, handler));
return new Proxy(target, handler);
};

const makeTrapGetterProxy = x => {
/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const target = freeze(Object.create(null));
const handler = harden({
...baseFreezableProxyHandler,
has(_target, _prop) {
@@ -77,7 +89,7 @@ export const makeTrap = trapImpl => {
return trapImpl.get(x, prop);
},
});
return new Proxy(Object.create(null), handler);
return new Proxy(target, handler);
};
Trap.get = makeTrapGetterProxy;

47 changes: 37 additions & 10 deletions packages/eventual-send/src/E.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { trackTurns } from './track-turns.js';
import { makeMessageBreakpointTester } from './message-breakpoints.js';

const { details: X, quote: q, Fail, error: makeError } = assert;
const { assign, create } = Object;
const { assign, create, freeze } = Object;

/**
* @import { HandledPromiseConstructor } from './types.js';
@@ -167,6 +167,38 @@ const makeEGetProxyHandler = (x, HandledPromise) =>
get: (_target, prop) => HandledPromise.get(x, prop),
});

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* This is safe to share between proxy instances because they are encapsulated
* within the proxy.
* - Before stabilize/suppressTrapping, this is safe
* because they are already frozen, and so they cannot be damaged by the
* proxies that encapsulate them.
* - After stabilize/suppressTrapping, this is safe because the only damage
* that could be done would be by stabilize/suppressTrapping. These proxies
* do not explicitly provide such a trap, and thus will use the default
* behavior which is to refuse to be made non-trapping.
*
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const funcTarget = freeze(() => {});

/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* This is safe to share between proxy instances because they are encapsulated
* within the proxy.
* - Before stabilize/suppressTrapping, this is safe
* because they are already frozen, and so they cannot be damaged by the
* proxies that encapsulate them.
* - After stabilize/suppressTrapping, this is safe because the only damage
* that could be done would be by stabilize/suppressTrapping. These proxies
* do not explicitly provide such a trap, and thus will use the default
* behavior which is to refuse to be made non-trapping.
*
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const objTarget = freeze(create(null));

/**
* @param {HandledPromiseConstructor} HandledPromise
*/
@@ -183,7 +215,7 @@ const makeE = HandledPromise => {
* @returns {ECallableOrMethods<RemoteFunctions<T>>} method/function call proxy
*/
// @ts-expect-error XXX typedef
x => harden(new Proxy(() => {}, makeEProxyHandler(x, HandledPromise))),
x => new Proxy(funcTarget, makeEProxyHandler(x, HandledPromise)),
{
/**
* E.get(x) returns a proxy on which you can get arbitrary properties.
@@ -196,11 +228,8 @@ const makeE = HandledPromise => {
* @returns {EGetters<LocalRecord<T>>} property get proxy
* @readonly
*/
get: x =>
// @ts-expect-error XXX typedef
harden(
new Proxy(create(null), makeEGetProxyHandler(x, HandledPromise)),
),
// @ts-expect-error XXX typedef
get: x => new Proxy(objTarget, makeEGetProxyHandler(x, HandledPromise)),

/**
* E.resolve(x) converts x to a handled promise. It is
@@ -224,9 +253,7 @@ const makeE = HandledPromise => {
*/
sendOnly: x =>
// @ts-expect-error XXX typedef
harden(
new Proxy(() => {}, makeESendOnlyProxyHandler(x, HandledPromise)),
),
new Proxy(funcTarget, makeESendOnlyProxyHandler(x, HandledPromise)),

/**
* E.when(x, res, rej) is equivalent to
3 changes: 3 additions & 0 deletions packages/eventual-send/src/handled-promise.js
Original file line number Diff line number Diff line change
@@ -309,6 +309,9 @@ export const makeHandledPromise = () => {
if (proxyOpts) {
const {
handler: proxyHandler,
// The proxy target can be frozen but should not be hardened
// so it remains trapping.
// See https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
target: proxyTarget,
revokerCallback,
} = proxyOpts;
2 changes: 1 addition & 1 deletion packages/far/test/marshal-far-function.test.js
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ test('Data can contain far functions', t => {
const arrow = Far('arrow', a => a + 1);
t.is(passStyleOf(harden({ x: 8, foo: arrow })), 'copyRecord');
const mightBeMethod = a => a + 1;
t.throws(() => passStyleOf(freeze({ x: 8, foo: mightBeMethod })), {
t.throws(() => passStyleOf(harden({ x: 8, foo: mightBeMethod })), {
message: /Remotables with non-methods like "x" /,
});
});
2 changes: 2 additions & 0 deletions packages/marshal/src/encodeToCapData.js
Original file line number Diff line number Diff line change
@@ -187,6 +187,8 @@ export const makeEncodeToCapData = (encodeOptions = {}) => {
// work. If we allow sortable symbol keys, this will need to
// become more interesting.
const names = ownKeys(passable).sort();
// TODO either delete or at-ts-expect-error
// @ts-ignore
return fromEntries(
names.map(name => [name, encodeToCapDataRecur(passable[name])]),
);
14 changes: 12 additions & 2 deletions packages/marshal/src/marshal-stringify.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@ import { makeMarshal } from './marshal.js';

/** @import {Passable} from '@endo/pass-style' */

const { freeze } = Object;

/** @type {import('./types.js').ConvertValToSlot<any>} */
const doNotConvertValToSlot = val =>
Fail`Marshal's stringify rejects presences and promises ${val}`;
@@ -23,7 +25,12 @@ const badArrayHandler = harden({
},
});

const badArray = harden(new Proxy(harden([]), badArrayHandler));
/**
* `freeze` but not `harden` the proxy target so it remains trapping.
* @see https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
*/
const arrayTarget = freeze(/** @type {any[]} */ ([]));
const badArray = new Proxy(arrayTarget, badArrayHandler);

const { serialize, unserialize } = makeMarshal(
doNotConvertValToSlot,
@@ -48,7 +55,10 @@ harden(stringify);
*/
const parse = str =>
unserialize(
harden({
// `freeze` but not `harden` since the `badArray` proxy and its target
// must remain trapping.
// See https://github.com/endojs/endo/blob/master/packages/ses/docs/preparing-for-stabilize.md
freeze({
body: str,
slots: badArray,
}),
2 changes: 2 additions & 0 deletions packages/marshal/src/types.js
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@ export {};

/**
* @template T
* TODO either delete or at-ts-expect-error
* // @ts-ignore
* @typedef {{ '@qclass': T }} EncodingClass
*/

2 changes: 1 addition & 1 deletion packages/marshal/test/marshal-far-function.test.js
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ test('Data can contain far functions', t => {
const arrow = Far('arrow', a => a + 1);
t.is(passStyleOf(harden({ x: 8, foo: arrow })), 'copyRecord');
const mightBeMethod = a => a + 1;
t.throws(() => passStyleOf(freeze({ x: 8, foo: mightBeMethod })), {
t.throws(() => passStyleOf(harden({ x: 8, foo: mightBeMethod })), {
message: /Remotables with non-methods like "x" /,
});
});
3 changes: 2 additions & 1 deletion packages/pass-style/src/symbol.js
Original file line number Diff line number Diff line change
@@ -11,7 +11,8 @@ const wellKnownSymbolNames = new Map(
name => typeof name === 'string' && typeof Symbol[name] === 'symbol',
)
.filter(name => {
// @ts-expect-error It doesn't know name cannot be a symbol
// TODO either delete or at-ts-expect-error
// @ts-ignore It doesn't know name cannot be a symbol
!name.startsWith('@@') ||
Fail`Did not expect Symbol to have a symbol-valued property name starting with "@@" ${q(
name,
Loading
Loading