From f5848efb44561445a911a147335ff1d32b4331b7 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 28 May 2024 19:40:53 +0100 Subject: [PATCH 001/115] feat(ses): strip async generators for Hermes - fix React Native Android release build (Metro bundle) error - fix getAnonymousIntrinsics runtime SES error - strip async generators and iterators - strip related intrinsics (control abstraction objects) - no longer attempt to repair them - remove (and update) related tests - before: 380 passed, 2 known failures, 2 skipped - after: 379 passed, 2 known failures, 2 skipped --- packages/ses/src/get-anonymous-intrinsics.js | 18 ------------ packages/ses/src/permits.js | 28 ------------------- .../ses/src/tame-function-constructors.js | 6 +--- packages/ses/test/harden.test.js | 3 -- packages/ses/test/ses.test.js | 9 +----- packages/ses/test/tame-function-unit.test.js | 16 ----------- 6 files changed, 2 insertions(+), 78 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index cf402c3339..256a121af6 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -95,20 +95,6 @@ export const getAnonymousIntrinsics = () => { const Generator = GeneratorFunction.prototype; - // 25.3.1 The AsyncGeneratorFunction Constructor - - // eslint-disable-next-line no-empty-function - async function* AsyncGeneratorFunctionInstance() {} - const AsyncGeneratorFunction = getConstructorOf( - AsyncGeneratorFunctionInstance, - ); - - // 25.3.2.2 AsyncGeneratorFunction.prototype - const AsyncGenerator = AsyncGeneratorFunction.prototype; - // 25.5.1 Properties of the AsyncGenerator Prototype Object - const AsyncGeneratorPrototype = AsyncGenerator.prototype; - const AsyncIteratorPrototype = getPrototypeOf(AsyncGeneratorPrototype); - // 25.7.1 The AsyncFunction Constructor // eslint-disable-next-line no-empty-function @@ -119,10 +105,6 @@ export const getAnonymousIntrinsics = () => { '%InertFunction%': InertFunction, '%ArrayIteratorPrototype%': ArrayIteratorPrototype, '%InertAsyncFunction%': AsyncFunction, - '%AsyncGenerator%': AsyncGenerator, - '%InertAsyncGeneratorFunction%': AsyncGeneratorFunction, - '%AsyncGeneratorPrototype%': AsyncGeneratorPrototype, - '%AsyncIteratorPrototype%': AsyncIteratorPrototype, '%Generator%': Generator, '%InertGeneratorFunction%': GeneratorFunction, '%IteratorPrototype%': IteratorPrototype, diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index d364501067..269a4689a0 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1430,24 +1430,6 @@ export const permitted = { '@@toStringTag': 'string', }, - '%InertAsyncGeneratorFunction%': { - // Properties of the AsyncGeneratorFunction Constructor - '[[Proto]]': '%InertFunction%', - prototype: '%AsyncGenerator%', - }, - - '%AsyncGenerator%': { - // Properties of the AsyncGeneratorFunction Prototype Object - '[[Proto]]': '%FunctionPrototype%', - constructor: '%InertAsyncGeneratorFunction%', - prototype: '%AsyncGeneratorPrototype%', - // length prop added here for React Native jsc-android - // https://github.com/endojs/endo/issues/660 - // https://github.com/react-native-community/jsc-android-buildscripts/issues/181 - length: 'number', - '@@toStringTag': 'string', - }, - '%GeneratorPrototype%': { // Properties of the Generator Prototype Object '[[Proto]]': '%IteratorPrototype%', @@ -1458,16 +1440,6 @@ export const permitted = { '@@toStringTag': 'string', }, - '%AsyncGeneratorPrototype%': { - // Properties of the AsyncGenerator Prototype Object - '[[Proto]]': '%AsyncIteratorPrototype%', - constructor: '%AsyncGenerator%', - next: fn, - return: fn, - throw: fn, - '@@toStringTag': 'string', - }, - // TODO: To be replaced with Promise.delegate // // The HandledPromise global variable shimmed by `@agoric/eventual-send/shim` diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 4380ae4d4e..77dd7f83b5 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -121,16 +121,12 @@ export default function tameFunctionConstructors() { '%InertGeneratorFunction%', '(function*(){})', ); + // Hermes doesn't support async arrow functions, is this ok? repairFunction( 'AsyncFunction', '%InertAsyncFunction%', '(async function(){})', ); - repairFunction( - 'AsyncGeneratorFunction', - '%InertAsyncGeneratorFunction%', - '(async function*(){})', - ); return newIntrinsics; } diff --git a/packages/ses/test/harden.test.js b/packages/ses/test/harden.test.js index d4ba4297ca..b20d342948 100644 --- a/packages/ses/test/harden.test.js +++ b/packages/ses/test/harden.test.js @@ -25,9 +25,6 @@ test('Compartment anonymous intrinsics are frozen', t => { t.throws(() => c.evaluate('(async function() {}).constructor.a = 10;'), { instanceOf: TypeError, }); - t.throws(() => c.evaluate('(async function*() {}).constructor.a = 10;'), { - instanceOf: TypeError, - }); t.throws(() => c.evaluate('(function*() {}).constructor.a = 10;'), { instanceOf: TypeError, }); diff --git a/packages/ses/test/ses.test.js b/packages/ses/test/ses.test.js index dc654beaf8..c3637ebf75 100644 --- a/packages/ses/test/ses.test.js +++ b/packages/ses/test/ses.test.js @@ -6,7 +6,7 @@ lockdown(); /* eslint-disable no-proto, no-empty-function */ test('tamed constructors', t => { - t.plan(12); + t.plan(10); function F() {} t.throws(() => F.__proto__.constructor(''), { instanceOf: TypeError }); @@ -17,9 +17,6 @@ test('tamed constructors', t => { function* G() {} t.throws(() => G.__proto__.constructor(''), { instanceOf: TypeError }); - async function* AG() {} - t.throws(() => AG.__proto__.constructor(''), { instanceOf: TypeError }); - t.throws(() => Error.__proto__.constructor(''), { instanceOf: TypeError }); t.throws(() => Function.prototype.constructor(''), { instanceOf: TypeError }); @@ -42,10 +39,6 @@ test('tamed constructors', t => { t.throws(() => c.evaluate("function* G() {}; G.__proto__.constructor('')"), { instanceOf: TypeError, }); - t.throws( - () => c.evaluate("async function* AG() {}; AG.__proto__.constructor('')"), - { instanceOf: TypeError }, - ); }); test('frozen', t => { diff --git a/packages/ses/test/tame-function-unit.test.js b/packages/ses/test/tame-function-unit.test.js index 8445b6d1f5..23b919000c 100644 --- a/packages/ses/test/tame-function-unit.test.js +++ b/packages/ses/test/tame-function-unit.test.js @@ -48,19 +48,3 @@ test('GeneratorFunction.constructor', t => { } } }); - -test('AsyncGeneratorFunction.constructor', t => { - t.plan(1); - - try { - // eslint-disable-next-line no-eval - const proto = Object.getPrototypeOf((0, eval)('(async function* () {})')); - t.throws(() => proto.constructor(''), { instanceOf: TypeError }); - } catch (e) { - if (e instanceof SyntaxError) { - t.pass('not supported'); - } else { - throw e; - } - } -}); From ef479f20276a53b7f420175c782065a20754c13b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Sun, 2 Jun 2024 17:28:12 +0100 Subject: [PATCH 002/115] refactor(ses): remove comment --- packages/ses/src/tame-function-constructors.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 77dd7f83b5..ac26d3b08a 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -121,7 +121,6 @@ export default function tameFunctionConstructors() { '%InertGeneratorFunction%', '(function*(){})', ); - // Hermes doesn't support async arrow functions, is this ok? repairFunction( 'AsyncFunction', '%InertAsyncFunction%', From eb5577700bee0655d0cee6615e16cf80b0df2234 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Sun, 2 Jun 2024 17:45:51 +0100 Subject: [PATCH 003/115] refactor(ses): convert async arrow functions for Hermes - fix remaining React Native Android release build (Metro bundle) errors - convert load fn and drainQueue fn to standard async fns like asyncTrampoline - test: 379 passed, 2 known failures, 2 skipped - load fn is too integrated into SES and tests to be removed --- packages/ses/src/module-load.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ses/src/module-load.js b/packages/ses/src/module-load.js index dff6c35bc6..dbf93975ae 100644 --- a/packages/ses/src/module-load.js +++ b/packages/ses/src/module-load.js @@ -522,7 +522,7 @@ const asyncJobQueue = () => { * * @returns {Promise>} */ - const drainQueue = async () => { + async function drainQueue () { await null; for (const job of pendingJobs) { // eslint-disable-next-line no-await-in-loop @@ -562,12 +562,12 @@ const preferAsync = (asyncImpl, _syncImpl) => asyncImpl; * compartment and the specifier of the module within its own compartment. * This graph is then ready to be synchronously linked and executed. */ -export const load = async ( +export async function load ( compartmentPrivateFields, moduleAliases, compartment, moduleSpecifier, -) => { +) { const { name: compartmentName } = weakmapGet( compartmentPrivateFields, compartment, From 888caa933e47bc47c22e20b98768d192d6499603 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:49:20 +0100 Subject: [PATCH 004/115] refactor(ses): WIP --- packages/ses/index-hermes.js | 15 ++ packages/ses/scripts/bundle.js | 12 +- .../src/get-anonymous-intrinsics-hermes.js | 143 ++++++++++++++++++ packages/ses/src/get-anonymous-intrinsics.js | 18 +++ packages/ses/src/lockdown.js | 9 +- 5 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 packages/ses/index-hermes.js create mode 100644 packages/ses/src/get-anonymous-intrinsics-hermes.js diff --git a/packages/ses/index-hermes.js b/packages/ses/index-hermes.js new file mode 100644 index 0000000000..15f55c84d0 --- /dev/null +++ b/packages/ses/index-hermes.js @@ -0,0 +1,15 @@ +// Copyright (C) 2018 Agoric +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import './src/lockdown-shim.js'; diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 542995a6ac..b0a7b413f3 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -14,7 +14,8 @@ const write = async (target, content) => { await fs.promises.writeFile(location, content); }; -const main = async () => { +const main = async (options) => { + console.log({ options }); const text = await fs.promises.readFile( fileURLToPath(`${root}/package.json`), 'utf8', @@ -22,10 +23,13 @@ const main = async () => { const packageJson = JSON.parse(text); const version = packageJson.version; + const entryPointPath = options && options.buildType ? `../index-${options.buildType}.js` : '../index.js'; + const bundle = await makeBundle( read, - pathToFileURL(resolve('../index.js', import.meta.url)).toString(), + pathToFileURL(resolve(entryPointPath, import.meta.url)).toString(), ); + const versionedBundle = `// ses@${version}\n${bundle}`; const { code: terse } = await minify(versionedBundle, { @@ -46,6 +50,7 @@ const main = async () => { 'dist/lockdown.cjs', 'dist/lockdown.mjs', 'dist/lockdown.umd.js', + 'dist/ses-hermes.umd.js', ]; const terseFilePaths = ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; @@ -80,7 +85,8 @@ const main = async () => { console.log(`Copied ${sourceDTS} to ${destDTS}`); }; -main().catch(err => { +const options = { buildType: process.env.SES_BUILDTYPE }; +main(options).catch(err => { console.error('Error running main:', err); process.exitCode = 1; }); diff --git a/packages/ses/src/get-anonymous-intrinsics-hermes.js b/packages/ses/src/get-anonymous-intrinsics-hermes.js new file mode 100644 index 0000000000..050132dfc2 --- /dev/null +++ b/packages/ses/src/get-anonymous-intrinsics-hermes.js @@ -0,0 +1,143 @@ +import { + FERAL_FUNCTION, + Float32Array, + Map, + Set, + String, + getOwnPropertyDescriptor, + getPrototypeOf, + iterateArray, + iterateMap, + iterateSet, + iterateString, + matchAllRegExp, + matchAllSymbol, + regexpPrototype, + globalThis, +} from './commons.js'; +import { InertCompartment } from './compartment.js'; + +/** + * Object.getConstructorOf() + * Helper function to improve readability, similar to Object.getPrototypeOf(). + * + * @param {object} obj + */ +function getConstructorOf(obj) { + return getPrototypeOf(obj).constructor; +} + +// getAnonymousIntrinsics uses a utility function to construct an arguments +// object, since it cannot have one of its own and also be a const export. +function makeArguments() { + // eslint-disable-next-line prefer-rest-params + return arguments; +} + +/** + * getAnonymousIntrinsics() + * Get the intrinsics not otherwise reachable by named own property + * traversal from the global object. + * + * @returns {object} + */ +export const getAnonymousIntrinsicsHermes = () => { + const InertFunction = FERAL_FUNCTION.prototype.constructor; + + // 9.2.4.1 %ThrowTypeError% + + const argsCalleeDesc = getOwnPropertyDescriptor(makeArguments(), 'callee'); + const ThrowTypeError = argsCalleeDesc && argsCalleeDesc.get; + + // 21.1.5.2 The %StringIteratorPrototype% Object + + // eslint-disable-next-line no-new-wrappers + const StringIteratorObject = iterateString(new String()); + const StringIteratorPrototype = getPrototypeOf(StringIteratorObject); + + // 21.2.7.1 The %RegExpStringIteratorPrototype% Object + const RegExpStringIterator = + regexpPrototype[matchAllSymbol] && matchAllRegExp(/./); + const RegExpStringIteratorPrototype = + RegExpStringIterator && getPrototypeOf(RegExpStringIterator); + + // 22.1.5.2 The %ArrayIteratorPrototype% Object + + // eslint-disable-next-line no-array-constructor + const ArrayIteratorObject = iterateArray([]); + const ArrayIteratorPrototype = getPrototypeOf(ArrayIteratorObject); + + // 22.2.1 The %TypedArray% Intrinsic Object + + const TypedArray = getPrototypeOf(Float32Array); + + // 23.1.5.2 The %MapIteratorPrototype% Object + + const MapIteratorObject = iterateMap(new Map()); + const MapIteratorPrototype = getPrototypeOf(MapIteratorObject); + + // 23.2.5.2 The %SetIteratorPrototype% Object + + const SetIteratorObject = iterateSet(new Set()); + const SetIteratorPrototype = getPrototypeOf(SetIteratorObject); + + // 25.1.2 The %IteratorPrototype% Object + + const IteratorPrototype = getPrototypeOf(ArrayIteratorPrototype); + + // 25.2.1 The GeneratorFunction Constructor + + // eslint-disable-next-line no-empty-function + function* GeneratorFunctionInstance() {} + const GeneratorFunction = getConstructorOf(GeneratorFunctionInstance); + + // 25.2.3 Properties of the GeneratorFunction Prototype Object + + const Generator = GeneratorFunction.prototype; + + // 25.7.1 The AsyncFunction Constructor + + // eslint-disable-next-line no-empty-function + async function AsyncFunctionInstance() {} + const AsyncFunction = getConstructorOf(AsyncFunctionInstance); + + const intrinsics = { + '%InertFunction%': InertFunction, + '%ArrayIteratorPrototype%': ArrayIteratorPrototype, + '%InertAsyncFunction%': AsyncFunction, + '%Generator%': Generator, + '%InertGeneratorFunction%': GeneratorFunction, + '%IteratorPrototype%': IteratorPrototype, + '%MapIteratorPrototype%': MapIteratorPrototype, + '%RegExpStringIteratorPrototype%': RegExpStringIteratorPrototype, + '%SetIteratorPrototype%': SetIteratorPrototype, + '%StringIteratorPrototype%': StringIteratorPrototype, + '%ThrowTypeError%': ThrowTypeError, + '%TypedArray%': TypedArray, + '%InertCompartment%': InertCompartment, + }; + + if (globalThis.Iterator) { + intrinsics['%IteratorHelperPrototype%'] = getPrototypeOf( + // eslint-disable-next-line @endo/no-polymorphic-call + globalThis.Iterator.from([]).take(0), + ); + intrinsics['%WrapForValidIteratorPrototype%'] = getPrototypeOf( + // eslint-disable-next-line @endo/no-polymorphic-call + globalThis.Iterator.from({ next() {} }), + ); + } + + if (globalThis.AsyncIterator) { + intrinsics['%AsyncIteratorHelperPrototype%'] = getPrototypeOf( + // eslint-disable-next-line @endo/no-polymorphic-call + globalThis.AsyncIterator.from([]).take(0), + ); + intrinsics['%WrapForValidAsyncIteratorPrototype%'] = getPrototypeOf( + // eslint-disable-next-line @endo/no-polymorphic-call + globalThis.AsyncIterator.from({ next() {} }), + ); + } + + return intrinsics; +}; diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 256a121af6..cf402c3339 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -95,6 +95,20 @@ export const getAnonymousIntrinsics = () => { const Generator = GeneratorFunction.prototype; + // 25.3.1 The AsyncGeneratorFunction Constructor + + // eslint-disable-next-line no-empty-function + async function* AsyncGeneratorFunctionInstance() {} + const AsyncGeneratorFunction = getConstructorOf( + AsyncGeneratorFunctionInstance, + ); + + // 25.3.2.2 AsyncGeneratorFunction.prototype + const AsyncGenerator = AsyncGeneratorFunction.prototype; + // 25.5.1 Properties of the AsyncGenerator Prototype Object + const AsyncGeneratorPrototype = AsyncGenerator.prototype; + const AsyncIteratorPrototype = getPrototypeOf(AsyncGeneratorPrototype); + // 25.7.1 The AsyncFunction Constructor // eslint-disable-next-line no-empty-function @@ -105,6 +119,10 @@ export const getAnonymousIntrinsics = () => { '%InertFunction%': InertFunction, '%ArrayIteratorPrototype%': ArrayIteratorPrototype, '%InertAsyncFunction%': AsyncFunction, + '%AsyncGenerator%': AsyncGenerator, + '%InertAsyncGeneratorFunction%': AsyncGeneratorFunction, + '%AsyncGeneratorPrototype%': AsyncGeneratorPrototype, + '%AsyncIteratorPrototype%': AsyncIteratorPrototype, '%Generator%': Generator, '%InertGeneratorFunction%': GeneratorFunction, '%IteratorPrototype%': IteratorPrototype, diff --git a/packages/ses/src/lockdown.js b/packages/ses/src/lockdown.js index 3a2e9c4921..86f70fccb4 100644 --- a/packages/ses/src/lockdown.js +++ b/packages/ses/src/lockdown.js @@ -55,6 +55,7 @@ import { makeCompartmentConstructor } from './compartment.js'; import { tameHarden } from './tame-harden.js'; import { tameSymbolConstructor } from './tame-symbol-constructor.js'; import { tameFauxDataProperties } from './tame-faux-data-properties.js'; +import { getAnonymousIntrinsicsHermes } from './get-anonymous-intrinsics-hermes.js'; /** @import {LockdownOptions} from '../types.js' */ @@ -275,7 +276,13 @@ export const repairIntrinsics = (options = {}) => { addIntrinsics(tameRegExpConstructor(regExpTaming)); addIntrinsics(tameSymbolConstructor()); - addIntrinsics(getAnonymousIntrinsics()); + // Needs to be tested in React Native + const AsyncGeneratorFunctionInstance = (0, eval)('async function* AsyncGeneratorFunctionInstance() {}'); + if (AsyncGeneratorFunctionInstance) { + addIntrinsics(getAnonymousIntrinsics()); + } else { + addIntrinsics(getAnonymousIntrinsicsHermes()); + } completePrototypes(); From 13c72e52852fcc9fb442b4ed830f82de1e5af04e Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Tue, 11 Jun 2024 11:53:16 +0000 Subject: [PATCH 005/115] fix output paths --- packages/ses/scripts/bundle.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index b0a7b413f3..c4fd6d28c3 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -43,16 +43,25 @@ const main = async (options) => { await fs.promises.mkdir('dist', { recursive: true }); - const bundleFilePaths = [ + const bundleFilePaths = options.buildType ? [ + `dist/ses-${options.buildType}.cjs`, + `dist/ses-${options.buildType}.mjs`, + `dist/ses-${options.buildType}.umd.js`, + `dist/lockdown-${options.buildType}.cjs`, + `dist/lockdown-${options.buildType}.mjs`, + `dist/lockdown-${options.buildType}.umd.js`, + ] : [ 'dist/ses.cjs', 'dist/ses.mjs', 'dist/ses.umd.js', 'dist/lockdown.cjs', 'dist/lockdown.mjs', 'dist/lockdown.umd.js', - 'dist/ses-hermes.umd.js', ]; - const terseFilePaths = ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; + const terseFilePaths = options.buildType + ? [`dist/ses-${options.buildType}.umd.min.js`, `dist/lockdown-${options.buildType}.umd.min.js`] + : ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; + await Promise.all([ ...bundleFilePaths.map(dest => write(dest, versionedBundle)), From 7bff3fc9fb9c52b51e99aff7423cabd9e3a545b6 Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Tue, 11 Jun 2024 12:18:35 +0000 Subject: [PATCH 006/115] refactor ses/scripts/bundle.js - remove env var SES_BUILDTYPE - now build all --- packages/ses/scripts/bundle.js | 40 +++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index c4fd6d28c3..9c1985a409 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -14,8 +14,12 @@ const write = async (target, content) => { await fs.promises.writeFile(location, content); }; -const main = async (options) => { - console.log({ options }); +const BUILD_TYPES = [ + '', + 'hermes', +]; + +const writeBundle = async ({ buildType }) => { const text = await fs.promises.readFile( fileURLToPath(`${root}/package.json`), 'utf8', @@ -23,13 +27,13 @@ const main = async (options) => { const packageJson = JSON.parse(text); const version = packageJson.version; - const entryPointPath = options && options.buildType ? `../index-${options.buildType}.js` : '../index.js'; + const entryPointPath = buildType ? `../index-${buildType}.js` : '../index.js'; const bundle = await makeBundle( read, pathToFileURL(resolve(entryPointPath, import.meta.url)).toString(), ); - + const versionedBundle = `// ses@${version}\n${bundle}`; const { code: terse } = await minify(versionedBundle, { @@ -43,13 +47,13 @@ const main = async (options) => { await fs.promises.mkdir('dist', { recursive: true }); - const bundleFilePaths = options.buildType ? [ - `dist/ses-${options.buildType}.cjs`, - `dist/ses-${options.buildType}.mjs`, - `dist/ses-${options.buildType}.umd.js`, - `dist/lockdown-${options.buildType}.cjs`, - `dist/lockdown-${options.buildType}.mjs`, - `dist/lockdown-${options.buildType}.umd.js`, + const bundleFilePaths = buildType ? [ + `dist/ses-${buildType}.cjs`, + `dist/ses-${buildType}.mjs`, + `dist/ses-${buildType}.umd.js`, + `dist/lockdown-${buildType}.cjs`, + `dist/lockdown-${buildType}.mjs`, + `dist/lockdown-${buildType}.umd.js`, ] : [ 'dist/ses.cjs', 'dist/ses.mjs', @@ -58,8 +62,8 @@ const main = async (options) => { 'dist/lockdown.mjs', 'dist/lockdown.umd.js', ]; - const terseFilePaths = options.buildType - ? [`dist/ses-${options.buildType}.umd.min.js`, `dist/lockdown-${options.buildType}.umd.min.js`] + const terseFilePaths = buildType + ? [`dist/ses-${buildType}.umd.min.js`, `dist/lockdown-${buildType}.umd.min.js`] : ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; @@ -94,8 +98,14 @@ const main = async (options) => { console.log(`Copied ${sourceDTS} to ${destDTS}`); }; -const options = { buildType: process.env.SES_BUILDTYPE }; -main(options).catch(err => { +const main = async () => { + await Promise.all( + BUILD_TYPES.map( + buildType => writeBundle({ buildType })), + ); +}; + +main().catch(err => { console.error('Error running main:', err); process.exitCode = 1; }); From 9578cc8632051d6fb3c5e30556d0bbd24f67b08e Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Tue, 11 Jun 2024 12:21:55 +0000 Subject: [PATCH 007/115] chore: template in ses version in comment --- packages/ses/scripts/bundle.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 9c1985a409..edf288100a 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -25,7 +25,9 @@ const writeBundle = async ({ buildType }) => { 'utf8', ); const packageJson = JSON.parse(text); - const version = packageJson.version; + const version = buildType + ? `${packageJson.version}-${buildType}` + : packageJson.version; const entryPointPath = buildType ? `../index-${buildType}.js` : '../index.js'; From 48579785ec1685b896dae62101ea19cebeed9aa1 Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Tue, 11 Jun 2024 12:23:02 +0000 Subject: [PATCH 008/115] chore: relocate BUILD_TYPES --- packages/ses/scripts/bundle.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index edf288100a..f6b7b2f9c8 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -14,11 +14,6 @@ const write = async (target, content) => { await fs.promises.writeFile(location, content); }; -const BUILD_TYPES = [ - '', - 'hermes', -]; - const writeBundle = async ({ buildType }) => { const text = await fs.promises.readFile( fileURLToPath(`${root}/package.json`), @@ -100,6 +95,11 @@ const writeBundle = async ({ buildType }) => { console.log(`Copied ${sourceDTS} to ${destDTS}`); }; +const BUILD_TYPES = [ + '', + 'hermes', +]; + const main = async () => { await Promise.all( BUILD_TYPES.map( From 644db02522720d12c339ffbab82f3c9bf70aad44 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 11 Jun 2024 13:25:14 +0100 Subject: [PATCH 009/115] refactor: WIP --- packages/ses/index-hermes.js | 2 +- packages/ses/src/lockdown-shim-hermes.js | 37 ++++++++++++++++++++++++ packages/ses/src/lockdown.js | 11 ++++--- 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 packages/ses/src/lockdown-shim-hermes.js diff --git a/packages/ses/index-hermes.js b/packages/ses/index-hermes.js index 15f55c84d0..5bac57fb60 100644 --- a/packages/ses/index-hermes.js +++ b/packages/ses/index-hermes.js @@ -12,4 +12,4 @@ // See the License for the specific language governing permissions and // limitations under the License. -import './src/lockdown-shim.js'; +import './src/lockdown-shim-hermes.js'; diff --git a/packages/ses/src/lockdown-shim-hermes.js b/packages/ses/src/lockdown-shim-hermes.js new file mode 100644 index 0000000000..d846159b52 --- /dev/null +++ b/packages/ses/src/lockdown-shim-hermes.js @@ -0,0 +1,37 @@ +// @ts-check + +// We import this first to fail as fast as possible if the shim has been +// transformed or embedded in a way that causes it to run in sloppy mode. +// See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_NO_SLOPPY.md +import './assert-sloppy-mode.js'; +import { globalThis } from './commons.js'; +import { repairIntrinsics } from './lockdown.js'; + +/** @import {LockdownOptions} from '../types.js' */ + +/** + * @param {LockdownOptions} options + */ +globalThis.lockdown = options => { + const hardenIntrinsics = repairIntrinsics(options, true); + globalThis.harden = hardenIntrinsics(); +}; + +/** + * @param {LockdownOptions} options + */ +globalThis.repairIntrinsics = options => { + const hardenIntrinsics = repairIntrinsics(options); + // Reveal hardenIntrinsics after repairs. + globalThis.hardenIntrinsics = () => { + // Reveal harden after hardenIntrinsics. + // Harden is dangerous before hardenIntrinsics because hardening just + // about anything will inadvertently render intrinsics irreparable. + // Also, for modules that must work both before or after lockdown (code + // that is portable between JS and SES), the existence of harden in global + // scope signals whether such code should attempt to use harden in the + // defense of its own API. + // @ts-ignore harden not yet recognized on globalThis. + globalThis.harden = hardenIntrinsics(); + }; +}; diff --git a/packages/ses/src/lockdown.js b/packages/ses/src/lockdown.js index 86f70fccb4..3a60f9e3f1 100644 --- a/packages/ses/src/lockdown.js +++ b/packages/ses/src/lockdown.js @@ -131,8 +131,9 @@ const assertDirectEvalAvailable = () => { /** * @param {LockdownOptions} [options] + * @param {boolean} hermes */ -export const repairIntrinsics = (options = {}) => { +export const repairIntrinsics = (options = {}, hermes) => { // First time, absent options default to 'safe'. // Subsequent times, absent options default to first options. // Thus, all present options must agree with first options. @@ -276,12 +277,10 @@ export const repairIntrinsics = (options = {}) => { addIntrinsics(tameRegExpConstructor(regExpTaming)); addIntrinsics(tameSymbolConstructor()); - // Needs to be tested in React Native - const AsyncGeneratorFunctionInstance = (0, eval)('async function* AsyncGeneratorFunctionInstance() {}'); - if (AsyncGeneratorFunctionInstance) { - addIntrinsics(getAnonymousIntrinsics()); - } else { + if (hermes) { addIntrinsics(getAnonymousIntrinsicsHermes()); + } else { + addIntrinsics(getAnonymousIntrinsics()); } completePrototypes(); From 1bd528fe04ef7edd7f53eae663babf1551ba3dba Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 25 Jun 2024 18:27:14 +0100 Subject: [PATCH 010/115] refactor(ses): WIP Co-authored-by: naugtur Co-Authored-By: Saleh Abdel Motaal --- packages/ses/index-hermes.js | 3 + packages/ses/lockdown-hermes.js | 1 + packages/ses/package.json | 13 +- packages/ses/scripts/bundle.js | 48 +- .../src/get-anonymous-intrinsics-hermes.js | 3 +- packages/ses/src/lockdown-hermes.js | 441 ++++++++++++++++++ packages/ses/src/lockdown-shim-hermes.js | 4 +- packages/ses/src/lockdown.js | 10 +- packages/ses/src/permits.js | 38 +- .../ses/src/tame-function-constructors.js | 12 + 10 files changed, 532 insertions(+), 41 deletions(-) create mode 100644 packages/ses/lockdown-hermes.js create mode 100644 packages/ses/src/lockdown-hermes.js diff --git a/packages/ses/index-hermes.js b/packages/ses/index-hermes.js index 5bac57fb60..cdc16daabe 100644 --- a/packages/ses/index-hermes.js +++ b/packages/ses/index-hermes.js @@ -13,3 +13,6 @@ // limitations under the License. import './src/lockdown-shim-hermes.js'; +import './src/compartment-shim.js'; +import './src/assert-shim.js'; +import './src/console-shim.js'; diff --git a/packages/ses/lockdown-hermes.js b/packages/ses/lockdown-hermes.js new file mode 100644 index 0000000000..4b3e46328d --- /dev/null +++ b/packages/ses/lockdown-hermes.js @@ -0,0 +1 @@ +import './index-hermes.js'; diff --git a/packages/ses/package.json b/packages/ses/package.json index e562a123e7..8218df9eeb 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -55,9 +55,20 @@ "default": "./dist/ses.cjs" } }, + "./lockdown-hermes": { + "import": { + "types": "./types.d.ts", + "default": "./index-hermes.js" + }, + "require": { + "types": "./dist/types.d.cts", + "default": "./dist/ses-hermes.cjs" + } + }, "./tools.js": "./tools.js", "./assert-shim.js": "./assert-shim.js", "./lockdown-shim.js": "./lockdown-shim.js", + "./lockdown-shim-hermes.js": "./lockdown-shim-hermes.js", "./compartment-shim.js": "./compartment-shim.js", "./package.json": "./package.json" }, @@ -70,7 +81,7 @@ "lint-fix": "eslint --fix .", "lint:eslint": "eslint .", "lint:types": "tsc", - "prepare": "npm run clean && npm run build", + "prepare": "npm run clean && npm run build && SES_BUILD_TYPE=hermes npm run build", "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs" diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index f6b7b2f9c8..5c0acd6d03 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -1,5 +1,6 @@ /* global process */ import '../index.js'; +// lockdown(); import fs from 'fs'; import { makeBundle } from '@endo/compartment-mapper/bundle.js'; import { minify } from 'terser'; @@ -14,7 +15,11 @@ const write = async (target, content) => { await fs.promises.writeFile(location, content); }; -const writeBundle = async ({ buildType }) => { +/** + * @param {object} [options] + * @param {string} [options.buildType] Suffix used to build special bundles (e.g. 'hermes') + */ +const writeBundle = async ({ buildType } = {}) => { const text = await fs.promises.readFile( fileURLToPath(`${root}/package.json`), 'utf8', @@ -24,7 +29,8 @@ const writeBundle = async ({ buildType }) => { ? `${packageJson.version}-${buildType}` : packageJson.version; - const entryPointPath = buildType ? `../index-${buildType}.js` : '../index.js'; + const entryPointPath = `../index${buildType ? `-${buildType}` : ''}.js`; + console.log(`Bundle entrypoint: ${entryPointPath}`); const bundle = await makeBundle( read, @@ -44,24 +50,18 @@ const writeBundle = async ({ buildType }) => { await fs.promises.mkdir('dist', { recursive: true }); - const bundleFilePaths = buildType ? [ - `dist/ses-${buildType}.cjs`, - `dist/ses-${buildType}.mjs`, - `dist/ses-${buildType}.umd.js`, - `dist/lockdown-${buildType}.cjs`, - `dist/lockdown-${buildType}.mjs`, - `dist/lockdown-${buildType}.umd.js`, - ] : [ - 'dist/ses.cjs', - 'dist/ses.mjs', - 'dist/ses.umd.js', - 'dist/lockdown.cjs', - 'dist/lockdown.mjs', - 'dist/lockdown.umd.js', + const bundleFilePaths = [ + `dist/ses${buildType ? `-${buildType}` : ''}.cjs`, + `dist/ses${buildType ? `-${buildType}` : ''}.mjs`, + `dist/ses${buildType ? `-${buildType}` : ''}.umd.js`, + `dist/lockdown${buildType ? `-${buildType}` : ''}.cjs`, + `dist/lockdown${buildType ? `-${buildType}` : ''}.mjs`, + `dist/lockdown${buildType ? `-${buildType}` : ''}.umd.js`, + ]; + const terseFilePaths = [ + `dist/ses${buildType ? `-${buildType}` : ''}.umd.min.js`, + `dist/lockdown${buildType ? `-${buildType}` : ''}.umd.min.js`, ]; - const terseFilePaths = buildType - ? [`dist/ses-${buildType}.umd.min.js`, `dist/lockdown-${buildType}.umd.min.js`] - : ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; await Promise.all([ @@ -95,16 +95,8 @@ const writeBundle = async ({ buildType }) => { console.log(`Copied ${sourceDTS} to ${destDTS}`); }; -const BUILD_TYPES = [ - '', - 'hermes', -]; - const main = async () => { - await Promise.all( - BUILD_TYPES.map( - buildType => writeBundle({ buildType })), - ); + await writeBundle({ buildType: process.env.SES_BUILD_TYPE || undefined }); }; main().catch(err => { diff --git a/packages/ses/src/get-anonymous-intrinsics-hermes.js b/packages/ses/src/get-anonymous-intrinsics-hermes.js index 050132dfc2..b4dbb1db1f 100644 --- a/packages/ses/src/get-anonymous-intrinsics-hermes.js +++ b/packages/ses/src/get-anonymous-intrinsics-hermes.js @@ -35,9 +35,10 @@ function makeArguments() { } /** - * getAnonymousIntrinsics() + * getAnonymousIntrinsicsHermes() * Get the intrinsics not otherwise reachable by named own property * traversal from the global object. + * This excludes async generators. * * @returns {object} */ diff --git a/packages/ses/src/lockdown-hermes.js b/packages/ses/src/lockdown-hermes.js new file mode 100644 index 0000000000..9086fa66cb --- /dev/null +++ b/packages/ses/src/lockdown-hermes.js @@ -0,0 +1,441 @@ +// Copyright (C) 2018 Agoric +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @ts-check + +import { getEnvironmentOption as getenv } from '@endo/env-options'; +import { + FERAL_FUNCTION, + FERAL_EVAL, + TypeError, + arrayFilter, + globalThis, + is, + ownKeys, + stringSplit, + noEvalEvaluate, + getOwnPropertyNames, + getPrototypeOf, +} from './commons.js'; +import { makeHardener } from './make-hardener.js'; +import { makeIntrinsicsCollector } from './intrinsics.js'; +import whitelistIntrinsics from './permits-intrinsics.js'; +import tameFunctionConstructors from './tame-function-constructors.js'; +import tameDateConstructor from './tame-date-constructor.js'; +import tameMathObject from './tame-math-object.js'; +import tameRegExpConstructor from './tame-regexp-constructor.js'; +import enablePropertyOverrides from './enable-property-overrides.js'; +import tameLocaleMethods from './tame-locale-methods.js'; +import { + setGlobalObjectConstantProperties, + setGlobalObjectMutableProperties, + setGlobalObjectEvaluators, +} from './global-object.js'; +import { makeSafeEvaluator } from './make-safe-evaluator.js'; +import { initialGlobalPropertyNames } from './permits.js'; +import { tameFunctionToString } from './tame-function-tostring.js'; +import { tameDomains } from './tame-domains.js'; + +import { tameConsole } from './error/tame-console.js'; +import tameErrorConstructor from './error/tame-error-constructor.js'; +import { assert, makeAssert } from './error/assert.js'; +import { getAnonymousIntrinsicsHermes } from './get-anonymous-intrinsics-hermes.js'; +import { makeCompartmentConstructor } from './compartment.js'; +import { tameHarden } from './tame-harden.js'; +import { tameSymbolConstructor } from './tame-symbol-constructor.js'; +import { tameFauxDataProperties } from './tame-faux-data-properties.js'; + +/** @import {LockdownOptions} from '../types.js' */ + +const { Fail, details: d, quote: q } = assert; + +/** @type {Error=} */ +let priorRepairIntrinsics; + +/** @type {Error=} */ +let priorHardenIntrinsics; + +// Build a harden() with an empty fringe. +// Gate it on lockdown. +/** + * @template T + * @param {T} ref + * @returns {T} + */ +const safeHarden = makeHardener(); + +/** + * @callback Transform + * @param {string} source + * @returns {string} + */ + +/** + * @callback CompartmentConstructor + * @param {object} endowments + * @param {object} moduleMap + * @param {object} [options] + * @param {Array} [options.transforms] + * @param {Array} [options.__shimTransforms__] + */ + +// TODO https://github.com/endojs/endo/issues/814 +// Lockdown currently allows multiple calls provided that the specified options +// of every call agree. With experience, we have observed that lockdown should +// only ever need to be called once and that simplifying lockdown will improve +// the quality of audits. + +const assertDirectEvalAvailable = () => { + let allowed = false; + try { + allowed = FERAL_FUNCTION( + 'eval', + 'SES_changed', + `\ + eval("SES_changed = true"); + return SES_changed; + `, + )(FERAL_EVAL, false); + // If we get here and SES_changed stayed false, that means the eval was sloppy + // and indirect, which generally creates a new global. + // We are going to throw an exception for failing to initialize SES, but + // good neighbors clean up. + if (!allowed) { + delete globalThis.SES_changed; + } + } catch (_error) { + // We reach here if eval is outright forbidden by a Content Security Policy. + // We allow this for SES usage that delegates the responsibility to isolate + // guest code to production code generation. + allowed = true; + } + if (!allowed) { + // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_DIRECT_EVAL.md + throw TypeError( + `SES cannot initialize unless 'eval' is the original intrinsic 'eval', suitable for direct-eval (dynamically scoped eval) (SES_DIRECT_EVAL)`, + ); + } +}; + +/** + * @param {LockdownOptions} [options] + * @param {boolean} hermes + */ +export const repairIntrinsics = (options = {}) => { + // First time, absent options default to 'safe'. + // Subsequent times, absent options default to first options. + // Thus, all present options must agree with first options. + // Reconstructing `option` here also ensures that it is a well + // behaved record, with only own data properties. + // + // The `overrideTaming` is not a safety issue. Rather it is a tradeoff + // between code compatibility, which is better with the `'moderate'` + // setting, and tool compatibility, which is better with the `'min'` + // setting. See + // https://github.com/Agoric/SES-shim/blob/master/packages/ses/README.md#enabling-override-by-assignment) + // for an explanation of when to use which. + // + // The `stackFiltering` is not a safety issue. Rather it is a tradeoff + // between relevance and completeness of the stack frames shown on the + // console. Setting`stackFiltering` to `'verbose'` applies no filters, providing + // the raw stack frames that can be quite versbose. Setting + // `stackFrameFiltering` to`'concise'` limits the display to the stack frame + // information most likely to be relevant, eliminating distracting frames + // such as those from the infrastructure. However, the bug you're trying to + // track down might be in the infrastrure, in which case the `'verbose'` setting + // is useful. See + // [`stackFiltering` options](https://github.com/Agoric/SES-shim/blob/master/packages/ses/docs/lockdown.md#stackfiltering-options) + // for an explanation. + + const { + errorTaming = getenv('LOCKDOWN_ERROR_TAMING', 'safe'), + errorTrapping = /** @type {"platform" | "none" | "report" | "abort" | "exit" | undefined} */ ( + getenv('LOCKDOWN_ERROR_TRAPPING', 'platform') + ), + unhandledRejectionTrapping = /** @type {"none" | "report" | undefined} */ ( + getenv('LOCKDOWN_UNHANDLED_REJECTION_TRAPPING', 'report') + ), + regExpTaming = getenv('LOCKDOWN_REGEXP_TAMING', 'safe'), + localeTaming = getenv('LOCKDOWN_LOCALE_TAMING', 'safe'), + + consoleTaming = /** @type {'unsafe' | 'safe' | undefined} */ ( + getenv('LOCKDOWN_CONSOLE_TAMING', 'safe') + ), + overrideTaming = getenv('LOCKDOWN_OVERRIDE_TAMING', 'moderate'), + stackFiltering = getenv('LOCKDOWN_STACK_FILTERING', 'concise'), + domainTaming = getenv('LOCKDOWN_DOMAIN_TAMING', 'safe'), + evalTaming = getenv('LOCKDOWN_EVAL_TAMING', 'safeEval'), + overrideDebug = arrayFilter( + stringSplit(getenv('LOCKDOWN_OVERRIDE_DEBUG', ''), ','), + /** @param {string} debugName */ + debugName => debugName !== '', + ), + __hardenTaming__ = getenv('LOCKDOWN_HARDEN_TAMING', 'safe'), + dateTaming = 'safe', // deprecated + mathTaming = 'safe', // deprecated + ...extraOptions + } = options; + + evalTaming === 'unsafeEval' || + evalTaming === 'safeEval' || + evalTaming === 'noEval' || + Fail`lockdown(): non supported option evalTaming: ${q(evalTaming)}`; + + // Assert that only supported options were passed. + // Use Reflect.ownKeys to reject symbol-named properties as well. + const extraOptionsNames = ownKeys(extraOptions); + extraOptionsNames.length === 0 || + Fail`lockdown(): non supported option ${q(extraOptionsNames)}`; + + priorRepairIntrinsics === undefined || + // eslint-disable-next-line @endo/no-polymorphic-call + assert.fail( + d`Already locked down at ${priorRepairIntrinsics} (SES_ALREADY_LOCKED_DOWN)`, + TypeError, + ); + // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_ALREADY_LOCKED_DOWN.md + priorRepairIntrinsics = TypeError('Prior lockdown (SES_ALREADY_LOCKED_DOWN)'); + // Tease V8 to generate the stack string and release the closures the stack + // trace retained: + priorRepairIntrinsics.stack; + + assertDirectEvalAvailable(); + + /** + * Because of packagers and bundlers, etc, multiple invocations of lockdown + * might happen in separate instantiations of the source of this module. + * In that case, each one sees its own `firstOptions` variable, so the test + * above will not detect that lockdown has already happened. We + * unreliably test some telltale signs that lockdown has run, to avoid + * trying to lock down a locked down environment. Although the test is + * unreliable, this is consistent with the SES threat model. SES provides + * security only if it runs first in a given realm, or if everything that + * runs before it is SES-aware and cooperative. Neither SES nor anything + * can protect itself from corrupting code that runs first. For these + * purposes, code that turns a realm into something that passes these + * tests without actually locking down counts as corrupting code. + * + * The specifics of what this tests for may change over time, but it + * should be consistent with any setting of the lockdown options. + */ + const seemsToBeLockedDown = () => { + return ( + globalThis.Function.prototype.constructor !== globalThis.Function && + // @ts-ignore harden is absent on globalThis type def. + typeof globalThis.harden === 'function' && + // @ts-ignore lockdown is absent on globalThis type def. + typeof globalThis.lockdown === 'function' && + globalThis.Date.prototype.constructor !== globalThis.Date && + typeof globalThis.Date.now === 'function' && + // @ts-ignore does not recognize that Date constructor is a special + // Function. + // eslint-disable-next-line @endo/no-polymorphic-call + is(globalThis.Date.prototype.constructor.now(), NaN) + ); + }; + + if (seemsToBeLockedDown()) { + // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_MULTIPLE_INSTANCES.md + throw TypeError( + `Already locked down but not by this SES instance (SES_MULTIPLE_INSTANCES)`, + ); + } + + /** + * 1. TAME powers & gather intrinsics first. + */ + + tameDomains(domainTaming); + + // Replace Function.prototype.toString with one that recognizes + // shimmed functions as honorary native functions. + const markVirtualizedNativeFunction = tameFunctionToString(); + + const { addIntrinsics, completePrototypes, finalIntrinsics } = + makeIntrinsicsCollector(); + + const tamedHarden = tameHarden(safeHarden, __hardenTaming__); + addIntrinsics({ harden: tamedHarden }); + + addIntrinsics(tameFunctionConstructors()); + + addIntrinsics(tameDateConstructor(dateTaming)); + addIntrinsics(tameErrorConstructor(errorTaming, stackFiltering)); + addIntrinsics(tameMathObject(mathTaming)); + addIntrinsics(tameRegExpConstructor(regExpTaming)); + addIntrinsics(tameSymbolConstructor()); + + addIntrinsics(getAnonymousIntrinsicsHermes()); + + completePrototypes(); + + const intrinsics = finalIntrinsics(); + + const hostIntrinsics = { __proto__: null }; + + // The Node.js Buffer is a derived class of Uint8Array, and as such is often + // passed around where a Uint8Array is expected. + if (typeof globalThis.Buffer === 'function') { + hostIntrinsics.Buffer = globalThis.Buffer; + } + + /** + * Wrap console unless suppressed. + * At the moment, the console is considered a host power in the start + * compartment, and not a primordial. Hence it is absent from the whilelist + * and bypasses the intrinsicsCollector. + * + * @type {((error: any) => string | undefined) | undefined} + */ + let optGetStackString; + if (errorTaming !== 'unsafe') { + optGetStackString = intrinsics['%InitialGetStackString%']; + } + const consoleRecord = tameConsole( + consoleTaming, + errorTrapping, + unhandledRejectionTrapping, + optGetStackString, + ); + globalThis.console = /** @type {Console} */ (consoleRecord.console); + + // The untamed Node.js console cannot itself be hardened as it has mutable + // internal properties, but some of these properties expose internal versions + // of classes from node's "primordials" concept. + // eslint-disable-next-line no-underscore-dangle + if (typeof (/** @type {any} */ (consoleRecord.console)._times) === 'object') { + // SafeMap is a derived Map class used internally by Node + // There doesn't seem to be a cleaner way to reach it. + hostIntrinsics.SafeMap = getPrototypeOf( + // eslint-disable-next-line no-underscore-dangle + /** @type {any} */ (consoleRecord.console)._times, + ); + } + + // @ts-ignore assert is absent on globalThis type def. + if (errorTaming === 'unsafe' && globalThis.assert === assert) { + // If errorTaming is 'unsafe' we replace the global assert with + // one whose `details` template literal tag does not redact + // unmarked substitution values. IOW, it blabs information that + // was supposed to be secret from callers, as an aid to debugging + // at a further cost in safety. + // @ts-ignore assert is absent on globalThis type def. + globalThis.assert = makeAssert(undefined, true); + } + + // Replace *Locale* methods with their non-locale equivalents + tameLocaleMethods(intrinsics, localeTaming); + + tameFauxDataProperties(intrinsics); + + /** + * 2. WHITELIST to standardize the environment. + */ + + // Remove non-standard properties. + // All remaining function encountered during whitelisting are + // branded as honorary native functions. + whitelistIntrinsics(intrinsics, markVirtualizedNativeFunction); + + // Initialize the powerful initial global, i.e., the global of the + // start compartment, from the intrinsics. + + setGlobalObjectConstantProperties(globalThis); + + setGlobalObjectMutableProperties(globalThis, { + intrinsics, + newGlobalPropertyNames: initialGlobalPropertyNames, + makeCompartmentConstructor, + markVirtualizedNativeFunction, + }); + + if (evalTaming === 'noEval') { + setGlobalObjectEvaluators( + globalThis, + noEvalEvaluate, + markVirtualizedNativeFunction, + ); + } else if (evalTaming === 'safeEval') { + const { safeEvaluate } = makeSafeEvaluator({ globalObject: globalThis }); + setGlobalObjectEvaluators( + globalThis, + safeEvaluate, + markVirtualizedNativeFunction, + ); + } else if (evalTaming === 'unsafeEval') { + // Leave eval function and Function constructor of the initial compartment in-tact. + // Other compartments will not have access to these evaluators unless a guest program + // escapes containment. + } + + /** + * 3. HARDEN to share the intrinsics. + * + * We define hardenIntrinsics here so that options are in scope, but return + * it to the caller because we intend to eventually allow vetted shims to run + * between repairs and the hardening of intrinsics and so we can benchmark + * repair separately from hardening. + */ + + const hardenIntrinsics = () => { + priorHardenIntrinsics === undefined || + // eslint-disable-next-line @endo/no-polymorphic-call + assert.fail( + d`Already locked down at ${priorHardenIntrinsics} (SES_ALREADY_LOCKED_DOWN)`, + TypeError, + ); + // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_ALREADY_LOCKED_DOWN.md + priorHardenIntrinsics = TypeError( + 'Prior lockdown (SES_ALREADY_LOCKED_DOWN)', + ); + // Tease V8 to generate the stack string and release the closures the stack + // trace retained: + priorHardenIntrinsics.stack; + + // Circumvent the override mistake. + // TODO consider moving this to the end of the repair phase, and + // therefore before vetted shims rather than afterwards. It is not + // clear yet which is better. + // @ts-ignore enablePropertyOverrides does its own input validation + enablePropertyOverrides(intrinsics, overrideTaming, overrideDebug); + + // Finally register and optionally freeze all the intrinsics. This + // must be the operation that modifies the intrinsics. + const toHarden = { + intrinsics, + hostIntrinsics, + globals: { + // Harden evaluators + Function: globalThis.Function, + eval: globalThis.eval, + // @ts-ignore Compartment does exist on globalThis + Compartment: globalThis.Compartment, + + // Harden Symbol + Symbol: globalThis.Symbol, + }, + }; + + // Harden Symbol and properties for initialGlobalPropertyNames in the host realm + for (const prop of getOwnPropertyNames(initialGlobalPropertyNames)) { + toHarden.globals[prop] = globalThis[prop]; + } + + tamedHarden(toHarden); + + return tamedHarden; + }; + + return hardenIntrinsics; +}; diff --git a/packages/ses/src/lockdown-shim-hermes.js b/packages/ses/src/lockdown-shim-hermes.js index d846159b52..c3ec5da104 100644 --- a/packages/ses/src/lockdown-shim-hermes.js +++ b/packages/ses/src/lockdown-shim-hermes.js @@ -5,7 +5,7 @@ // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_NO_SLOPPY.md import './assert-sloppy-mode.js'; import { globalThis } from './commons.js'; -import { repairIntrinsics } from './lockdown.js'; +import { repairIntrinsics } from './lockdown-hermes.js'; /** @import {LockdownOptions} from '../types.js' */ @@ -13,7 +13,7 @@ import { repairIntrinsics } from './lockdown.js'; * @param {LockdownOptions} options */ globalThis.lockdown = options => { - const hardenIntrinsics = repairIntrinsics(options, true); + const hardenIntrinsics = repairIntrinsics(options); globalThis.harden = hardenIntrinsics(); }; diff --git a/packages/ses/src/lockdown.js b/packages/ses/src/lockdown.js index 3a60f9e3f1..3a2e9c4921 100644 --- a/packages/ses/src/lockdown.js +++ b/packages/ses/src/lockdown.js @@ -55,7 +55,6 @@ import { makeCompartmentConstructor } from './compartment.js'; import { tameHarden } from './tame-harden.js'; import { tameSymbolConstructor } from './tame-symbol-constructor.js'; import { tameFauxDataProperties } from './tame-faux-data-properties.js'; -import { getAnonymousIntrinsicsHermes } from './get-anonymous-intrinsics-hermes.js'; /** @import {LockdownOptions} from '../types.js' */ @@ -131,9 +130,8 @@ const assertDirectEvalAvailable = () => { /** * @param {LockdownOptions} [options] - * @param {boolean} hermes */ -export const repairIntrinsics = (options = {}, hermes) => { +export const repairIntrinsics = (options = {}) => { // First time, absent options default to 'safe'. // Subsequent times, absent options default to first options. // Thus, all present options must agree with first options. @@ -277,11 +275,7 @@ export const repairIntrinsics = (options = {}, hermes) => { addIntrinsics(tameRegExpConstructor(regExpTaming)); addIntrinsics(tameSymbolConstructor()); - if (hermes) { - addIntrinsics(getAnonymousIntrinsicsHermes()); - } else { - addIntrinsics(getAnonymousIntrinsics()); - } + addIntrinsics(getAnonymousIntrinsics()); completePrototypes(); diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index 269a4689a0..73b5871f80 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1,7 +1,7 @@ /* eslint-disable no-restricted-globals */ /* eslint max-lines: 0 */ -import { arrayPush } from './commons.js'; +import { arrayPush, assign, FERAL_FUNCTION } from './commons.js'; /** @import {GenericErrorConstructor} from '../types.js' */ @@ -1572,3 +1572,39 @@ export const permitted = { '%InitialGetStackString%': fn, }; + +try { + // eslint-disable-next-line + new FERAL_FUNCTION('async function* (){}') // A string, so Metro doesn't throw creating release bundle + assign(permitted, { + '%InertAsyncGeneratorFunction%': { + // Properties of the AsyncGeneratorFunction Constructor + '[[Proto]]': '%InertFunction%', + prototype: '%AsyncGenerator%', + }, + + '%AsyncGenerator%': { + // Properties of the AsyncGeneratorFunction Prototype Object + '[[Proto]]': '%FunctionPrototype%', + constructor: '%InertAsyncGeneratorFunction%', + prototype: '%AsyncGeneratorPrototype%', + // length prop added here for React Native jsc-android + // https://github.com/endojs/endo/issues/660 + // https://github.com/react-native-community/jsc-android-buildscripts/issues/181 + length: 'number', + '@@toStringTag': 'string', + }, + + '%AsyncGeneratorPrototype%': { + // Properties of the AsyncGenerator Prototype Object + '[[Proto]]': '%AsyncIteratorPrototype%', + constructor: '%AsyncGenerator%', + next: fn, + return: fn, + throw: fn, + '@@toStringTag': 'string', + }, + }) +} catch { + // +} diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index ac26d3b08a..8bb54671ba 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -127,5 +127,17 @@ export default function tameFunctionConstructors() { '(async function(){})', ); + try { + // eslint-disable-next-line + new FERAL_FUNCTION('async function* (){}'); + repairFunction( + 'AsyncGeneratorFunction', + '%InertAsyncGeneratorFunction%', + '(async function*(){})', + ); + } catch { + // + } + return newIntrinsics; } From a87fbb8203831f00f1bae8a9381db7fbb1beae41 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 28 Jun 2024 19:32:42 +0100 Subject: [PATCH 011/115] fix(ses): WIP Co-Authored-By: Saleh Abdel Motaal --- packages/ses/scripts/bundle.js | 2 - .../src/get-anonymous-intrinsics-hermes.js | 144 ------------------ packages/ses/src/get-anonymous-intrinsics.js | 46 +++--- packages/ses/src/lockdown-hermes.js | 5 +- packages/ses/src/permits.js | 43 +++++- .../ses/src/tame-function-constructors.js | 7 +- 6 files changed, 73 insertions(+), 174 deletions(-) delete mode 100644 packages/ses/src/get-anonymous-intrinsics-hermes.js diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 5c0acd6d03..ce3aff8002 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -1,6 +1,5 @@ /* global process */ import '../index.js'; -// lockdown(); import fs from 'fs'; import { makeBundle } from '@endo/compartment-mapper/bundle.js'; import { minify } from 'terser'; @@ -63,7 +62,6 @@ const writeBundle = async ({ buildType } = {}) => { `dist/lockdown${buildType ? `-${buildType}` : ''}.umd.min.js`, ]; - await Promise.all([ ...bundleFilePaths.map(dest => write(dest, versionedBundle)), ...terseFilePaths.map(dest => write(dest, terse)), diff --git a/packages/ses/src/get-anonymous-intrinsics-hermes.js b/packages/ses/src/get-anonymous-intrinsics-hermes.js deleted file mode 100644 index b4dbb1db1f..0000000000 --- a/packages/ses/src/get-anonymous-intrinsics-hermes.js +++ /dev/null @@ -1,144 +0,0 @@ -import { - FERAL_FUNCTION, - Float32Array, - Map, - Set, - String, - getOwnPropertyDescriptor, - getPrototypeOf, - iterateArray, - iterateMap, - iterateSet, - iterateString, - matchAllRegExp, - matchAllSymbol, - regexpPrototype, - globalThis, -} from './commons.js'; -import { InertCompartment } from './compartment.js'; - -/** - * Object.getConstructorOf() - * Helper function to improve readability, similar to Object.getPrototypeOf(). - * - * @param {object} obj - */ -function getConstructorOf(obj) { - return getPrototypeOf(obj).constructor; -} - -// getAnonymousIntrinsics uses a utility function to construct an arguments -// object, since it cannot have one of its own and also be a const export. -function makeArguments() { - // eslint-disable-next-line prefer-rest-params - return arguments; -} - -/** - * getAnonymousIntrinsicsHermes() - * Get the intrinsics not otherwise reachable by named own property - * traversal from the global object. - * This excludes async generators. - * - * @returns {object} - */ -export const getAnonymousIntrinsicsHermes = () => { - const InertFunction = FERAL_FUNCTION.prototype.constructor; - - // 9.2.4.1 %ThrowTypeError% - - const argsCalleeDesc = getOwnPropertyDescriptor(makeArguments(), 'callee'); - const ThrowTypeError = argsCalleeDesc && argsCalleeDesc.get; - - // 21.1.5.2 The %StringIteratorPrototype% Object - - // eslint-disable-next-line no-new-wrappers - const StringIteratorObject = iterateString(new String()); - const StringIteratorPrototype = getPrototypeOf(StringIteratorObject); - - // 21.2.7.1 The %RegExpStringIteratorPrototype% Object - const RegExpStringIterator = - regexpPrototype[matchAllSymbol] && matchAllRegExp(/./); - const RegExpStringIteratorPrototype = - RegExpStringIterator && getPrototypeOf(RegExpStringIterator); - - // 22.1.5.2 The %ArrayIteratorPrototype% Object - - // eslint-disable-next-line no-array-constructor - const ArrayIteratorObject = iterateArray([]); - const ArrayIteratorPrototype = getPrototypeOf(ArrayIteratorObject); - - // 22.2.1 The %TypedArray% Intrinsic Object - - const TypedArray = getPrototypeOf(Float32Array); - - // 23.1.5.2 The %MapIteratorPrototype% Object - - const MapIteratorObject = iterateMap(new Map()); - const MapIteratorPrototype = getPrototypeOf(MapIteratorObject); - - // 23.2.5.2 The %SetIteratorPrototype% Object - - const SetIteratorObject = iterateSet(new Set()); - const SetIteratorPrototype = getPrototypeOf(SetIteratorObject); - - // 25.1.2 The %IteratorPrototype% Object - - const IteratorPrototype = getPrototypeOf(ArrayIteratorPrototype); - - // 25.2.1 The GeneratorFunction Constructor - - // eslint-disable-next-line no-empty-function - function* GeneratorFunctionInstance() {} - const GeneratorFunction = getConstructorOf(GeneratorFunctionInstance); - - // 25.2.3 Properties of the GeneratorFunction Prototype Object - - const Generator = GeneratorFunction.prototype; - - // 25.7.1 The AsyncFunction Constructor - - // eslint-disable-next-line no-empty-function - async function AsyncFunctionInstance() {} - const AsyncFunction = getConstructorOf(AsyncFunctionInstance); - - const intrinsics = { - '%InertFunction%': InertFunction, - '%ArrayIteratorPrototype%': ArrayIteratorPrototype, - '%InertAsyncFunction%': AsyncFunction, - '%Generator%': Generator, - '%InertGeneratorFunction%': GeneratorFunction, - '%IteratorPrototype%': IteratorPrototype, - '%MapIteratorPrototype%': MapIteratorPrototype, - '%RegExpStringIteratorPrototype%': RegExpStringIteratorPrototype, - '%SetIteratorPrototype%': SetIteratorPrototype, - '%StringIteratorPrototype%': StringIteratorPrototype, - '%ThrowTypeError%': ThrowTypeError, - '%TypedArray%': TypedArray, - '%InertCompartment%': InertCompartment, - }; - - if (globalThis.Iterator) { - intrinsics['%IteratorHelperPrototype%'] = getPrototypeOf( - // eslint-disable-next-line @endo/no-polymorphic-call - globalThis.Iterator.from([]).take(0), - ); - intrinsics['%WrapForValidIteratorPrototype%'] = getPrototypeOf( - // eslint-disable-next-line @endo/no-polymorphic-call - globalThis.Iterator.from({ next() {} }), - ); - } - - if (globalThis.AsyncIterator) { - intrinsics['%AsyncIteratorHelperPrototype%'] = getPrototypeOf( - // eslint-disable-next-line @endo/no-polymorphic-call - globalThis.AsyncIterator.from([]).take(0), - ); - intrinsics['%WrapForValidAsyncIteratorPrototype%'] = getPrototypeOf( - // eslint-disable-next-line @endo/no-polymorphic-call - globalThis.AsyncIterator.from({ next() {} }), - ); - } - - return intrinsics; -}; diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index cf402c3339..5c4825d540 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -14,6 +14,7 @@ import { matchAllSymbol, regexpPrototype, globalThis, + assign, } from './commons.js'; import { InertCompartment } from './compartment.js'; @@ -95,20 +96,6 @@ export const getAnonymousIntrinsics = () => { const Generator = GeneratorFunction.prototype; - // 25.3.1 The AsyncGeneratorFunction Constructor - - // eslint-disable-next-line no-empty-function - async function* AsyncGeneratorFunctionInstance() {} - const AsyncGeneratorFunction = getConstructorOf( - AsyncGeneratorFunctionInstance, - ); - - // 25.3.2.2 AsyncGeneratorFunction.prototype - const AsyncGenerator = AsyncGeneratorFunction.prototype; - // 25.5.1 Properties of the AsyncGenerator Prototype Object - const AsyncGeneratorPrototype = AsyncGenerator.prototype; - const AsyncIteratorPrototype = getPrototypeOf(AsyncGeneratorPrototype); - // 25.7.1 The AsyncFunction Constructor // eslint-disable-next-line no-empty-function @@ -119,10 +106,6 @@ export const getAnonymousIntrinsics = () => { '%InertFunction%': InertFunction, '%ArrayIteratorPrototype%': ArrayIteratorPrototype, '%InertAsyncFunction%': AsyncFunction, - '%AsyncGenerator%': AsyncGenerator, - '%InertAsyncGeneratorFunction%': AsyncGeneratorFunction, - '%AsyncGeneratorPrototype%': AsyncGeneratorPrototype, - '%AsyncIteratorPrototype%': AsyncIteratorPrototype, '%Generator%': Generator, '%InertGeneratorFunction%': GeneratorFunction, '%IteratorPrototype%': IteratorPrototype, @@ -135,6 +118,33 @@ export const getAnonymousIntrinsics = () => { '%InertCompartment%': InertCompartment, }; + try { + // 25.3.1 The AsyncGeneratorFunction Constructor + + // eslint-disable-next-line no-empty-function + const AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( + 'return (async function* AsyncGeneratorFunctionInstance() {})', + )(); + const AsyncGeneratorFunction = getConstructorOf( + AsyncGeneratorFunctionInstance, + ); + + // 25.3.2.2 AsyncGeneratorFunction.prototype + const AsyncGenerator = AsyncGeneratorFunction.prototype; + // 25.5.1 Properties of the AsyncGenerator Prototype Object + const AsyncGeneratorPrototype = AsyncGenerator.prototype; + const AsyncIteratorPrototype = getPrototypeOf(AsyncGeneratorPrototype); + + assign(intrinsics, { + '%AsyncGenerator%': AsyncGenerator, + '%InertAsyncGeneratorFunction%': AsyncGeneratorFunction, + '%AsyncGeneratorPrototype%': AsyncGeneratorPrototype, + '%AsyncIteratorPrototype%': AsyncIteratorPrototype, + }); + } catch { + // + } + if (globalThis.Iterator) { intrinsics['%IteratorHelperPrototype%'] = getPrototypeOf( // eslint-disable-next-line @endo/no-polymorphic-call diff --git a/packages/ses/src/lockdown-hermes.js b/packages/ses/src/lockdown-hermes.js index 9086fa66cb..107b5d08a5 100644 --- a/packages/ses/src/lockdown-hermes.js +++ b/packages/ses/src/lockdown-hermes.js @@ -50,7 +50,7 @@ import { tameDomains } from './tame-domains.js'; import { tameConsole } from './error/tame-console.js'; import tameErrorConstructor from './error/tame-error-constructor.js'; import { assert, makeAssert } from './error/assert.js'; -import { getAnonymousIntrinsicsHermes } from './get-anonymous-intrinsics-hermes.js'; +import { getAnonymousIntrinsics } from './get-anonymous-intrinsics.js'; import { makeCompartmentConstructor } from './compartment.js'; import { tameHarden } from './tame-harden.js'; import { tameSymbolConstructor } from './tame-symbol-constructor.js'; @@ -130,7 +130,6 @@ const assertDirectEvalAvailable = () => { /** * @param {LockdownOptions} [options] - * @param {boolean} hermes */ export const repairIntrinsics = (options = {}) => { // First time, absent options default to 'safe'. @@ -276,7 +275,7 @@ export const repairIntrinsics = (options = {}) => { addIntrinsics(tameRegExpConstructor(regExpTaming)); addIntrinsics(tameSymbolConstructor()); - addIntrinsics(getAnonymousIntrinsicsHermes()); + addIntrinsics(getAnonymousIntrinsics()); completePrototypes(); diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index 73b5871f80..e88cb9e548 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1574,8 +1574,9 @@ export const permitted = { }; try { - // eslint-disable-next-line - new FERAL_FUNCTION('async function* (){}') // A string, so Metro doesn't throw creating release bundle + new FERAL_FUNCTION( + 'return (async function* AsyncGeneratorFunctionInstance() {})', + )(); assign(permitted, { '%InertAsyncGeneratorFunction%': { // Properties of the AsyncGeneratorFunction Constructor @@ -1604,7 +1605,41 @@ try { throw: fn, '@@toStringTag': 'string', }, - }) + + // https://github.com/tc39/proposal-async-iterator-helpers + AsyncIterator: { + // Properties of the Iterator Constructor + '[[Proto]]': '%FunctionPrototype%', + prototype: '%AsyncIteratorPrototype%', + from: fn, + }, + + '%AsyncIteratorPrototype%': { + // The %AsyncIteratorPrototype% Object + '@@asyncIterator': fn, + // https://github.com/tc39/proposal-async-iterator-helpers + constructor: 'AsyncIterator', + map: fn, + filter: fn, + take: fn, + drop: fn, + flatMap: fn, + reduce: fn, + toArray: fn, + forEach: fn, + some: fn, + every: fn, + find: fn, + '@@toStringTag': 'string', + // See https://github.com/Moddable-OpenSource/moddable/issues/523#issuecomment-1942904505 + '@@asyncDispose': false, + }, + }); + + // assign(uniqueGlobalPropertyNames, { + // // https://github.com/tc39/proposal-async-iterator-helpers + // AsyncIterator: 'AsyncIterator', + // }); } catch { - // + // } diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 8bb54671ba..01e7be5a8e 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -128,15 +128,16 @@ export default function tameFunctionConstructors() { ); try { - // eslint-disable-next-line - new FERAL_FUNCTION('async function* (){}'); + new FERAL_FUNCTION( + 'return (async function* AsyncGeneratorFunctionInstance() {})', + )(); repairFunction( 'AsyncGeneratorFunction', '%InertAsyncGeneratorFunction%', '(async function*(){})', ); } catch { - // + // } return newIntrinsics; From 6b6ee3be693bc33e6c3a6e615242c1595cab75c2 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:53:55 +0100 Subject: [PATCH 012/115] refactor(ses): permit try/catch condition for Hermes --- packages/ses/src/permits.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index e88cb9e548..6a58840eb0 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1574,9 +1574,7 @@ export const permitted = { }; try { - new FERAL_FUNCTION( - 'return (async function* AsyncGeneratorFunctionInstance() {})', - )(); +new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); assign(permitted, { '%InertAsyncGeneratorFunction%': { // Properties of the AsyncGeneratorFunction Constructor From 0e8de2372001fe91af3d5992e924a0fe18de9990 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 11:59:14 +0100 Subject: [PATCH 013/115] refactor(ses): tame fn constructors try/catch condition for Hermes --- packages/ses/src/tame-function-constructors.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 01e7be5a8e..8d26ee0f28 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -128,9 +128,7 @@ export default function tameFunctionConstructors() { ); try { - new FERAL_FUNCTION( - 'return (async function* AsyncGeneratorFunctionInstance() {})', - )(); +new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); repairFunction( 'AsyncGeneratorFunction', '%InertAsyncGeneratorFunction%', From 94ac76b6720b868bf2e55300ffa461acee0a5152 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:45:45 +0100 Subject: [PATCH 014/115] fix(ses): lint --- packages/ses/src/module-load.js | 8 ++++---- packages/ses/src/permits.js | 2 +- packages/ses/src/tame-function-constructors.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ses/src/module-load.js b/packages/ses/src/module-load.js index dbf93975ae..881cf390b6 100644 --- a/packages/ses/src/module-load.js +++ b/packages/ses/src/module-load.js @@ -522,14 +522,14 @@ const asyncJobQueue = () => { * * @returns {Promise>} */ - async function drainQueue () { + async function drainQueue() { await null; for (const job of pendingJobs) { // eslint-disable-next-line no-await-in-loop await job; } return errors; - }; + } return { enqueueJob, drainQueue }; }; @@ -562,7 +562,7 @@ const preferAsync = (asyncImpl, _syncImpl) => asyncImpl; * compartment and the specifier of the module within its own compartment. * This graph is then ready to be synchronously linked and executed. */ -export async function load ( +export async function load( compartmentPrivateFields, moduleAliases, compartment, @@ -597,7 +597,7 @@ export async function load ( compartmentName, )}`, }); -}; +} /* * `loadNow` synchronously gathers the module records for a specified module diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index 6a58840eb0..bc7205d218 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1574,7 +1574,7 @@ export const permitted = { }; try { -new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); + new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); assign(permitted, { '%InertAsyncGeneratorFunction%': { // Properties of the AsyncGeneratorFunction Constructor diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 8d26ee0f28..b73dd539b5 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -128,7 +128,7 @@ export default function tameFunctionConstructors() { ); try { -new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); + new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); repairFunction( 'AsyncGeneratorFunction', '%InertAsyncGeneratorFunction%', From f18e8762cd66c79513e7c21ff9ea5c1bd07cc99e Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:51:55 +0100 Subject: [PATCH 015/115] refactor(ses): revert bundling new Hermes shim --- packages/ses/scripts/bundle.js | 37 +++++++++------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index ce3aff8002..542995a6ac 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -14,28 +14,18 @@ const write = async (target, content) => { await fs.promises.writeFile(location, content); }; -/** - * @param {object} [options] - * @param {string} [options.buildType] Suffix used to build special bundles (e.g. 'hermes') - */ -const writeBundle = async ({ buildType } = {}) => { +const main = async () => { const text = await fs.promises.readFile( fileURLToPath(`${root}/package.json`), 'utf8', ); const packageJson = JSON.parse(text); - const version = buildType - ? `${packageJson.version}-${buildType}` - : packageJson.version; - - const entryPointPath = `../index${buildType ? `-${buildType}` : ''}.js`; - console.log(`Bundle entrypoint: ${entryPointPath}`); + const version = packageJson.version; const bundle = await makeBundle( read, - pathToFileURL(resolve(entryPointPath, import.meta.url)).toString(), + pathToFileURL(resolve('../index.js', import.meta.url)).toString(), ); - const versionedBundle = `// ses@${version}\n${bundle}`; const { code: terse } = await minify(versionedBundle, { @@ -50,17 +40,14 @@ const writeBundle = async ({ buildType } = {}) => { await fs.promises.mkdir('dist', { recursive: true }); const bundleFilePaths = [ - `dist/ses${buildType ? `-${buildType}` : ''}.cjs`, - `dist/ses${buildType ? `-${buildType}` : ''}.mjs`, - `dist/ses${buildType ? `-${buildType}` : ''}.umd.js`, - `dist/lockdown${buildType ? `-${buildType}` : ''}.cjs`, - `dist/lockdown${buildType ? `-${buildType}` : ''}.mjs`, - `dist/lockdown${buildType ? `-${buildType}` : ''}.umd.js`, - ]; - const terseFilePaths = [ - `dist/ses${buildType ? `-${buildType}` : ''}.umd.min.js`, - `dist/lockdown${buildType ? `-${buildType}` : ''}.umd.min.js`, + 'dist/ses.cjs', + 'dist/ses.mjs', + 'dist/ses.umd.js', + 'dist/lockdown.cjs', + 'dist/lockdown.mjs', + 'dist/lockdown.umd.js', ]; + const terseFilePaths = ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; await Promise.all([ ...bundleFilePaths.map(dest => write(dest, versionedBundle)), @@ -93,10 +80,6 @@ const writeBundle = async ({ buildType } = {}) => { console.log(`Copied ${sourceDTS} to ${destDTS}`); }; -const main = async () => { - await writeBundle({ buildType: process.env.SES_BUILD_TYPE || undefined }); -}; - main().catch(err => { console.error('Error running main:', err); process.exitCode = 1; From 17ff2169cf9f00e79f3d1394c12292a52b814f5e Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:52:02 +0100 Subject: [PATCH 016/115] refactor(ses): revert publishing new Hermes shim --- packages/ses/package.json | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 8218df9eeb..e562a123e7 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -55,20 +55,9 @@ "default": "./dist/ses.cjs" } }, - "./lockdown-hermes": { - "import": { - "types": "./types.d.ts", - "default": "./index-hermes.js" - }, - "require": { - "types": "./dist/types.d.cts", - "default": "./dist/ses-hermes.cjs" - } - }, "./tools.js": "./tools.js", "./assert-shim.js": "./assert-shim.js", "./lockdown-shim.js": "./lockdown-shim.js", - "./lockdown-shim-hermes.js": "./lockdown-shim-hermes.js", "./compartment-shim.js": "./compartment-shim.js", "./package.json": "./package.json" }, @@ -81,7 +70,7 @@ "lint-fix": "eslint --fix .", "lint:eslint": "eslint .", "lint:types": "tsc", - "prepare": "npm run clean && npm run build && SES_BUILD_TYPE=hermes npm run build", + "prepare": "npm run clean && npm run build", "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs" From d32b262632de5264b61266f6b501206a2821cf4a Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:52:24 +0100 Subject: [PATCH 017/115] refactor(ses): remove remaining stale Hermes files --- packages/ses/index-hermes.js | 18 - packages/ses/lockdown-hermes.js | 1 - packages/ses/src/lockdown-hermes.js | 440 ----------------------- packages/ses/src/lockdown-shim-hermes.js | 37 -- 4 files changed, 496 deletions(-) delete mode 100644 packages/ses/index-hermes.js delete mode 100644 packages/ses/lockdown-hermes.js delete mode 100644 packages/ses/src/lockdown-hermes.js delete mode 100644 packages/ses/src/lockdown-shim-hermes.js diff --git a/packages/ses/index-hermes.js b/packages/ses/index-hermes.js deleted file mode 100644 index cdc16daabe..0000000000 --- a/packages/ses/index-hermes.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2018 Agoric -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import './src/lockdown-shim-hermes.js'; -import './src/compartment-shim.js'; -import './src/assert-shim.js'; -import './src/console-shim.js'; diff --git a/packages/ses/lockdown-hermes.js b/packages/ses/lockdown-hermes.js deleted file mode 100644 index 4b3e46328d..0000000000 --- a/packages/ses/lockdown-hermes.js +++ /dev/null @@ -1 +0,0 @@ -import './index-hermes.js'; diff --git a/packages/ses/src/lockdown-hermes.js b/packages/ses/src/lockdown-hermes.js deleted file mode 100644 index 107b5d08a5..0000000000 --- a/packages/ses/src/lockdown-hermes.js +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright (C) 2018 Agoric -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// @ts-check - -import { getEnvironmentOption as getenv } from '@endo/env-options'; -import { - FERAL_FUNCTION, - FERAL_EVAL, - TypeError, - arrayFilter, - globalThis, - is, - ownKeys, - stringSplit, - noEvalEvaluate, - getOwnPropertyNames, - getPrototypeOf, -} from './commons.js'; -import { makeHardener } from './make-hardener.js'; -import { makeIntrinsicsCollector } from './intrinsics.js'; -import whitelistIntrinsics from './permits-intrinsics.js'; -import tameFunctionConstructors from './tame-function-constructors.js'; -import tameDateConstructor from './tame-date-constructor.js'; -import tameMathObject from './tame-math-object.js'; -import tameRegExpConstructor from './tame-regexp-constructor.js'; -import enablePropertyOverrides from './enable-property-overrides.js'; -import tameLocaleMethods from './tame-locale-methods.js'; -import { - setGlobalObjectConstantProperties, - setGlobalObjectMutableProperties, - setGlobalObjectEvaluators, -} from './global-object.js'; -import { makeSafeEvaluator } from './make-safe-evaluator.js'; -import { initialGlobalPropertyNames } from './permits.js'; -import { tameFunctionToString } from './tame-function-tostring.js'; -import { tameDomains } from './tame-domains.js'; - -import { tameConsole } from './error/tame-console.js'; -import tameErrorConstructor from './error/tame-error-constructor.js'; -import { assert, makeAssert } from './error/assert.js'; -import { getAnonymousIntrinsics } from './get-anonymous-intrinsics.js'; -import { makeCompartmentConstructor } from './compartment.js'; -import { tameHarden } from './tame-harden.js'; -import { tameSymbolConstructor } from './tame-symbol-constructor.js'; -import { tameFauxDataProperties } from './tame-faux-data-properties.js'; - -/** @import {LockdownOptions} from '../types.js' */ - -const { Fail, details: d, quote: q } = assert; - -/** @type {Error=} */ -let priorRepairIntrinsics; - -/** @type {Error=} */ -let priorHardenIntrinsics; - -// Build a harden() with an empty fringe. -// Gate it on lockdown. -/** - * @template T - * @param {T} ref - * @returns {T} - */ -const safeHarden = makeHardener(); - -/** - * @callback Transform - * @param {string} source - * @returns {string} - */ - -/** - * @callback CompartmentConstructor - * @param {object} endowments - * @param {object} moduleMap - * @param {object} [options] - * @param {Array} [options.transforms] - * @param {Array} [options.__shimTransforms__] - */ - -// TODO https://github.com/endojs/endo/issues/814 -// Lockdown currently allows multiple calls provided that the specified options -// of every call agree. With experience, we have observed that lockdown should -// only ever need to be called once and that simplifying lockdown will improve -// the quality of audits. - -const assertDirectEvalAvailable = () => { - let allowed = false; - try { - allowed = FERAL_FUNCTION( - 'eval', - 'SES_changed', - `\ - eval("SES_changed = true"); - return SES_changed; - `, - )(FERAL_EVAL, false); - // If we get here and SES_changed stayed false, that means the eval was sloppy - // and indirect, which generally creates a new global. - // We are going to throw an exception for failing to initialize SES, but - // good neighbors clean up. - if (!allowed) { - delete globalThis.SES_changed; - } - } catch (_error) { - // We reach here if eval is outright forbidden by a Content Security Policy. - // We allow this for SES usage that delegates the responsibility to isolate - // guest code to production code generation. - allowed = true; - } - if (!allowed) { - // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_DIRECT_EVAL.md - throw TypeError( - `SES cannot initialize unless 'eval' is the original intrinsic 'eval', suitable for direct-eval (dynamically scoped eval) (SES_DIRECT_EVAL)`, - ); - } -}; - -/** - * @param {LockdownOptions} [options] - */ -export const repairIntrinsics = (options = {}) => { - // First time, absent options default to 'safe'. - // Subsequent times, absent options default to first options. - // Thus, all present options must agree with first options. - // Reconstructing `option` here also ensures that it is a well - // behaved record, with only own data properties. - // - // The `overrideTaming` is not a safety issue. Rather it is a tradeoff - // between code compatibility, which is better with the `'moderate'` - // setting, and tool compatibility, which is better with the `'min'` - // setting. See - // https://github.com/Agoric/SES-shim/blob/master/packages/ses/README.md#enabling-override-by-assignment) - // for an explanation of when to use which. - // - // The `stackFiltering` is not a safety issue. Rather it is a tradeoff - // between relevance and completeness of the stack frames shown on the - // console. Setting`stackFiltering` to `'verbose'` applies no filters, providing - // the raw stack frames that can be quite versbose. Setting - // `stackFrameFiltering` to`'concise'` limits the display to the stack frame - // information most likely to be relevant, eliminating distracting frames - // such as those from the infrastructure. However, the bug you're trying to - // track down might be in the infrastrure, in which case the `'verbose'` setting - // is useful. See - // [`stackFiltering` options](https://github.com/Agoric/SES-shim/blob/master/packages/ses/docs/lockdown.md#stackfiltering-options) - // for an explanation. - - const { - errorTaming = getenv('LOCKDOWN_ERROR_TAMING', 'safe'), - errorTrapping = /** @type {"platform" | "none" | "report" | "abort" | "exit" | undefined} */ ( - getenv('LOCKDOWN_ERROR_TRAPPING', 'platform') - ), - unhandledRejectionTrapping = /** @type {"none" | "report" | undefined} */ ( - getenv('LOCKDOWN_UNHANDLED_REJECTION_TRAPPING', 'report') - ), - regExpTaming = getenv('LOCKDOWN_REGEXP_TAMING', 'safe'), - localeTaming = getenv('LOCKDOWN_LOCALE_TAMING', 'safe'), - - consoleTaming = /** @type {'unsafe' | 'safe' | undefined} */ ( - getenv('LOCKDOWN_CONSOLE_TAMING', 'safe') - ), - overrideTaming = getenv('LOCKDOWN_OVERRIDE_TAMING', 'moderate'), - stackFiltering = getenv('LOCKDOWN_STACK_FILTERING', 'concise'), - domainTaming = getenv('LOCKDOWN_DOMAIN_TAMING', 'safe'), - evalTaming = getenv('LOCKDOWN_EVAL_TAMING', 'safeEval'), - overrideDebug = arrayFilter( - stringSplit(getenv('LOCKDOWN_OVERRIDE_DEBUG', ''), ','), - /** @param {string} debugName */ - debugName => debugName !== '', - ), - __hardenTaming__ = getenv('LOCKDOWN_HARDEN_TAMING', 'safe'), - dateTaming = 'safe', // deprecated - mathTaming = 'safe', // deprecated - ...extraOptions - } = options; - - evalTaming === 'unsafeEval' || - evalTaming === 'safeEval' || - evalTaming === 'noEval' || - Fail`lockdown(): non supported option evalTaming: ${q(evalTaming)}`; - - // Assert that only supported options were passed. - // Use Reflect.ownKeys to reject symbol-named properties as well. - const extraOptionsNames = ownKeys(extraOptions); - extraOptionsNames.length === 0 || - Fail`lockdown(): non supported option ${q(extraOptionsNames)}`; - - priorRepairIntrinsics === undefined || - // eslint-disable-next-line @endo/no-polymorphic-call - assert.fail( - d`Already locked down at ${priorRepairIntrinsics} (SES_ALREADY_LOCKED_DOWN)`, - TypeError, - ); - // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_ALREADY_LOCKED_DOWN.md - priorRepairIntrinsics = TypeError('Prior lockdown (SES_ALREADY_LOCKED_DOWN)'); - // Tease V8 to generate the stack string and release the closures the stack - // trace retained: - priorRepairIntrinsics.stack; - - assertDirectEvalAvailable(); - - /** - * Because of packagers and bundlers, etc, multiple invocations of lockdown - * might happen in separate instantiations of the source of this module. - * In that case, each one sees its own `firstOptions` variable, so the test - * above will not detect that lockdown has already happened. We - * unreliably test some telltale signs that lockdown has run, to avoid - * trying to lock down a locked down environment. Although the test is - * unreliable, this is consistent with the SES threat model. SES provides - * security only if it runs first in a given realm, or if everything that - * runs before it is SES-aware and cooperative. Neither SES nor anything - * can protect itself from corrupting code that runs first. For these - * purposes, code that turns a realm into something that passes these - * tests without actually locking down counts as corrupting code. - * - * The specifics of what this tests for may change over time, but it - * should be consistent with any setting of the lockdown options. - */ - const seemsToBeLockedDown = () => { - return ( - globalThis.Function.prototype.constructor !== globalThis.Function && - // @ts-ignore harden is absent on globalThis type def. - typeof globalThis.harden === 'function' && - // @ts-ignore lockdown is absent on globalThis type def. - typeof globalThis.lockdown === 'function' && - globalThis.Date.prototype.constructor !== globalThis.Date && - typeof globalThis.Date.now === 'function' && - // @ts-ignore does not recognize that Date constructor is a special - // Function. - // eslint-disable-next-line @endo/no-polymorphic-call - is(globalThis.Date.prototype.constructor.now(), NaN) - ); - }; - - if (seemsToBeLockedDown()) { - // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_MULTIPLE_INSTANCES.md - throw TypeError( - `Already locked down but not by this SES instance (SES_MULTIPLE_INSTANCES)`, - ); - } - - /** - * 1. TAME powers & gather intrinsics first. - */ - - tameDomains(domainTaming); - - // Replace Function.prototype.toString with one that recognizes - // shimmed functions as honorary native functions. - const markVirtualizedNativeFunction = tameFunctionToString(); - - const { addIntrinsics, completePrototypes, finalIntrinsics } = - makeIntrinsicsCollector(); - - const tamedHarden = tameHarden(safeHarden, __hardenTaming__); - addIntrinsics({ harden: tamedHarden }); - - addIntrinsics(tameFunctionConstructors()); - - addIntrinsics(tameDateConstructor(dateTaming)); - addIntrinsics(tameErrorConstructor(errorTaming, stackFiltering)); - addIntrinsics(tameMathObject(mathTaming)); - addIntrinsics(tameRegExpConstructor(regExpTaming)); - addIntrinsics(tameSymbolConstructor()); - - addIntrinsics(getAnonymousIntrinsics()); - - completePrototypes(); - - const intrinsics = finalIntrinsics(); - - const hostIntrinsics = { __proto__: null }; - - // The Node.js Buffer is a derived class of Uint8Array, and as such is often - // passed around where a Uint8Array is expected. - if (typeof globalThis.Buffer === 'function') { - hostIntrinsics.Buffer = globalThis.Buffer; - } - - /** - * Wrap console unless suppressed. - * At the moment, the console is considered a host power in the start - * compartment, and not a primordial. Hence it is absent from the whilelist - * and bypasses the intrinsicsCollector. - * - * @type {((error: any) => string | undefined) | undefined} - */ - let optGetStackString; - if (errorTaming !== 'unsafe') { - optGetStackString = intrinsics['%InitialGetStackString%']; - } - const consoleRecord = tameConsole( - consoleTaming, - errorTrapping, - unhandledRejectionTrapping, - optGetStackString, - ); - globalThis.console = /** @type {Console} */ (consoleRecord.console); - - // The untamed Node.js console cannot itself be hardened as it has mutable - // internal properties, but some of these properties expose internal versions - // of classes from node's "primordials" concept. - // eslint-disable-next-line no-underscore-dangle - if (typeof (/** @type {any} */ (consoleRecord.console)._times) === 'object') { - // SafeMap is a derived Map class used internally by Node - // There doesn't seem to be a cleaner way to reach it. - hostIntrinsics.SafeMap = getPrototypeOf( - // eslint-disable-next-line no-underscore-dangle - /** @type {any} */ (consoleRecord.console)._times, - ); - } - - // @ts-ignore assert is absent on globalThis type def. - if (errorTaming === 'unsafe' && globalThis.assert === assert) { - // If errorTaming is 'unsafe' we replace the global assert with - // one whose `details` template literal tag does not redact - // unmarked substitution values. IOW, it blabs information that - // was supposed to be secret from callers, as an aid to debugging - // at a further cost in safety. - // @ts-ignore assert is absent on globalThis type def. - globalThis.assert = makeAssert(undefined, true); - } - - // Replace *Locale* methods with their non-locale equivalents - tameLocaleMethods(intrinsics, localeTaming); - - tameFauxDataProperties(intrinsics); - - /** - * 2. WHITELIST to standardize the environment. - */ - - // Remove non-standard properties. - // All remaining function encountered during whitelisting are - // branded as honorary native functions. - whitelistIntrinsics(intrinsics, markVirtualizedNativeFunction); - - // Initialize the powerful initial global, i.e., the global of the - // start compartment, from the intrinsics. - - setGlobalObjectConstantProperties(globalThis); - - setGlobalObjectMutableProperties(globalThis, { - intrinsics, - newGlobalPropertyNames: initialGlobalPropertyNames, - makeCompartmentConstructor, - markVirtualizedNativeFunction, - }); - - if (evalTaming === 'noEval') { - setGlobalObjectEvaluators( - globalThis, - noEvalEvaluate, - markVirtualizedNativeFunction, - ); - } else if (evalTaming === 'safeEval') { - const { safeEvaluate } = makeSafeEvaluator({ globalObject: globalThis }); - setGlobalObjectEvaluators( - globalThis, - safeEvaluate, - markVirtualizedNativeFunction, - ); - } else if (evalTaming === 'unsafeEval') { - // Leave eval function and Function constructor of the initial compartment in-tact. - // Other compartments will not have access to these evaluators unless a guest program - // escapes containment. - } - - /** - * 3. HARDEN to share the intrinsics. - * - * We define hardenIntrinsics here so that options are in scope, but return - * it to the caller because we intend to eventually allow vetted shims to run - * between repairs and the hardening of intrinsics and so we can benchmark - * repair separately from hardening. - */ - - const hardenIntrinsics = () => { - priorHardenIntrinsics === undefined || - // eslint-disable-next-line @endo/no-polymorphic-call - assert.fail( - d`Already locked down at ${priorHardenIntrinsics} (SES_ALREADY_LOCKED_DOWN)`, - TypeError, - ); - // See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_ALREADY_LOCKED_DOWN.md - priorHardenIntrinsics = TypeError( - 'Prior lockdown (SES_ALREADY_LOCKED_DOWN)', - ); - // Tease V8 to generate the stack string and release the closures the stack - // trace retained: - priorHardenIntrinsics.stack; - - // Circumvent the override mistake. - // TODO consider moving this to the end of the repair phase, and - // therefore before vetted shims rather than afterwards. It is not - // clear yet which is better. - // @ts-ignore enablePropertyOverrides does its own input validation - enablePropertyOverrides(intrinsics, overrideTaming, overrideDebug); - - // Finally register and optionally freeze all the intrinsics. This - // must be the operation that modifies the intrinsics. - const toHarden = { - intrinsics, - hostIntrinsics, - globals: { - // Harden evaluators - Function: globalThis.Function, - eval: globalThis.eval, - // @ts-ignore Compartment does exist on globalThis - Compartment: globalThis.Compartment, - - // Harden Symbol - Symbol: globalThis.Symbol, - }, - }; - - // Harden Symbol and properties for initialGlobalPropertyNames in the host realm - for (const prop of getOwnPropertyNames(initialGlobalPropertyNames)) { - toHarden.globals[prop] = globalThis[prop]; - } - - tamedHarden(toHarden); - - return tamedHarden; - }; - - return hardenIntrinsics; -}; diff --git a/packages/ses/src/lockdown-shim-hermes.js b/packages/ses/src/lockdown-shim-hermes.js deleted file mode 100644 index c3ec5da104..0000000000 --- a/packages/ses/src/lockdown-shim-hermes.js +++ /dev/null @@ -1,37 +0,0 @@ -// @ts-check - -// We import this first to fail as fast as possible if the shim has been -// transformed or embedded in a way that causes it to run in sloppy mode. -// See https://github.com/endojs/endo/blob/master/packages/ses/error-codes/SES_NO_SLOPPY.md -import './assert-sloppy-mode.js'; -import { globalThis } from './commons.js'; -import { repairIntrinsics } from './lockdown-hermes.js'; - -/** @import {LockdownOptions} from '../types.js' */ - -/** - * @param {LockdownOptions} options - */ -globalThis.lockdown = options => { - const hardenIntrinsics = repairIntrinsics(options); - globalThis.harden = hardenIntrinsics(); -}; - -/** - * @param {LockdownOptions} options - */ -globalThis.repairIntrinsics = options => { - const hardenIntrinsics = repairIntrinsics(options); - // Reveal hardenIntrinsics after repairs. - globalThis.hardenIntrinsics = () => { - // Reveal harden after hardenIntrinsics. - // Harden is dangerous before hardenIntrinsics because hardening just - // about anything will inadvertently render intrinsics irreparable. - // Also, for modules that must work both before or after lockdown (code - // that is portable between JS and SES), the existence of harden in global - // scope signals whether such code should attempt to use harden in the - // defense of its own API. - // @ts-ignore harden not yet recognized on globalThis. - globalThis.harden = hardenIntrinsics(); - }; -}; From 50780cb5d986555216c613526f33d7eee3046990 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:09:27 +0100 Subject: [PATCH 018/115] refactor(ses): remove stale comment No further changes needed to uniqueGlobalPropertyNames --- packages/ses/src/permits.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index bc7205d218..c820d70d02 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1633,11 +1633,6 @@ try { '@@asyncDispose': false, }, }); - - // assign(uniqueGlobalPropertyNames, { - // // https://github.com/tc39/proposal-async-iterator-helpers - // AsyncIterator: 'AsyncIterator', - // }); } catch { // } From a5ff96bb5e92f6831a30516c6eed4e57b97ad109 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:43:43 +0100 Subject: [PATCH 019/115] refactor(ses): improve try/catch comments (catch) Indicate we're dealing with an expected Hermes error at runtime --- packages/ses/src/get-anonymous-intrinsics.js | 1 + packages/ses/src/permits.js | 2 +- packages/ses/src/tame-function-constructors.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 5c4825d540..681f6e28e6 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -142,6 +142,7 @@ export const getAnonymousIntrinsics = () => { '%AsyncIteratorPrototype%': AsyncIteratorPrototype, }); } catch { + // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime // } diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index c820d70d02..2be83a145c 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1634,5 +1634,5 @@ try { }, }); } catch { - // + // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime } diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index b73dd539b5..90a6b86cff 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -135,7 +135,7 @@ export default function tameFunctionConstructors() { '(async function*(){})', ); } catch { - // + // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime } return newIntrinsics; From 2066510863ba4193780163208cc138ff9bd5fcfc Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:58:50 +0100 Subject: [PATCH 020/115] refactor(ses): revert tests --- packages/ses/test/harden.test.js | 3 +++ packages/ses/test/ses.test.js | 9 ++++++++- packages/ses/test/tame-function-unit.test.js | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/ses/test/harden.test.js b/packages/ses/test/harden.test.js index b20d342948..d4ba4297ca 100644 --- a/packages/ses/test/harden.test.js +++ b/packages/ses/test/harden.test.js @@ -25,6 +25,9 @@ test('Compartment anonymous intrinsics are frozen', t => { t.throws(() => c.evaluate('(async function() {}).constructor.a = 10;'), { instanceOf: TypeError, }); + t.throws(() => c.evaluate('(async function*() {}).constructor.a = 10;'), { + instanceOf: TypeError, + }); t.throws(() => c.evaluate('(function*() {}).constructor.a = 10;'), { instanceOf: TypeError, }); diff --git a/packages/ses/test/ses.test.js b/packages/ses/test/ses.test.js index c3637ebf75..dc654beaf8 100644 --- a/packages/ses/test/ses.test.js +++ b/packages/ses/test/ses.test.js @@ -6,7 +6,7 @@ lockdown(); /* eslint-disable no-proto, no-empty-function */ test('tamed constructors', t => { - t.plan(10); + t.plan(12); function F() {} t.throws(() => F.__proto__.constructor(''), { instanceOf: TypeError }); @@ -17,6 +17,9 @@ test('tamed constructors', t => { function* G() {} t.throws(() => G.__proto__.constructor(''), { instanceOf: TypeError }); + async function* AG() {} + t.throws(() => AG.__proto__.constructor(''), { instanceOf: TypeError }); + t.throws(() => Error.__proto__.constructor(''), { instanceOf: TypeError }); t.throws(() => Function.prototype.constructor(''), { instanceOf: TypeError }); @@ -39,6 +42,10 @@ test('tamed constructors', t => { t.throws(() => c.evaluate("function* G() {}; G.__proto__.constructor('')"), { instanceOf: TypeError, }); + t.throws( + () => c.evaluate("async function* AG() {}; AG.__proto__.constructor('')"), + { instanceOf: TypeError }, + ); }); test('frozen', t => { diff --git a/packages/ses/test/tame-function-unit.test.js b/packages/ses/test/tame-function-unit.test.js index 23b919000c..8445b6d1f5 100644 --- a/packages/ses/test/tame-function-unit.test.js +++ b/packages/ses/test/tame-function-unit.test.js @@ -48,3 +48,19 @@ test('GeneratorFunction.constructor', t => { } } }); + +test('AsyncGeneratorFunction.constructor', t => { + t.plan(1); + + try { + // eslint-disable-next-line no-eval + const proto = Object.getPrototypeOf((0, eval)('(async function* () {})')); + t.throws(() => proto.constructor(''), { instanceOf: TypeError }); + } catch (e) { + if (e instanceof SyntaxError) { + t.pass('not supported'); + } else { + throw e; + } + } +}); From b674db01bcd7f6fbcfaeacca734d23196b172ce8 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:55:03 +0100 Subject: [PATCH 021/115] refactor(ses): remove comment --- packages/ses/src/get-anonymous-intrinsics.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 681f6e28e6..017bbb02ef 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -143,7 +143,6 @@ export const getAnonymousIntrinsics = () => { }); } catch { // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime - // } if (globalThis.Iterator) { From 1c527867002e42299b483127624240bb86ba09be Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:35:52 +0100 Subject: [PATCH 022/115] refactor(ses): get-anonymous-intrinsics try/catch Co-authored-by: Kris Kowal --- packages/ses/src/get-anonymous-intrinsics.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 017bbb02ef..14f3ff4e67 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -118,13 +118,20 @@ export const getAnonymousIntrinsics = () => { '%InertCompartment%': InertCompartment, }; + // Test for support async generator function syntax. + let AsyncGeneratorFunctionInstance; try { - // 25.3.1 The AsyncGeneratorFunction Constructor - // eslint-disable-next-line no-empty-function - const AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( + AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); + } catch { + // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime + } + + if (AsyncGeneratorFunctionInstance !== undefined) { + // 25.3.1 The AsyncGeneratorFunction Constructor + const AsyncGeneratorFunction = getConstructorOf( AsyncGeneratorFunctionInstance, ); @@ -141,8 +148,6 @@ export const getAnonymousIntrinsics = () => { '%AsyncGeneratorPrototype%': AsyncGeneratorPrototype, '%AsyncIteratorPrototype%': AsyncIteratorPrototype, }); - } catch { - // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime } if (globalThis.Iterator) { From f66bf785ab677c72a976fa3e3e8d9a03bebd828f Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:21:10 +0100 Subject: [PATCH 023/115] fix(ses): lint --- packages/ses/src/get-anonymous-intrinsics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 14f3ff4e67..2835e698d7 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -128,8 +128,8 @@ export const getAnonymousIntrinsics = () => { } catch { // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime } - - if (AsyncGeneratorFunctionInstance !== undefined) { + + if (AsyncGeneratorFunctionInstance !== undefined) { // 25.3.1 The AsyncGeneratorFunction Constructor const AsyncGeneratorFunction = getConstructorOf( From a017db089c1d18b09fe4ae22364d328eab6335a8 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:36:40 +0100 Subject: [PATCH 024/115] refactor(ses): restore permits.js - condition not needed - permits.js naming something that doesn't exist is fine --- packages/ses/src/permits.js | 94 ++++++++++++------------------------- 1 file changed, 29 insertions(+), 65 deletions(-) diff --git a/packages/ses/src/permits.js b/packages/ses/src/permits.js index 2be83a145c..d364501067 100644 --- a/packages/ses/src/permits.js +++ b/packages/ses/src/permits.js @@ -1,7 +1,7 @@ /* eslint-disable no-restricted-globals */ /* eslint max-lines: 0 */ -import { arrayPush, assign, FERAL_FUNCTION } from './commons.js'; +import { arrayPush } from './commons.js'; /** @import {GenericErrorConstructor} from '../types.js' */ @@ -1430,6 +1430,24 @@ export const permitted = { '@@toStringTag': 'string', }, + '%InertAsyncGeneratorFunction%': { + // Properties of the AsyncGeneratorFunction Constructor + '[[Proto]]': '%InertFunction%', + prototype: '%AsyncGenerator%', + }, + + '%AsyncGenerator%': { + // Properties of the AsyncGeneratorFunction Prototype Object + '[[Proto]]': '%FunctionPrototype%', + constructor: '%InertAsyncGeneratorFunction%', + prototype: '%AsyncGeneratorPrototype%', + // length prop added here for React Native jsc-android + // https://github.com/endojs/endo/issues/660 + // https://github.com/react-native-community/jsc-android-buildscripts/issues/181 + length: 'number', + '@@toStringTag': 'string', + }, + '%GeneratorPrototype%': { // Properties of the Generator Prototype Object '[[Proto]]': '%IteratorPrototype%', @@ -1440,6 +1458,16 @@ export const permitted = { '@@toStringTag': 'string', }, + '%AsyncGeneratorPrototype%': { + // Properties of the AsyncGenerator Prototype Object + '[[Proto]]': '%AsyncIteratorPrototype%', + constructor: '%AsyncGenerator%', + next: fn, + return: fn, + throw: fn, + '@@toStringTag': 'string', + }, + // TODO: To be replaced with Promise.delegate // // The HandledPromise global variable shimmed by `@agoric/eventual-send/shim` @@ -1572,67 +1600,3 @@ export const permitted = { '%InitialGetStackString%': fn, }; - -try { - new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); - assign(permitted, { - '%InertAsyncGeneratorFunction%': { - // Properties of the AsyncGeneratorFunction Constructor - '[[Proto]]': '%InertFunction%', - prototype: '%AsyncGenerator%', - }, - - '%AsyncGenerator%': { - // Properties of the AsyncGeneratorFunction Prototype Object - '[[Proto]]': '%FunctionPrototype%', - constructor: '%InertAsyncGeneratorFunction%', - prototype: '%AsyncGeneratorPrototype%', - // length prop added here for React Native jsc-android - // https://github.com/endojs/endo/issues/660 - // https://github.com/react-native-community/jsc-android-buildscripts/issues/181 - length: 'number', - '@@toStringTag': 'string', - }, - - '%AsyncGeneratorPrototype%': { - // Properties of the AsyncGenerator Prototype Object - '[[Proto]]': '%AsyncIteratorPrototype%', - constructor: '%AsyncGenerator%', - next: fn, - return: fn, - throw: fn, - '@@toStringTag': 'string', - }, - - // https://github.com/tc39/proposal-async-iterator-helpers - AsyncIterator: { - // Properties of the Iterator Constructor - '[[Proto]]': '%FunctionPrototype%', - prototype: '%AsyncIteratorPrototype%', - from: fn, - }, - - '%AsyncIteratorPrototype%': { - // The %AsyncIteratorPrototype% Object - '@@asyncIterator': fn, - // https://github.com/tc39/proposal-async-iterator-helpers - constructor: 'AsyncIterator', - map: fn, - filter: fn, - take: fn, - drop: fn, - flatMap: fn, - reduce: fn, - toArray: fn, - forEach: fn, - some: fn, - every: fn, - find: fn, - '@@toStringTag': 'string', - // See https://github.com/Moddable-OpenSource/moddable/issues/523#issuecomment-1942904505 - '@@asyncDispose': false, - }, - }); -} catch { - // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime -} From e40555cee0b7aaf141969db06a4b840fa32a043b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 22 Jul 2024 20:02:23 +0100 Subject: [PATCH 025/115] feat(ses): console.info when skipping async generators --- packages/ses/src/get-anonymous-intrinsics.js | 4 +++- packages/ses/src/tame-function-constructors.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 2835e698d7..0a6905fcb8 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -126,7 +126,9 @@ export const getAnonymousIntrinsics = () => { 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); } catch { - // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime + // Swallows Hermes SyntaxError `async generators are unsupported` at runtime. + // eslint-disable-next-line @endo/no-polymorphic-call + console.info('skipping async generators'); } if (AsyncGeneratorFunctionInstance !== undefined) { diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 90a6b86cff..12f5755b75 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -135,7 +135,9 @@ export default function tameFunctionConstructors() { '(async function*(){})', ); } catch { - // Silently swallow Hermes SyntaxError `async generators are unsupported` at runtime + // Swallows Hermes SyntaxError `async generators are unsupported` at runtime. + // eslint-disable-next-line @endo/no-polymorphic-call + console.info('skipping async generators'); } return newIntrinsics; From 8c9031aa57f6f355e12071d68bcb18beebdcb766 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 22 Jul 2024 20:03:54 +0100 Subject: [PATCH 026/115] feat(ses): improve console.info when skipping async generators --- packages/ses/src/get-anonymous-intrinsics.js | 2 +- packages/ses/src/tame-function-constructors.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 0a6905fcb8..c8de10f29b 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -128,7 +128,7 @@ export const getAnonymousIntrinsics = () => { } catch { // Swallows Hermes SyntaxError `async generators are unsupported` at runtime. // eslint-disable-next-line @endo/no-polymorphic-call - console.info('skipping async generators'); + console.info('getAnonymousIntrinsics: skipping async generators'); } if (AsyncGeneratorFunctionInstance !== undefined) { diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 12f5755b75..7a6f318b87 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -137,7 +137,7 @@ export default function tameFunctionConstructors() { } catch { // Swallows Hermes SyntaxError `async generators are unsupported` at runtime. // eslint-disable-next-line @endo/no-polymorphic-call - console.info('skipping async generators'); + console.info('tameFunctionConstructors: skipping async generators'); } return newIntrinsics; From 0ecf0b894b994745d31de388ea843d2f14f779a6 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 22 Jul 2024 20:34:29 +0100 Subject: [PATCH 027/115] refactor(ses): remove eslint-disable --- packages/ses/src/get-anonymous-intrinsics.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index c8de10f29b..533d6a35d3 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -121,7 +121,6 @@ export const getAnonymousIntrinsics = () => { // Test for support async generator function syntax. let AsyncGeneratorFunctionInstance; try { - // eslint-disable-next-line no-empty-function AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); From 4b1b5e672477a7305e97601fcad26d48c186d141 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:40:10 +0100 Subject: [PATCH 028/115] feat(ses): add AsyncGeneratorFunctionInstance to commons --- packages/ses/src/commons.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index 5028a7f572..d72fe27790 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -360,3 +360,25 @@ export const FERAL_STACK_GETTER = feralStackGetter; * @type {((newValue: any) => void) | undefined} */ export const FERAL_STACK_SETTER = feralStackSetter; + +// Test for async generator function syntax support. +let AsyncGeneratorNewFunctionInstance; +try { + // Wrapping one in an new Function lets the `hermesc` binary file + // parse the Metro js bundle without SyntaxError, to generate the + // optimised Hermes bytecode bundle, when `gradlew` is called to + // assemble the release build APK for React Native prod Android apps. + // Delaying the error until runtime lets us customise lockdown behaviour. + AsyncGeneratorNewFunctionInstance = new FERAL_FUNCTION( + 'return (async function* AsyncGeneratorFunctionInstance() {})', + )(); +} catch (e) { + if (e.name === 'SyntaxError') { + // Swallows Hermes error `async generators are unsupported` at runtime. + // eslint-disable-next-line @endo/no-polymorphic-call + console.info('skipping async generators'); + } else { + throw e; + } +} +export const AsyncGeneratorFunctionInstance = AsyncGeneratorNewFunctionInstance; From 2c76a2b29d9eee00e8de1b6efec579c0d95fd57c Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:14:37 +0100 Subject: [PATCH 029/115] refactor(ses): use AsyncGeneratorFunctionInstance from commons --- packages/ses/src/get-anonymous-intrinsics.js | 14 ++------------ packages/ses/src/tame-function-constructors.js | 9 +++------ 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index 533d6a35d3..e4e9028470 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -15,6 +15,7 @@ import { regexpPrototype, globalThis, assign, + AsyncGeneratorFunctionInstance, } from './commons.js'; import { InertCompartment } from './compartment.js'; @@ -118,18 +119,7 @@ export const getAnonymousIntrinsics = () => { '%InertCompartment%': InertCompartment, }; - // Test for support async generator function syntax. - let AsyncGeneratorFunctionInstance; - try { - AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( - 'return (async function* AsyncGeneratorFunctionInstance() {})', - )(); - } catch { - // Swallows Hermes SyntaxError `async generators are unsupported` at runtime. - // eslint-disable-next-line @endo/no-polymorphic-call - console.info('getAnonymousIntrinsics: skipping async generators'); - } - + // Test for async generator function syntax support. if (AsyncGeneratorFunctionInstance !== undefined) { // 25.3.1 The AsyncGeneratorFunction Constructor diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 7a6f318b87..956a06214c 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -6,6 +6,7 @@ import { getPrototypeOf, setPrototypeOf, freeze, + AsyncGeneratorFunctionInstance, } from './commons.js'; // This module replaces the original `Function` constructor, and the original @@ -127,17 +128,13 @@ export default function tameFunctionConstructors() { '(async function(){})', ); - try { - new FERAL_FUNCTION('async function* AsyncGeneratorFunctionInstance() {}')(); + // Test for async generator function syntax support. + if (AsyncGeneratorFunctionInstance !== undefined) { repairFunction( 'AsyncGeneratorFunction', '%InertAsyncGeneratorFunction%', '(async function*(){})', ); - } catch { - // Swallows Hermes SyntaxError `async generators are unsupported` at runtime. - // eslint-disable-next-line @endo/no-polymorphic-call - console.info('tameFunctionConstructors: skipping async generators'); } return newIntrinsics; From a5aedbe73141dbf70fd46ab8b8b70be68a86ae19 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:20:24 +0100 Subject: [PATCH 030/115] refactor(ses): remove dupe comments --- packages/ses/src/get-anonymous-intrinsics.js | 1 - packages/ses/src/tame-function-constructors.js | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/ses/src/get-anonymous-intrinsics.js b/packages/ses/src/get-anonymous-intrinsics.js index e4e9028470..41fd9d1a2a 100644 --- a/packages/ses/src/get-anonymous-intrinsics.js +++ b/packages/ses/src/get-anonymous-intrinsics.js @@ -119,7 +119,6 @@ export const getAnonymousIntrinsics = () => { '%InertCompartment%': InertCompartment, }; - // Test for async generator function syntax support. if (AsyncGeneratorFunctionInstance !== undefined) { // 25.3.1 The AsyncGeneratorFunction Constructor diff --git a/packages/ses/src/tame-function-constructors.js b/packages/ses/src/tame-function-constructors.js index 956a06214c..402b1b3b82 100644 --- a/packages/ses/src/tame-function-constructors.js +++ b/packages/ses/src/tame-function-constructors.js @@ -128,7 +128,6 @@ export default function tameFunctionConstructors() { '(async function(){})', ); - // Test for async generator function syntax support. if (AsyncGeneratorFunctionInstance !== undefined) { repairFunction( 'AsyncGeneratorFunction', From 6c1b4458c336ec70dfdf72b0ac7d06f1983817dc Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:45:38 +0100 Subject: [PATCH 031/115] refactor(ses): asyncTrampoline as standard async fn for Hermes --- packages/ses/src/module-load.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/module-load.js b/packages/ses/src/module-load.js index 881cf390b6..5b19380849 100644 --- a/packages/ses/src/module-load.js +++ b/packages/ses/src/module-load.js @@ -25,7 +25,7 @@ import { makeError, annotateError, q, X } from './error/assert.js'; const noop = () => {}; -const asyncTrampoline = async (generatorFunc, args, errorWrapper) => { +async function asyncTrampoline(generatorFunc, args, errorWrapper) { await null; const iterator = generatorFunc(...args); let result = generatorNext(iterator); @@ -39,7 +39,7 @@ const asyncTrampoline = async (generatorFunc, args, errorWrapper) => { } } return result.value; -}; +} const syncTrampoline = (generatorFunc, args) => { const iterator = generatorFunc(...args); From 375c01b413473c6ce7fa2dcf36a02f61fd7952a7 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:03:48 +0100 Subject: [PATCH 032/115] test(ses): add hermes smoke test --- packages/ses/test/hermes-smoke.js | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 packages/ses/test/hermes-smoke.js diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js new file mode 100644 index 0000000000..7f786b6f02 --- /dev/null +++ b/packages/ses/test/hermes-smoke.js @@ -0,0 +1,42 @@ +import '../dist/ses.cjs'; +import '../src/assert-shim.js'; + +// Test lockdown + +lockdown(); + +// Test Compartment + +const c = new Compartment(); + +c.evaluate('1+1'); +c.evaluate("const c2 = new Compartment(); c2.evaluate('1+2')"); + +// Test importHook and resolveHook (non-ESM) + +// https://github.com/facebook/hermes/blob/main/doc/Features.md +// In Progress: ES modules (`import` and `export`) + +const resolveHook = ''; + +const importHook = async () => { + return { + imports: [], + exports: ['meaning'], + execute(exports) { + exports.meaning = 42; + }, + }; +}; + +const compartment = new Compartment({}, {}, { resolveHook, importHook }); + +const module = compartment.module('.'); + +const { + namespace: { meaning }, +} = await compartment.import('.'); + +assert(module); +// t.is(meaning, 42, 'exports seen'); +// t.is(module.meaning, 42, 'exports seen through deferred proxy'); From bb2c2c85eda44508ba477e892bd825b1926b318d Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:06:49 +0100 Subject: [PATCH 033/115] test(ses): add hermes compiler test script --- packages/ses/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index e562a123e7..7242374391 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -73,7 +73,8 @@ "prepare": "npm run clean && npm run build", "qt": "ava", "test": "tsd && ava", - "test:platform-compatibility": "node test/package/test.cjs" + "test:platform-compatibility": "node test/package/test.cjs", + "test:hermesc": "cd hermes && ./hermesc -emit-binary -out hermes-smoke.hbc ../test/hermes-smoke.js" }, "dependencies": { "@endo/env-options": "^1.1.4" From 61123b1c022a1100383d06d0e6efe04f4f367fec Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:07:28 +0100 Subject: [PATCH 034/115] test(ses): add hermes runtime test script --- packages/ses/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 7242374391..2b0560c13d 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -74,7 +74,8 @@ "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", - "test:hermesc": "cd hermes && ./hermesc -emit-binary -out hermes-smoke.hbc ../test/hermes-smoke.js" + "test:hermesc": "cd hermes && ./hermesc -emit-binary -out hermes-smoke.hbc ../test/hermes-smoke.js", + "test:hermes": "cd hermes && ./hermes -b hermes-smoke.hbc" }, "dependencies": { "@endo/env-options": "^1.1.4" From d373214273b5ec09b9e31c656c663251994efa7c Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:07:57 +0100 Subject: [PATCH 035/115] test(ses): add hermes-test CI job --- .github/workflows/ci.yml | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a9fe9bdfb..1f8d66fce1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -282,6 +282,59 @@ jobs: # npm b/c Yarn 4 doesn't work in Node 12 run: cd packages/ses && npm run test:platform-compatibility + hermes-test: + name: hermes-test + + # begin macro + + runs-on: ${{ matrix.platform }} + strategy: + fail-fast: false + matrix: + node-version: [18.x, 20.x] + platform: [ubuntu-latest] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + # without this, setup-node errors on mismatched yarn versions + - run: corepack enable + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: yarn + + - name: Echo node version + run: node --version + + - name: Install dependencies + run: yarn install --immutable + + # end macro + + - name: 'build' + run: yarn run build + + - name: Echo node version + run: node --version + + - name: Get Hermes CLI for Linux tar file + run: cd packages/ses; mkdir hermes; cd hermes; curl -O https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz + + - name: Extract tar file + run: tar -xzvf https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz; cd .. + + - name: Run test:hermesc + run: npm run test:hermesc + # errors on async (arrow) functions and async generators + + - name: Run test:hermes + run: npm run test:hermes + # SES TypeErrors expected until resolved and hardenIntrinsics loop + viable-release: name: viable-release From 6909484438a974b4482fe9c59a06b23f6fc96528 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:28:45 +0100 Subject: [PATCH 036/115] fix(ses): format --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f8d66fce1..28fd5f35a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -322,7 +322,7 @@ jobs: run: node --version - name: Get Hermes CLI for Linux tar file - run: cd packages/ses; mkdir hermes; cd hermes; curl -O https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz + run: cd packages/ses; mkdir hermes; cd hermes; curl -O https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz - name: Extract tar file run: tar -xzvf https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz; cd .. From 56a31b046b2a1c5e4a8594295227559cd181b3b8 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:30:28 +0100 Subject: [PATCH 037/115] fix(ses): fix CI tar extraction --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28fd5f35a6..8ad07e00a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -325,7 +325,7 @@ jobs: run: cd packages/ses; mkdir hermes; cd hermes; curl -O https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz - name: Extract tar file - run: tar -xzvf https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz; cd .. + run: tar -xzvf hermes-cli-linux-v0.12.0.tar.gz; cd .. - name: Run test:hermesc run: npm run test:hermesc From d8f35bb471a9194eabde7e5773768cbdca915764 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:36:05 +0100 Subject: [PATCH 038/115] fix(ses): lint --- packages/ses/test/hermes-smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index 7f786b6f02..f6d9e0b857 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -34,7 +34,7 @@ const compartment = new Compartment({}, {}, { resolveHook, importHook }); const module = compartment.module('.'); const { - namespace: { meaning }, + namespace: { _meaning }, } = await compartment.import('.'); assert(module); From 61700f865eaf3fc9ee5cb817576aac3b31085ea6 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:50:49 +0100 Subject: [PATCH 039/115] fix(ses): use wget --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ad07e00a8..d72f743e87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -322,7 +322,7 @@ jobs: run: node --version - name: Get Hermes CLI for Linux tar file - run: cd packages/ses; mkdir hermes; cd hermes; curl -O https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz + run: cd packages/ses; mkdir hermes; cd hermes; wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz - name: Extract tar file run: tar -xzvf hermes-cli-linux-v0.12.0.tar.gz; cd .. From e5560905c080e4231ee76dbbe3b39f277765296e Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:56:09 +0100 Subject: [PATCH 040/115] fix(ses): update CI ';' to '&&' --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d72f743e87..2bcc0cff6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -322,7 +322,7 @@ jobs: run: node --version - name: Get Hermes CLI for Linux tar file - run: cd packages/ses; mkdir hermes; cd hermes; wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz + run: cd packages/ses && mkdir hermes && cd hermes && wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz - name: Extract tar file run: tar -xzvf hermes-cli-linux-v0.12.0.tar.gz; cd .. From 284fbdf7a6fb6202e1d5836e1944e6d0aa52487b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:38:12 +0100 Subject: [PATCH 041/115] refactor(ses): use Node 20 only in CI matrix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bcc0cff6b..4b48c167ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -291,7 +291,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x] + node-version: [20.x] platform: [ubuntu-latest] steps: From dc79e1169d23d63bf45ac1016c819a1851e70681 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:41:37 +0100 Subject: [PATCH 042/115] refactor(ses): remove dupe CI node ver step --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b48c167ff..6e38985596 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,9 +318,6 @@ jobs: - name: 'build' run: yarn run build - - name: Echo node version - run: node --version - - name: Get Hermes CLI for Linux tar file run: cd packages/ses && mkdir hermes && cd hermes && wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz From 62975bee2ca36bc8d8c8facc4c18121c52425041 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:19:33 +0100 Subject: [PATCH 043/115] fix(ses): Hermes CI tar file extract step --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e38985596..13e4eba3a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,11 +318,11 @@ jobs: - name: 'build' run: yarn run build - - name: Get Hermes CLI for Linux tar file - run: cd packages/ses && mkdir hermes && cd hermes && wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz + - name: Fetch Hermes CLI for Linux tar file + run: cd packages/ses && mkdir hermes-cli-linux && cd hermes-cli-linux && wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz - - name: Extract tar file - run: tar -xzvf hermes-cli-linux-v0.12.0.tar.gz; cd .. + - name: Extract Hermes CLI for Linux tar file + run: cd packages/ses/hermes-cli-linux && tar -xzvf hermes-cli-linux-v0.12.0.tar.gz - name: Run test:hermesc run: npm run test:hermesc From 4936b6a2ea25f8ba423952166a3b63507fc64171 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:34:32 +0100 Subject: [PATCH 044/115] fix(ses): Hermes scripts not found --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13e4eba3a7..8416cf0b10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -324,12 +324,12 @@ jobs: - name: Extract Hermes CLI for Linux tar file run: cd packages/ses/hermes-cli-linux && tar -xzvf hermes-cli-linux-v0.12.0.tar.gz - - name: Run test:hermesc - run: npm run test:hermesc + - name: Run SES smoke test on Hermes JS compiler + run: cd packages/ses/hermes-cli-linux && npm run test:hermesc # errors on async (arrow) functions and async generators - - name: Run test:hermes - run: npm run test:hermes + - name: Run generated bytecode file on Hermes VM + run: cd packages/ses/hermes-cli-linux && npm run test:hermes # SES TypeErrors expected until resolved and hardenIntrinsics loop viable-release: From 26921fa0dfe321b7a6e256cc82dc1cff4e1dafc4 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:14:23 +0100 Subject: [PATCH 045/115] fix(ses): Hermes scripts CLI location --- packages/ses/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 2b0560c13d..66abeb91b6 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -74,8 +74,8 @@ "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", - "test:hermesc": "cd hermes && ./hermesc -emit-binary -out hermes-smoke.hbc ../test/hermes-smoke.js", - "test:hermes": "cd hermes && ./hermes -b hermes-smoke.hbc" + "test:hermesc": "cd hermes-cli-linux && ./hermesc -emit-binary -out hermes-smoke.hbc ../test/hermes-smoke.js", + "test:hermes": "cd hermes-cli-linux && ./hermes -b hermes-smoke.hbc" }, "dependencies": { "@endo/env-options": "^1.1.4" From 528236f2d501442f42f085e528a1f271e3439ee5 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 25 Jul 2024 19:27:57 +0100 Subject: [PATCH 046/115] fix(ses): Hermes smoke test --- packages/ses/test/hermes-smoke.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index f6d9e0b857..aba8f8335c 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -1,5 +1,7 @@ -import '../dist/ses.cjs'; -import '../src/assert-shim.js'; +// TODO: equivalent of: +// import '../dist/ses.cjs'; +// import '../src/assert-shim.js'; +// Since Hermes has no native support for I/O // Test lockdown @@ -12,14 +14,14 @@ const c = new Compartment(); c.evaluate('1+1'); c.evaluate("const c2 = new Compartment(); c2.evaluate('1+2')"); -// Test importHook and resolveHook (non-ESM) +// Test importHook and resolveHook // https://github.com/facebook/hermes/blob/main/doc/Features.md // In Progress: ES modules (`import` and `export`) const resolveHook = ''; -const importHook = async () => { +async function importHook() { return { imports: [], exports: ['meaning'], @@ -27,15 +29,15 @@ const importHook = async () => { exports.meaning = 42; }, }; -}; +} const compartment = new Compartment({}, {}, { resolveHook, importHook }); const module = compartment.module('.'); -const { - namespace: { _meaning }, -} = await compartment.import('.'); +// const { +// namespace: { _meaning }, +// } = await compartment.import('.'); assert(module); // t.is(meaning, 42, 'exports seen'); From b02ced10257361cf3f6ea3b975a9c4bd12d3aa44 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:49:29 +0100 Subject: [PATCH 047/115] test(ses): add hermes-engine-cli (v0.12.0) as dev dep --- packages/ses/package.json | 1 + yarn.lock | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/packages/ses/package.json b/packages/ses/package.json index 66abeb91b6..853e6b73eb 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -93,6 +93,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.29.1", + "hermes-engine-cli": "^0.12.0", "prettier": "^3.2.5", "sinon": "^15.1.0", "terser": "^5.16.6", diff --git a/yarn.lock b/yarn.lock index 748bddba0d..43b11b73d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6606,6 +6606,13 @@ __metadata: languageName: node linkType: hard +"hermes-engine-cli@npm:^0.12.0": + version: 0.12.0 + resolution: "hermes-engine-cli@npm:0.12.0" + checksum: 10c0/53a00336632cc7a743e9a88a5199865cf922d118f42f15bed4d2ed2fee635acd0d4d8563803b47e7c1bc2d17650281eb9188be8cfdaa25887243cfee840523be + languageName: node + linkType: hard + "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" @@ -10523,6 +10530,7 @@ __metadata: eslint-config-prettier: "npm:^9.1.0" eslint-plugin-eslint-comments: "npm:^3.2.0" eslint-plugin-import: "npm:^2.29.1" + hermes-engine-cli: "npm:^0.12.0" prettier: "npm:^3.2.5" sinon: "npm:^15.1.0" terser: "npm:^5.16.6" From 48fd5cca540cdb1861ae29e48049a1af20b4862e Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:02:25 +0100 Subject: [PATCH 048/115] test(ses): create shellscript to run hermesc on any OS --- packages/ses/scripts/hermesc.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 packages/ses/scripts/hermesc.sh diff --git a/packages/ses/scripts/hermesc.sh b/packages/ses/scripts/hermesc.sh new file mode 100755 index 0000000000..abf8249edb --- /dev/null +++ b/packages/ses/scripts/hermesc.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +OS="$(uname -s)" + +case "$OS" in + Linux*) + OS_DIR="linux64-bin" + ;; + Darwin*) + OS_DIR="osx-bin" + ;; + CYGWIN*|MINGW*|MSYS*) + OS_DIR="win64-bin" + ;; + *) + echo "Unsupported OS: $OS" + exit 1 + ;; +esac + +HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" + +$HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke.js From 8878833076118cc91eb198abc378e819635a6325 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 31 Jul 2024 18:00:56 +0100 Subject: [PATCH 049/115] test(ses): fix Hermes smoke test resolveHook --- packages/ses/test/hermes-smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index aba8f8335c..6015fc04f2 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -19,7 +19,7 @@ c.evaluate("const c2 = new Compartment(); c2.evaluate('1+2')"); // https://github.com/facebook/hermes/blob/main/doc/Features.md // In Progress: ES modules (`import` and `export`) -const resolveHook = ''; +const resolveHook = (a) => a; async function importHook() { return { From 8bd257ac50110d4bcba2f8f7c619769e75758de3 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 31 Jul 2024 18:01:26 +0100 Subject: [PATCH 050/115] test(ses): update Hermes smoke test --- packages/ses/test/hermes-smoke.js | 97 +++++++++++++++++-------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index 6015fc04f2..8244ba0e89 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -1,44 +1,53 @@ -// TODO: equivalent of: -// import '../dist/ses.cjs'; -// import '../src/assert-shim.js'; -// Since Hermes has no native support for I/O - -// Test lockdown - -lockdown(); - -// Test Compartment - -const c = new Compartment(); - -c.evaluate('1+1'); -c.evaluate("const c2 = new Compartment(); c2.evaluate('1+2')"); - -// Test importHook and resolveHook - -// https://github.com/facebook/hermes/blob/main/doc/Features.md -// In Progress: ES modules (`import` and `export`) - -const resolveHook = (a) => a; - -async function importHook() { - return { - imports: [], - exports: ['meaning'], - execute(exports) { - exports.meaning = 42; - }, - }; -} - -const compartment = new Compartment({}, {}, { resolveHook, importHook }); - -const module = compartment.module('.'); - -// const { -// namespace: { _meaning }, -// } = await compartment.import('.'); - -assert(module); -// t.is(meaning, 42, 'exports seen'); -// t.is(module.meaning, 42, 'exports seen through deferred proxy'); +// Hermes doesn't support native I/O, +// so we concat the SES shim above, +// when running this test on the `hermesc`. + +/** + * Test calling SES lockdown. + */ +const testLockdown = () => { + lockdown(); +}; + +testLockdown(); + +/** + * TODO: Test creating a new Compartment. + */ +// eslint-disable-next-line no-unused-vars +const testCompartment = () => { + // eslint-disable-next-line no-unused-vars + const c = new Compartment(); +}; + +// testCompartment(); + +/** + * TODO: Test Compartment import hook and resolve hook. + */ +// eslint-disable-next-line no-unused-vars +const testCompartmentHooks = async () => { + const resolveHook = a => a; + + async function importHook() { + return { + imports: [], + exports: ['meaning'], + execute(exports) { + exports.meaning = 42; + }, + }; + } + + const compartment = new Compartment({}, {}, { resolveHook, importHook }); + + const module = compartment.module('.'); + + const { + namespace: { _meaning }, + } = await compartment.import('.'); + + assert(module); +}; + +// testCompartmentHooks(); From a6b4ff37f6805e6f26d6e50b56beb5d7bc8146b3 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:58:30 +0100 Subject: [PATCH 051/115] test(ses): add shellscript to setup Hermes .bin symlinks on any OS --- packages/ses/scripts/hermes-bin-symlinks.sh | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100755 packages/ses/scripts/hermes-bin-symlinks.sh diff --git a/packages/ses/scripts/hermes-bin-symlinks.sh b/packages/ses/scripts/hermes-bin-symlinks.sh new file mode 100755 index 0000000000..1dc08b161a --- /dev/null +++ b/packages/ses/scripts/hermes-bin-symlinks.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +OS="$(uname -s)" + +case "$OS" in + Linux*) + OS_DIR="linux64-bin" + ;; + Darwin*) + OS_DIR="osx-bin" + ;; + CYGWIN*|MINGW*|MSYS*) + OS_DIR="win64-bin" + ;; + *) + echo "Unsupported OS: $OS" + exit 1 + ;; +esac + +# Path from 'packages/ses' +cd ../../node_modules/.bin + +if [[ "$OS" == linux* || "$OS" == Darwin* ]]; then + ln -s ../hermes-engine-cli/$OS_DIR/hbcdump hbcdump + ln -s ../hermes-engine-cli/$OS_DIR/hdb hdb + ln -s ../hermes-engine-cli/$OS_DIR/hermes hermes + ln -s ../hermes-engine-cli/$OS_DIR/hermesc hermesc +elif [[ "$OS" == CYGWIN* || "$OS" == MINGW* || "$OS" == MSYS* ]]; then + mklink -s ../hermes-engine-cli/$OS_DIR/hbcdump.exe hbcdump + mklink -s ../hermes-engine-cli/$OS_DIR/hdb.exe hdb + mklink -s ../hermes-engine-cli/$OS_DIR/hermes.exe hermes + mklink -s ../hermes-engine-cli/$OS_DIR/hermesc.exe hermesc +fi From 78ea7c9491f97ed466ac7b61851f5ea1541151f7 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:13:49 +0100 Subject: [PATCH 052/115] test(ses): add hermesc.sh comment --- packages/ses/scripts/hermesc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ses/scripts/hermesc.sh b/packages/ses/scripts/hermesc.sh index abf8249edb..6b4a3d117f 100755 --- a/packages/ses/scripts/hermesc.sh +++ b/packages/ses/scripts/hermesc.sh @@ -18,6 +18,7 @@ case "$OS" in ;; esac +# Path relative to 'packages/ses' HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" $HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke.js From e4f32a16c5820739b12cb9cf62d39c9a232af78f Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:16:29 +0100 Subject: [PATCH 053/115] test(ses): cat ses and test, use in hermesc.sh --- packages/ses/scripts/hermesc.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermesc.sh b/packages/ses/scripts/hermesc.sh index 6b4a3d117f..f239760c23 100755 --- a/packages/ses/scripts/hermesc.sh +++ b/packages/ses/scripts/hermesc.sh @@ -21,4 +21,6 @@ esac # Path relative to 'packages/ses' HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" -$HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke.js +cat dist/ses.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js + +$HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke-dist.js From 887077cc7f3f780e625dae458f1618d3ab94b126 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:20:17 +0100 Subject: [PATCH 054/115] test(ses): format test --- packages/ses/test/hermes-smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index 8244ba0e89..8435b7bceb 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -48,6 +48,6 @@ const testCompartmentHooks = async () => { } = await compartment.import('.'); assert(module); -}; +} // testCompartmentHooks(); From 519ba255f528ae2d966e2af644392cff52e58adc Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:20:59 +0100 Subject: [PATCH 055/115] test(ses): update test async arrow fn to non-arrow --- packages/ses/test/hermes-smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index 8435b7bceb..0dcd297663 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -26,7 +26,7 @@ const testCompartment = () => { * TODO: Test Compartment import hook and resolve hook. */ // eslint-disable-next-line no-unused-vars -const testCompartmentHooks = async () => { +async function testCompartmentHooks() { const resolveHook = a => a; async function importHook() { From b5f8b95493bb7fadc52e92d048aff20eb220ab81 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:27:50 +0100 Subject: [PATCH 056/115] test(ses): update package.json hermesc script to run .sh --- packages/ses/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 853e6b73eb..ce7f8a0770 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -74,7 +74,7 @@ "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", - "test:hermesc": "cd hermes-cli-linux && ./hermesc -emit-binary -out hermes-smoke.hbc ../test/hermes-smoke.js", + "test:hermesc": "./scripts/hermesc.sh", "test:hermes": "cd hermes-cli-linux && ./hermes -b hermes-smoke.hbc" }, "dependencies": { From 6764a40b370bd008b34a02beac9da88686addccd Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:21:28 +0100 Subject: [PATCH 057/115] test(ses): update comment --- packages/ses/test/hermes-smoke.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index 0dcd297663..d65c427096 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -1,6 +1,6 @@ // Hermes doesn't support native I/O, // so we concat the SES shim above, -// when running this test on the `hermesc`. +// when running this test on Hermes. /** * Test calling SES lockdown. From 3b6bbf1deeb7e7d04187cc2f0b44b20762e2dde0 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:23:12 +0100 Subject: [PATCH 058/115] test(ses): disable Hermes VM test --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8416cf0b10..6bae75ecd4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -328,8 +328,8 @@ jobs: run: cd packages/ses/hermes-cli-linux && npm run test:hermesc # errors on async (arrow) functions and async generators - - name: Run generated bytecode file on Hermes VM - run: cd packages/ses/hermes-cli-linux && npm run test:hermes + # - name: Run generated bytecode file on Hermes VM + # run: cd packages/ses/hermes-cli-linux && npm run test:hermes # SES TypeErrors expected until resolved and hardenIntrinsics loop viable-release: From 56af3773b248463f48ad5cff624ec4ff99ee9f7e Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:23:28 +0100 Subject: [PATCH 059/115] test(ses): pin hermes-engine-cli --- packages/ses/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index ce7f8a0770..0535e96eab 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -93,7 +93,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.29.1", - "hermes-engine-cli": "^0.12.0", + "hermes-engine-cli": "0.12.0", "prettier": "^3.2.5", "sinon": "^15.1.0", "terser": "^5.16.6", diff --git a/yarn.lock b/yarn.lock index 43b11b73d5..94af5669ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6606,7 +6606,7 @@ __metadata: languageName: node linkType: hard -"hermes-engine-cli@npm:^0.12.0": +"hermes-engine-cli@npm:0.12.0": version: 0.12.0 resolution: "hermes-engine-cli@npm:0.12.0" checksum: 10c0/53a00336632cc7a743e9a88a5199865cf922d118f42f15bed4d2ed2fee635acd0d4d8563803b47e7c1bc2d17650281eb9188be8cfdaa25887243cfee840523be @@ -10530,7 +10530,7 @@ __metadata: eslint-config-prettier: "npm:^9.1.0" eslint-plugin-eslint-comments: "npm:^3.2.0" eslint-plugin-import: "npm:^2.29.1" - hermes-engine-cli: "npm:^0.12.0" + hermes-engine-cli: "npm:0.12.0" prettier: "npm:^3.2.5" sinon: "npm:^15.1.0" terser: "npm:^5.16.6" From 1b968d247f8c4a7f7e1764813b46d37bf5b39102 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:26:25 +0100 Subject: [PATCH 060/115] test(ses): add script to run sh to create Hermes bin symlinks --- packages/ses/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ses/package.json b/packages/ses/package.json index 0535e96eab..dd25dc9c71 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -74,6 +74,7 @@ "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", + "test:create-hermes-bin-symlinks": "./scripts/hermes-bin-symlinks.sh", "test:hermesc": "./scripts/hermesc.sh", "test:hermes": "cd hermes-cli-linux && ./hermes -b hermes-smoke.hbc" }, From 85acfecc5828b6becc56754c4d2be766bc82d9a5 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 10:37:20 +0100 Subject: [PATCH 061/115] test(ses): move smoke test calls below --- packages/ses/test/hermes-smoke.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ses/test/hermes-smoke.js b/packages/ses/test/hermes-smoke.js index d65c427096..52dfe88892 100644 --- a/packages/ses/test/hermes-smoke.js +++ b/packages/ses/test/hermes-smoke.js @@ -9,8 +9,6 @@ const testLockdown = () => { lockdown(); }; -testLockdown(); - /** * TODO: Test creating a new Compartment. */ @@ -20,8 +18,6 @@ const testCompartment = () => { const c = new Compartment(); }; -// testCompartment(); - /** * TODO: Test Compartment import hook and resolve hook. */ @@ -50,4 +46,8 @@ async function testCompartmentHooks() { assert(module); } +testLockdown(); + +// testCompartment(); + // testCompartmentHooks(); From 0b1ca82f82ced36a65f6fde5dd8ff07c45043427 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 10:51:38 +0100 Subject: [PATCH 062/115] chore(ses): remove wget/extract hermes-cli-linux from CI --- .github/workflows/ci.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6bae75ecd4..8e25b1b840 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,14 +318,8 @@ jobs: - name: 'build' run: yarn run build - - name: Fetch Hermes CLI for Linux tar file - run: cd packages/ses && mkdir hermes-cli-linux && cd hermes-cli-linux && wget https://github.com/facebook/hermes/releases/download/v0.12.0/hermes-cli-linux-v0.12.0.tar.gz - - - name: Extract Hermes CLI for Linux tar file - run: cd packages/ses/hermes-cli-linux && tar -xzvf hermes-cli-linux-v0.12.0.tar.gz - - name: Run SES smoke test on Hermes JS compiler - run: cd packages/ses/hermes-cli-linux && npm run test:hermesc + run: cd packages/ses && npm run test:hermesc # errors on async (arrow) functions and async generators # - name: Run generated bytecode file on Hermes VM From 984bbcf4b7b041566a1be5b1cbe168adf35d207f Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:48:32 +0100 Subject: [PATCH 063/115] test(ses): merge Hermes compiler and VM sh --- .github/workflows/ci.yml | 9 ++------ packages/ses/package.json | 3 +-- packages/ses/scripts/hermes.sh | 39 +++++++++++++++++++++++++++++++++ packages/ses/scripts/hermesc.sh | 26 ---------------------- 4 files changed, 42 insertions(+), 35 deletions(-) create mode 100755 packages/ses/scripts/hermes.sh delete mode 100755 packages/ses/scripts/hermesc.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e25b1b840..c256ce1200 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,13 +318,8 @@ jobs: - name: 'build' run: yarn run build - - name: Run SES smoke test on Hermes JS compiler - run: cd packages/ses && npm run test:hermesc - # errors on async (arrow) functions and async generators - - # - name: Run generated bytecode file on Hermes VM - # run: cd packages/ses/hermes-cli-linux && npm run test:hermes - # SES TypeErrors expected until resolved and hardenIntrinsics loop + - name: Run SES smoke test on Hermes + run: cd packages/ses && yarn test:hermes viable-release: name: viable-release diff --git a/packages/ses/package.json b/packages/ses/package.json index dd25dc9c71..78c4fcd5a6 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -75,8 +75,7 @@ "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", "test:create-hermes-bin-symlinks": "./scripts/hermes-bin-symlinks.sh", - "test:hermesc": "./scripts/hermesc.sh", - "test:hermes": "cd hermes-cli-linux && ./hermes -b hermes-smoke.hbc" + "test:hermes": "./scripts/hermes.sh" }, "dependencies": { "@endo/env-options": "^1.1.4" diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh new file mode 100755 index 0000000000..5f1651ff8d --- /dev/null +++ b/packages/ses/scripts/hermes.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +OS="$(uname -s)" + +case "$OS" in + Linux*) + OS_DIR="linux64-bin" + ;; + Darwin*) + OS_DIR="osx-bin" + ;; + CYGWIN*|MINGW*|MSYS*) + OS_DIR="win64-bin" + ;; + *) + echo "Unsupported OS: $OS" + exit 1 + ;; +esac + +# Paths relative to 'packages/ses' +HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" +HERMES="../../node_modules/hermes-engine-cli/$OS_DIR/hermes" + +echo "Catenating SES to Hermes smoke test" +cat dist/ses.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js + +# Errors on async arrow functions and async generators +# Both are unsupported on Hermes +echo "Executing smoke test on Hermes compiler" +$HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke-dist.js +echo "Hermes compiler done" + +# Disabled until https://github.com/endojs/endo/issues/1891 complete +# echo "Executing generated bytecode file on Hermes VM" +# $HERMES -b hermes-smoke.hbc +# echo "Hermes VM done" + +echo "Hermes tests complete" diff --git a/packages/ses/scripts/hermesc.sh b/packages/ses/scripts/hermesc.sh deleted file mode 100755 index f239760c23..0000000000 --- a/packages/ses/scripts/hermesc.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -OS="$(uname -s)" - -case "$OS" in - Linux*) - OS_DIR="linux64-bin" - ;; - Darwin*) - OS_DIR="osx-bin" - ;; - CYGWIN*|MINGW*|MSYS*) - OS_DIR="win64-bin" - ;; - *) - echo "Unsupported OS: $OS" - exit 1 - ;; -esac - -# Path relative to 'packages/ses' -HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" - -cat dist/ses.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js - -$HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke-dist.js From b3bdf2609897ae7e103e442e4f5c3d5a68343c51 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:56:26 +0100 Subject: [PATCH 064/115] chore(ses): improve Hermes test logs --- packages/ses/scripts/hermes.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh index 5f1651ff8d..c79add1a6b 100755 --- a/packages/ses/scripts/hermes.sh +++ b/packages/ses/scripts/hermes.sh @@ -22,18 +22,21 @@ esac HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" HERMES="../../node_modules/hermes-engine-cli/$OS_DIR/hermes" -echo "Catenating SES to Hermes smoke test" +echo "Catenating: dist/ses.cjs + test/hermes-smoke.js" cat dist/ses.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js +echo "Generated: test/hermes-smoke-dist.js" # Errors on async arrow functions and async generators # Both are unsupported on Hermes -echo "Executing smoke test on Hermes compiler" -$HERMESC -emit-binary -out test/hermes-smoke.hbc test/hermes-smoke-dist.js +echo "Executing: test/hermes-smoke-dist.js on Hermes compiler" +$HERMESC -emit-binary -out test/hermes-smoke-dist.hbc test/hermes-smoke-dist.js +echo "Generated: test/hermes-smoke-dist.hbc" echo "Hermes compiler done" -# Disabled until https://github.com/endojs/endo/issues/1891 complete +# TODO: Disabled until https://github.com/endojs/endo/issues/1891 complete # echo "Executing generated bytecode file on Hermes VM" # $HERMES -b hermes-smoke.hbc # echo "Hermes VM done" +echo "Skipping: Hermes VM" echo "Hermes tests complete" From 7c2bc134bd335ded4a1802b931e002354f2c9430 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:59:25 +0100 Subject: [PATCH 065/115] test(ses): cleanup after running Hermes tests --- packages/ses/scripts/hermes.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh index c79add1a6b..974634f044 100755 --- a/packages/ses/scripts/hermes.sh +++ b/packages/ses/scripts/hermes.sh @@ -40,3 +40,8 @@ echo "Hermes compiler done" echo "Skipping: Hermes VM" echo "Hermes tests complete" + +echo "Removing: test/hermes-smoke-dist.js" +rm test/hermes-smoke-dist.js +echo "Removing: test/hermes-smoke-dist.hbc" +rm test/hermes-smoke-dist.hbc From ed958abefe941a1e2d0dce6adc887fe55be5e11e Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:01:38 +0100 Subject: [PATCH 066/115] Revert "refactor(ses): asyncTrampoline as standard async fn for Hermes" This reverts commit 6c1b4458c336ec70dfdf72b0ac7d06f1983817dc. --- packages/ses/src/module-load.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/module-load.js b/packages/ses/src/module-load.js index 5b19380849..881cf390b6 100644 --- a/packages/ses/src/module-load.js +++ b/packages/ses/src/module-load.js @@ -25,7 +25,7 @@ import { makeError, annotateError, q, X } from './error/assert.js'; const noop = () => {}; -async function asyncTrampoline(generatorFunc, args, errorWrapper) { +const asyncTrampoline = async (generatorFunc, args, errorWrapper) => { await null; const iterator = generatorFunc(...args); let result = generatorNext(iterator); @@ -39,7 +39,7 @@ async function asyncTrampoline(generatorFunc, args, errorWrapper) { } } return result.value; -} +}; const syncTrampoline = (generatorFunc, args) => { const iterator = generatorFunc(...args); From 76d1c37da29b5940787a301139d679daae80343f Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:01:46 +0100 Subject: [PATCH 067/115] Revert "refactor(ses): convert async arrow functions for Hermes" This reverts commit eb5577700bee0655d0cee6615e16cf80b0df2234. --- packages/ses/src/module-load.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ses/src/module-load.js b/packages/ses/src/module-load.js index 881cf390b6..dff6c35bc6 100644 --- a/packages/ses/src/module-load.js +++ b/packages/ses/src/module-load.js @@ -522,14 +522,14 @@ const asyncJobQueue = () => { * * @returns {Promise>} */ - async function drainQueue() { + const drainQueue = async () => { await null; for (const job of pendingJobs) { // eslint-disable-next-line no-await-in-loop await job; } return errors; - } + }; return { enqueueJob, drainQueue }; }; @@ -562,12 +562,12 @@ const preferAsync = (asyncImpl, _syncImpl) => asyncImpl; * compartment and the specifier of the module within its own compartment. * This graph is then ready to be synchronously linked and executed. */ -export async function load( +export const load = async ( compartmentPrivateFields, moduleAliases, compartment, moduleSpecifier, -) { +) => { const { name: compartmentName } = weakmapGet( compartmentPrivateFields, compartment, @@ -597,7 +597,7 @@ export async function load( compartmentName, )}`, }); -} +}; /* * `loadNow` synchronously gathers the module records for a specified module From c1b9051656f5724fc43c0c2ddd7851d877b4a308 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:15:42 +0100 Subject: [PATCH 068/115] feat(ses): add makeBundle Hermes async ArrowFunctionExpression transform Co-authored-by: naugtur --- packages/ses/scripts/bundle.js | 7 +++ packages/ses/scripts/hermesTransforms.js | 62 ++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 packages/ses/scripts/hermesTransforms.js diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 542995a6ac..da6cc861ae 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -4,6 +4,7 @@ import fs from 'fs'; import { makeBundle } from '@endo/compartment-mapper/bundle.js'; import { minify } from 'terser'; import { fileURLToPath, pathToFileURL } from 'url'; +import { hermesTransforms } from './hermesTransforms.js'; const resolve = (rel, abs) => fileURLToPath(new URL(rel, abs).toString()); const root = new URL('..', import.meta.url).toString(); @@ -22,9 +23,15 @@ const main = async () => { const packageJson = JSON.parse(text); const version = packageJson.version; + // TODO: make this conditional on hermes build + const moduleTransforms = hermesTransforms; + const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), + { + moduleTransforms, + }, ); const versionedBundle = `// ses@${version}\n${bundle}`; diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js new file mode 100644 index 0000000000..9cbd072aee --- /dev/null +++ b/packages/ses/scripts/hermesTransforms.js @@ -0,0 +1,62 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { parse } from '@babel/parser'; +import babelTraverse from '@babel/traverse'; +import babelGenerate from '@babel/generator'; +import * as t from '@babel/types'; + +// TODO: do we need to use this instead? +// import babelGenerator from '@agoric/babel-generator'; + +// TODO: Stolen from evasive-transform package sources. Is this still necessary? +const traverse = babelTraverse.default || babelTraverse; +const generate = babelGenerate.default || babelGenerate; + +const decoder = new TextDecoder('utf-8'); +const encoder = new TextEncoder('utf-8'); + +const asyncArrowEliminator = { + ArrowFunctionExpression(path) { + if (path.node.async) { + let body = path.node.body; + + // In case it's a ()=>expression style arrow function + if (!t.isBlockStatement(body)) { + body = t.blockStatement([t.returnStatement(body)]); + } + + const functionExpression = t.functionExpression( + null, + path.node.params, + body, + path.node.generator, + path.node.async, + ); + + path.replaceWith(functionExpression); + } + }, +}; + +export const hermesTransforms = { + mjs: (sourceBytes, specifier, location, _packageLocation, { sourceMap }) => { + const transforms = { + ...asyncArrowEliminator, + // Some transforms might be added based on the specifier later + }; + + const sourceString = decoder.decode(sourceBytes); + + const ast = parse(sourceString, { + sourceType: 'module', + // TODO: do we need more options here? + }); + + traverse(ast, transforms); + + const { code } = generate(ast, { + // TODO: any options needed here? + }); + + return { bytes: encoder.encode(code), parser: 'mjs', sourceMap }; + }, +}; From 27f766db5a94338a953ef76114820dd7f5c12d21 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 14 Aug 2024 19:24:48 +0100 Subject: [PATCH 069/115] fix(ses): Hermes transform typedoc TS errors --- packages/ses/scripts/hermesTransforms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index 9cbd072aee..c4e6c93aa0 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -11,8 +11,8 @@ import * as t from '@babel/types'; const traverse = babelTraverse.default || babelTraverse; const generate = babelGenerate.default || babelGenerate; -const decoder = new TextDecoder('utf-8'); -const encoder = new TextEncoder('utf-8'); +const decoder = new TextDecoder(); +const encoder = new TextEncoder(); const asyncArrowEliminator = { ArrowFunctionExpression(path) { From d7744b14356afe850776e36051c181d2d3de0683 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:04:07 +0100 Subject: [PATCH 070/115] refactor(ses): update Hermes transform --- packages/ses/scripts/hermesTransforms.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index c4e6c93aa0..84ab391468 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -1,18 +1,15 @@ +// @ts-nocheck XXX Babel types /* eslint-disable import/no-extraneous-dependencies */ import { parse } from '@babel/parser'; +import babelGenerate from '@agoric/babel-generator'; import babelTraverse from '@babel/traverse'; -import babelGenerate from '@babel/generator'; import * as t from '@babel/types'; -// TODO: do we need to use this instead? -// import babelGenerator from '@agoric/babel-generator'; - -// TODO: Stolen from evasive-transform package sources. Is this still necessary? const traverse = babelTraverse.default || babelTraverse; const generate = babelGenerate.default || babelGenerate; -const decoder = new TextDecoder(); -const encoder = new TextEncoder(); +const decoder = new TextDecoder('utf-8'); +const encoder = new TextEncoder('utf-8'); const asyncArrowEliminator = { ArrowFunctionExpression(path) { @@ -48,13 +45,14 @@ export const hermesTransforms = { const ast = parse(sourceString, { sourceType: 'module', - // TODO: do we need more options here? }); traverse(ast, transforms); const { code } = generate(ast, { - // TODO: any options needed here? + retainLines: true, + compact: true, + verbatim: true, }); return { bytes: encoder.encode(code), parser: 'mjs', sourceMap }; From 1fe6a5608b1414766e6d57b2a812a34a9145ea8b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:34:38 +0100 Subject: [PATCH 071/115] refactor(ses): obj assign async arrow fn --- packages/ses/scripts/hermesTransforms.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index 84ab391468..396aba8e35 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -35,7 +35,13 @@ const asyncArrowEliminator = { }; export const hermesTransforms = { - mjs: (sourceBytes, specifier, location, _packageLocation, { sourceMap }) => { + mjs: async ( + sourceBytes, + specifier, + location, + _packageLocation, + { sourceMap }, + ) => { const transforms = { ...asyncArrowEliminator, // Some transforms might be added based on the specifier later From e4af84a9952f5f3045eca92d65ee1a73607ab8f7 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:22:33 +0100 Subject: [PATCH 072/115] refactor(ses): update AsyncGeneratorFunctionInstance export --- packages/ses/src/commons.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index d72fe27790..564b93cf13 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -362,14 +362,15 @@ export const FERAL_STACK_GETTER = feralStackGetter; export const FERAL_STACK_SETTER = feralStackSetter; // Test for async generator function syntax support. -let AsyncGeneratorNewFunctionInstance; +// eslint-disable-next-line import/no-mutable-exports +let AsyncGeneratorFunctionInstance; try { // Wrapping one in an new Function lets the `hermesc` binary file // parse the Metro js bundle without SyntaxError, to generate the // optimised Hermes bytecode bundle, when `gradlew` is called to // assemble the release build APK for React Native prod Android apps. // Delaying the error until runtime lets us customise lockdown behaviour. - AsyncGeneratorNewFunctionInstance = new FERAL_FUNCTION( + AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); } catch (e) { @@ -381,4 +382,4 @@ try { throw e; } } -export const AsyncGeneratorFunctionInstance = AsyncGeneratorNewFunctionInstance; +export { AsyncGeneratorFunctionInstance }; From 1ed84e16ac968c5c7dc8a40e4dab582f569e39d0 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 19 Aug 2024 14:44:26 +0100 Subject: [PATCH 073/115] refactor(ses): update Hermes transform --- packages/ses/scripts/hermesTransforms.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index 396aba8e35..033dce50e6 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -1,14 +1,15 @@ -// @ts-nocheck XXX Babel types /* eslint-disable import/no-extraneous-dependencies */ import { parse } from '@babel/parser'; import babelGenerate from '@agoric/babel-generator'; import babelTraverse from '@babel/traverse'; import * as t from '@babel/types'; +// @ts-expect-error TS2339 Property 'default' does not exist const traverse = babelTraverse.default || babelTraverse; const generate = babelGenerate.default || babelGenerate; const decoder = new TextDecoder('utf-8'); +// @ts-expect-error TS2554 Expected 0 arguments, but got 1 const encoder = new TextEncoder('utf-8'); const asyncArrowEliminator = { @@ -56,6 +57,7 @@ export const hermesTransforms = { traverse(ast, transforms); const { code } = generate(ast, { + // Nothing being done with sourcemaps as this point retainLines: true, compact: true, verbatim: true, From a6c0300362da60269ec72a53c33afdf1d15ac29a Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 20 Aug 2024 13:35:49 +0100 Subject: [PATCH 074/115] feat(ses): update Hermes transform to error on 'this' expression --- packages/ses/scripts/hermesTransforms.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index 033dce50e6..80849b5fef 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -17,6 +17,18 @@ const asyncArrowEliminator = { if (path.node.async) { let body = path.node.body; + const startLine = path.node.loc.start.line; + const endLine = path.node.loc.end.line; + + path.traverse({ + ThisExpression(innerPath) { + // throw path.buildCodeFrameError("..."); // https://github.com/babel/babel/issues/8617 + throw Error( + `${startLine}:${endLine} Hermes makeBundle transform doesn't support 'this' keyword in async arrow functions`, + ); + }, + }); + // In case it's a ()=>expression style arrow function if (!t.isBlockStatement(body)) { body = t.blockStatement([t.returnStatement(body)]); From bea3ad4945735b0ccf3c62e6c8680741e0a9620b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:55:15 +0100 Subject: [PATCH 075/115] Revert "refactor(ses): update AsyncGeneratorFunctionInstance export" This reverts commit e4af84a9952f5f3045eca92d65ee1a73607ab8f7. --- packages/ses/src/commons.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index 564b93cf13..d72fe27790 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -362,15 +362,14 @@ export const FERAL_STACK_GETTER = feralStackGetter; export const FERAL_STACK_SETTER = feralStackSetter; // Test for async generator function syntax support. -// eslint-disable-next-line import/no-mutable-exports -let AsyncGeneratorFunctionInstance; +let AsyncGeneratorNewFunctionInstance; try { // Wrapping one in an new Function lets the `hermesc` binary file // parse the Metro js bundle without SyntaxError, to generate the // optimised Hermes bytecode bundle, when `gradlew` is called to // assemble the release build APK for React Native prod Android apps. // Delaying the error until runtime lets us customise lockdown behaviour. - AsyncGeneratorFunctionInstance = new FERAL_FUNCTION( + AsyncGeneratorNewFunctionInstance = new FERAL_FUNCTION( 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); } catch (e) { @@ -382,4 +381,4 @@ try { throw e; } } -export { AsyncGeneratorFunctionInstance }; +export const AsyncGeneratorFunctionInstance = AsyncGeneratorNewFunctionInstance; From 35f8116cf35713f1da5d53142a7c04dd8fa3b484 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 21 Aug 2024 23:24:17 +0100 Subject: [PATCH 076/115] refactor(ses): update Hermes transform --- packages/ses/scripts/hermesTransforms.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index 80849b5fef..cc71f58300 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -17,16 +17,17 @@ const asyncArrowEliminator = { if (path.node.async) { let body = path.node.body; - const startLine = path.node.loc.start.line; - const endLine = path.node.loc.end.line; - path.traverse({ ThisExpression(innerPath) { + const { start } = innerPath.node.loc; // throw path.buildCodeFrameError("..."); // https://github.com/babel/babel/issues/8617 throw Error( - `${startLine}:${endLine} Hermes makeBundle transform doesn't support 'this' keyword in async arrow functions`, + `Hermes makeBundle Babel transform doesn't support 'this' keyword in async arrow functions. + at this (${path.state.filename}:${start.line}:${start.column})`, ); }, + // No need for an Identifier traversal on nodes matching 'arguments' to error on + // Since only non-arrow functions can access the `arguments` array-like object }); // In case it's a ()=>expression style arrow function @@ -66,7 +67,7 @@ export const hermesTransforms = { sourceType: 'module', }); - traverse(ast, transforms); + traverse(ast, transforms, null, { filename: location }); const { code } = generate(ast, { // Nothing being done with sourcemaps as this point From f2d66913ac2ca4bb11bb6a93af40482cdc7bf6ed Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:10:05 +0100 Subject: [PATCH 077/115] feat(ses): bundle only Hermes cjs on env var --- packages/ses/scripts/bundle.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index da6cc861ae..30da9bde49 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -15,7 +15,11 @@ const write = async (target, content) => { await fs.promises.writeFile(location, content); }; -const main = async () => { +/** + * @param {object} [options] + * @param {string} [options.buildType] Suffix used to build special bundles (e.g. 'hermes') + */ +const writeBundle = async ({ buildType } = {}) => { const text = await fs.promises.readFile( fileURLToPath(`${root}/package.json`), 'utf8', @@ -23,13 +27,12 @@ const main = async () => { const packageJson = JSON.parse(text); const version = packageJson.version; - // TODO: make this conditional on hermes build const moduleTransforms = hermesTransforms; const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), - { + buildType && { moduleTransforms, }, ); @@ -54,12 +57,19 @@ const main = async () => { 'dist/lockdown.mjs', 'dist/lockdown.umd.js', ]; + const bundleFilePathsHermes = [ + `dist/ses${buildType ? `-${buildType}` : ''}.cjs`, + ]; const terseFilePaths = ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; - await Promise.all([ - ...bundleFilePaths.map(dest => write(dest, versionedBundle)), - ...terseFilePaths.map(dest => write(dest, terse)), - ]); + await Promise.all( + buildType + ? [bundleFilePathsHermes] + : [ + ...bundleFilePaths.map(dest => write(dest, versionedBundle)), + ...terseFilePaths.map(dest => write(dest, terse)), + ], + ); // When importing types from a CJS package, TS v5.5+ considers the "module" // field in `ses`' `package.json`, so any .d.ts file is considered to be "ESM @@ -87,6 +97,10 @@ const main = async () => { console.log(`Copied ${sourceDTS} to ${destDTS}`); }; +const main = async () => { + await writeBundle({ buildType: process.env.SES_BUILD_TYPE || undefined }); +}; + main().catch(err => { console.error('Error running main:', err); process.exitCode = 1; From eb87783e7155e36098961be264d8c9758d0ad7cb Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:11:44 +0100 Subject: [PATCH 078/115] feat(ses): add Hermes cjs bundle as export (exp) --- packages/ses/package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 78c4fcd5a6..74008d8873 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -55,6 +55,12 @@ "default": "./dist/ses.cjs" } }, + "./lockdown-hermes-exp": { + "require": { + "types": "./dist/types.d.cts", + "default": "./dist/ses-hermes.cjs" + } + }, "./tools.js": "./tools.js", "./assert-shim.js": "./assert-shim.js", "./lockdown-shim.js": "./lockdown-shim.js", @@ -70,7 +76,7 @@ "lint-fix": "eslint --fix .", "lint:eslint": "eslint .", "lint:types": "tsc", - "prepare": "npm run clean && npm run build", + "prepare": "npm run clean && npm run build && SES_BUILD_TYPE=hermes npm run build", "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", From 23945e4f53e201078c8919fb434eac8318f1f63d Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:19:49 +0100 Subject: [PATCH 079/115] fix(ses): update CI to build Hermes shim before compiler test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c256ce1200..0e288c12a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -319,7 +319,7 @@ jobs: run: yarn run build - name: Run SES smoke test on Hermes - run: cd packages/ses && yarn test:hermes + run: cd packages/ses && SES_BUILD_TYPE=hermes yarn run build && yarn test:hermes viable-release: name: viable-release From 69c08ee99328406d2918f38bd00dcd05fec20435 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 09:24:51 +0100 Subject: [PATCH 080/115] refactor(ses): fix Hermes transform typedoc TS errors --- packages/ses/scripts/bundle.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 30da9bde49..aac1a90d69 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -32,9 +32,7 @@ const writeBundle = async ({ buildType } = {}) => { const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), - buildType && { - moduleTransforms, - }, + buildType ? {} : { moduleTransforms }, ); const versionedBundle = `// ses@${version}\n${bundle}`; From 3df7ab2c86191c8b41053ee85ec05edb59fafccc Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:05:01 +0100 Subject: [PATCH 081/115] test(ses): update CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e288c12a6..c256ce1200 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -319,7 +319,7 @@ jobs: run: yarn run build - name: Run SES smoke test on Hermes - run: cd packages/ses && SES_BUILD_TYPE=hermes yarn run build && yarn test:hermes + run: cd packages/ses && yarn test:hermes viable-release: name: viable-release From e90d3bc84d61a239149f538b773b24c52c0842a4 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:52:15 +0100 Subject: [PATCH 082/115] refactor(ses): update SES bundling for Hermes --- packages/ses/scripts/bundle.js | 66 ++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index aac1a90d69..3319a7b842 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -27,47 +27,51 @@ const writeBundle = async ({ buildType } = {}) => { const packageJson = JSON.parse(text); const version = packageJson.version; - const moduleTransforms = hermesTransforms; + const moduleTransforms = {}; + + let bundleFilePaths = [ + 'dist/ses.cjs', + 'dist/ses.mjs', + 'dist/ses.umd.js', + 'dist/lockdown.cjs', + 'dist/lockdown.mjs', + 'dist/lockdown.umd.js', + ]; + let terseFilePaths = ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; + + if (buildType === 'hermes') { + bundleFilePaths = ['dist/ses-hermes.cjs']; + Object.assign(hermesTransforms, moduleTransforms); + terseFilePaths = []; + } const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), - buildType ? {} : { moduleTransforms }, + moduleTransforms, ); const versionedBundle = `// ses@${version}\n${bundle}`; - const { code: terse } = await minify(versionedBundle, { - mangle: false, - keep_classnames: true, - }); - assert.string(terse); - + buildType && console.log(`-- Building '${buildType}' version of SES --`); console.log(`Bundle size: ${versionedBundle.length} bytes`); - console.log(`Minified bundle size: ${terse.length} bytes`); + + let terse; + if (terseFilePaths.length) { + const { code } = await minify(versionedBundle, { + mangle: false, + keep_classnames: true, + }); + terse = code; + assert.string(terse); + console.log(`Minified bundle size: ${terse.length} bytes`); + } await fs.promises.mkdir('dist', { recursive: true }); - const bundleFilePaths = [ - 'dist/ses.cjs', - 'dist/ses.mjs', - 'dist/ses.umd.js', - 'dist/lockdown.cjs', - 'dist/lockdown.mjs', - 'dist/lockdown.umd.js', - ]; - const bundleFilePathsHermes = [ - `dist/ses${buildType ? `-${buildType}` : ''}.cjs`, - ]; - const terseFilePaths = ['dist/ses.umd.min.js', 'dist/lockdown.umd.min.js']; - - await Promise.all( - buildType - ? [bundleFilePathsHermes] - : [ - ...bundleFilePaths.map(dest => write(dest, versionedBundle)), - ...terseFilePaths.map(dest => write(dest, terse)), - ], - ); + await Promise.all([ + ...bundleFilePaths.map(dest => write(dest, versionedBundle)), + ...terseFilePaths.map(dest => write(dest, terse)), + ]); // When importing types from a CJS package, TS v5.5+ considers the "module" // field in `ses`' `package.json`, so any .d.ts file is considered to be "ESM @@ -96,7 +100,7 @@ const writeBundle = async ({ buildType } = {}) => { }; const main = async () => { - await writeBundle({ buildType: process.env.SES_BUILD_TYPE || undefined }); + await writeBundle({ buildType: process.env.SES_BUILD_TYPE || 'vanilla' }); }; main().catch(err => { From f82307a921934da0bd07acfd98f0ac5139a75b7f Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:09:16 +0100 Subject: [PATCH 083/115] fix(ses): update SES package.json scripts --- packages/ses/package.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 74008d8873..cbab7b121c 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -55,7 +55,7 @@ "default": "./dist/ses.cjs" } }, - "./lockdown-hermes-exp": { + "./lockdown-hermes": { "require": { "types": "./dist/types.d.cts", "default": "./dist/ses-hermes.cjs" @@ -68,7 +68,9 @@ "./package.json": "./package.json" }, "scripts": { - "build": "node scripts/bundle.js", + "build:vanilla": "node scripts/bundle.js", + "build:hermes": "SES_BUILD_TYPE=hermes node scripts/bundle.js", + "build": "yarn build:vanilla && yarn build:hermes", "clean": "rm -rf dist", "cover": "c8 ava", "demo": "python3 -m http.server", @@ -76,7 +78,7 @@ "lint-fix": "eslint --fix .", "lint:eslint": "eslint .", "lint:types": "tsc", - "prepare": "npm run clean && npm run build && SES_BUILD_TYPE=hermes npm run build", + "prepare": "yarn clean && yarn build", "qt": "ava", "test": "tsd && ava", "test:platform-compatibility": "node test/package/test.cjs", From 849248fccc3cb398b0970495764047544d8b4cc9 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:34:11 +0100 Subject: [PATCH 084/115] fix(ses): Hermes bundling Object.assign --- packages/ses/scripts/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 3319a7b842..96441feef2 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -41,7 +41,7 @@ const writeBundle = async ({ buildType } = {}) => { if (buildType === 'hermes') { bundleFilePaths = ['dist/ses-hermes.cjs']; - Object.assign(hermesTransforms, moduleTransforms); + Object.assign(moduleTransforms, hermesTransforms); terseFilePaths = []; } From 7b4ef2b7c759457b3fbae4f568729712c4073e0b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:15:50 +0100 Subject: [PATCH 085/115] fix(ses): shellscript --- packages/ses/scripts/hermes.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh index 974634f044..9edce019a8 100755 --- a/packages/ses/scripts/hermes.sh +++ b/packages/ses/scripts/hermes.sh @@ -22,8 +22,8 @@ esac HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" HERMES="../../node_modules/hermes-engine-cli/$OS_DIR/hermes" -echo "Catenating: dist/ses.cjs + test/hermes-smoke.js" -cat dist/ses.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js +echo "Catenating: dist/ses-hermes.cjs + test/hermes-smoke.js" +cat dist/ses-hermes.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js echo "Generated: test/hermes-smoke-dist.js" # Errors on async arrow functions and async generators From 734927856d9b4a2ed363b65b85fde1b07524e01b Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:16:40 +0100 Subject: [PATCH 086/115] fix(ses): Hermes bundling moduleTransforms --- packages/ses/scripts/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 96441feef2..31a2d44f64 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -48,7 +48,7 @@ const writeBundle = async ({ buildType } = {}) => { const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), - moduleTransforms, + { moduleTransforms }, ); const versionedBundle = `// ses@${version}\n${bundle}`; From ebb88c189703ca8d7bf8ae6f148ad1607a441b7d Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:17:06 +0100 Subject: [PATCH 087/115] refactor(ses): update bundle.js --- packages/ses/scripts/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 31a2d44f64..91634a2e6d 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -41,8 +41,8 @@ const writeBundle = async ({ buildType } = {}) => { if (buildType === 'hermes') { bundleFilePaths = ['dist/ses-hermes.cjs']; - Object.assign(moduleTransforms, hermesTransforms); terseFilePaths = []; + Object.assign(moduleTransforms, hermesTransforms); } const bundle = await makeBundle( From d8942d289944f35f756e6b98c389f41b5080be23 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:33:36 +0100 Subject: [PATCH 088/115] refactor(ses): fix bundle.js typedoc TS error --- packages/ses/scripts/bundle.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 91634a2e6d..58ff1deba9 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -48,6 +48,7 @@ const writeBundle = async ({ buildType } = {}) => { const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), + // @ts-expect-error TS2322 Type '{}' is not assignable to type 'ModuleTransforms'. Index signature for type 'string' is missing in type '{}'. { moduleTransforms }, ); const versionedBundle = `// ses@${version}\n${bundle}`; From 977925e74ded792892e7bf38a726edf6c32e74b5 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:54:06 +0100 Subject: [PATCH 089/115] refactor(ses): update bundle.js --- packages/ses/scripts/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index bb9e0a1b24..3880ec1455 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -54,7 +54,7 @@ const writeBundle = async ({ buildType } = {}) => { ); const versionedBundle = `// ses@${version}\n${bundle}`; - buildType && console.log(`-- Building '${buildType}' version of SES --`); + console.log(`-- Building '${buildType}' version of SES --`); console.log(`Bundle size: ${versionedBundle.length} bytes`); let terse; From 5dc71f913dc4a753334451d59bbb8591f49da769 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 30 Aug 2024 12:54:25 +0100 Subject: [PATCH 090/115] refactor(ses): use @endo/env-options vs process.env --- packages/ses/scripts/bundle.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 3880ec1455..e132a57c13 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -5,6 +5,7 @@ import fs from 'fs'; import { makeBundle } from '@endo/compartment-mapper/bundle.js'; import { minify } from 'terser'; import { fileURLToPath, pathToFileURL } from 'url'; +import { getEnvironmentOption as getenv } from '@endo/env-options'; import { hermesTransforms } from './hermesTransforms.js'; const resolve = (rel, abs) => fileURLToPath(new URL(rel, abs).toString()); @@ -102,7 +103,8 @@ const writeBundle = async ({ buildType } = {}) => { }; const main = async () => { - await writeBundle({ buildType: process.env.SES_BUILD_TYPE || 'vanilla' }); + const buildType = getenv('SES_BUILD_TYPE', 'vanilla'); + await writeBundle({ buildType }); }; main().catch(err => { From 7317d102e55eabeef3d2e5786b24580e00eca9b7 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:51:22 +0100 Subject: [PATCH 091/115] refactor(ses): update CI.yml --- .github/workflows/ci.yml | 61 ++++------------------------------------ 1 file changed, 5 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c256ce1200..b20cb780e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -231,59 +231,8 @@ jobs: - name: Run yarn test262 run: exit 0 # TODO remove test262 from required tests for CI - platform-compatibility-test: - name: platform-compatibility-test - - # begin macro - - runs-on: ${{ matrix.platform }} - strategy: - fail-fast: false - matrix: - node-version: [18.x, 20.x] - platform: [ubuntu-latest] - - steps: - - name: Checkout - uses: actions/checkout@v3 - - # without this, setup-node errors on mismatched yarn versions - - run: corepack enable - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: yarn - - - name: Echo node version - run: node --version - - - name: Install dependencies - run: yarn install --immutable - - # end macro - - - name: 'build' - run: yarn run build - - # fails under Node v12 - - run: corepack disable - - - name: 'switch to node v12' - uses: actions/setup-node@v3 - with: - node-version: '12.x' - - - name: Echo node version - run: node --version - - - name: Run test:platform-compatibility - # npm b/c Yarn 4 doesn't work in Node 12 - run: cd packages/ses && npm run test:platform-compatibility - - hermes-test: - name: hermes-test + test-hermes: + name: test-hermes # begin macro @@ -315,10 +264,10 @@ jobs: # end macro - - name: 'build' - run: yarn run build + - name: Run yarn build + run: yarn build - - name: Run SES smoke test on Hermes + - name: Run SES/Hermes smoke test run: cd packages/ses && yarn test:hermes viable-release: From bec012196e09f99127dffd8254b33f13d19358d8 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:39:34 +0100 Subject: [PATCH 092/115] refactor(ses): remove unused script from conflict res Co-authored-by: Saleh Abdel Motaal --- packages/ses/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index e2c3ab843b..04f6f4a013 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -81,7 +81,6 @@ "prepare": "yarn clean && yarn build", "qt": "ava", "test": "tsd && ava", - "test:platform-compatibility": "node test/package/test.cjs", "test:create-hermes-bin-symlinks": "./scripts/hermes-bin-symlinks.sh", "test:hermes": "./scripts/hermes.sh" }, From bec2c4dc68590c7b063ae7dae6acc380ea4cd500 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:41:06 +0100 Subject: [PATCH 093/115] feat(ses): update export name Co-authored-by: Saleh Abdel Motaal --- packages/ses/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 04f6f4a013..4de318e9da 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -55,7 +55,7 @@ "default": "./dist/ses.cjs" } }, - "./lockdown-hermes": { + "./hermes": { "require": { "types": "./dist/types.d.cts", "default": "./dist/ses-hermes.cjs" From c8e6b55b01d6bf2046d559c53d81c976f48a3e81 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:47:54 +0100 Subject: [PATCH 094/115] chore(ses): run Hermes CI on Node 18, 20 and 22 Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b20cb780e8..f4508156f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -240,7 +240,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [20.x] + node-version: [18.x, 20.x, 22.x] platform: [ubuntu-latest] steps: From 7e4f681ed36b7e9d211ba727dfd31d5f89659e68 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:49:48 +0100 Subject: [PATCH 095/115] chore(ses): bump Hermes CI actions/setup-node from v3 to v4 Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4508156f1..c960eb5e2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -251,7 +251,7 @@ jobs: - run: corepack enable - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: yarn From 58bf929eb01c887da0adceb043454919451074dd Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:34:16 +0100 Subject: [PATCH 096/115] fix(ses): bundle moduleTransforms TS2322 --- packages/ses/scripts/bundle.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index e132a57c13..037577c57d 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -1,3 +1,5 @@ +/** @import {ModuleTransforms} from '../../compartment-mapper/types.js' */ + /* global process */ import '../index.js'; import '../test/lockdown-safe.js'; @@ -29,6 +31,7 @@ const writeBundle = async ({ buildType } = {}) => { const packageJson = JSON.parse(text); const version = packageJson.version; + /** @type ModuleTransforms */ const moduleTransforms = {}; let bundleFilePaths = [ @@ -50,7 +53,6 @@ const writeBundle = async ({ buildType } = {}) => { const bundle = await makeBundle( read, pathToFileURL(resolve('../index.js', import.meta.url)).toString(), - // @ts-expect-error TS2322 Type '{}' is not assignable to type 'ModuleTransforms'. Index signature for type 'string' is missing in type '{}'. { moduleTransforms }, ); const versionedBundle = `// ses@${version}\n${bundle}`; From e6d5d7f2f6de4be6e5f7778ad55603931468a59f Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:47:05 +0100 Subject: [PATCH 097/115] refactor(ses): reorder hermesc args --- packages/ses/scripts/hermes.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh index 9edce019a8..0bd9c19f5b 100755 --- a/packages/ses/scripts/hermes.sh +++ b/packages/ses/scripts/hermes.sh @@ -29,7 +29,7 @@ echo "Generated: test/hermes-smoke-dist.js" # Errors on async arrow functions and async generators # Both are unsupported on Hermes echo "Executing: test/hermes-smoke-dist.js on Hermes compiler" -$HERMESC -emit-binary -out test/hermes-smoke-dist.hbc test/hermes-smoke-dist.js +$HERMESC test/hermes-smoke-dist.js -emit-binary -out test/hermes-smoke-dist.hbc echo "Generated: test/hermes-smoke-dist.hbc" echo "Hermes compiler done" From e4a4f8cb3cc482582e059880e6e21e0d3339a3be Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:48:04 +0100 Subject: [PATCH 098/115] fix(ses): hermes VM hbc path prefix/folder --- packages/ses/scripts/hermes.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh index 0bd9c19f5b..45b24e1a19 100755 --- a/packages/ses/scripts/hermes.sh +++ b/packages/ses/scripts/hermes.sh @@ -35,7 +35,7 @@ echo "Hermes compiler done" # TODO: Disabled until https://github.com/endojs/endo/issues/1891 complete # echo "Executing generated bytecode file on Hermes VM" -# $HERMES -b hermes-smoke.hbc +# $HERMES -b test/hermes-smoke-dist.hbc # echo "Hermes VM done" echo "Skipping: Hermes VM" From 63645cf55dbd061181611063195ad24ba25b5fcc Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:07:41 +0100 Subject: [PATCH 099/115] fix(ses): update `console` to `print` for Hermes VM --- packages/ses/src/commons.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index 6372cfef99..fd9debf411 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -393,8 +393,14 @@ try { } catch (e) { if (e.name === 'SyntaxError') { // Swallows Hermes error `async generators are unsupported` at runtime. - // eslint-disable-next-line @endo/no-polymorphic-call - console.info('skipping async generators'); + // @ts-ignore + // eslint-disable-next-line no-undef + print('SES: Skipping async generators, unsupported on Hermes'); + // Note: `console` is not a JS built-in, so Hermes engine throws: + // Uncaught ReferenceError: Property 'console' doesn't exist + // See: https://github.com/facebook/hermes/issues/675 + // However React Native provides a `console` implementation: + // https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/InitializeCore.js } else { throw e; } From cdd2dad04a7b280c5750e74e5dd13c653148da84 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:13:31 +0100 Subject: [PATCH 100/115] chore(ses): bump Hermes CI actions/checkout from v3 to v4 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c960eb5e2c..8997279da2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,7 +245,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 # without this, setup-node errors on mismatched yarn versions - run: corepack enable From 5374cfc97e81390588e525f7344f8bb68cb2acde Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:00:36 +0100 Subject: [PATCH 101/115] refactor(ses): stricten commons async gen fn instance error cond Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- packages/ses/src/commons.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index fd9debf411..d1eee0d478 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -391,9 +391,10 @@ try { 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); } catch (e) { - if (e.name === 'SyntaxError') { + // @ts-expect-error ts(2339) Property 'jsEngine' does not exist on type 'Error'. However it exists on Hermes. + if (Error.prototype.jsEngine === 'hermes' && e.name === 'SyntaxError') { // Swallows Hermes error `async generators are unsupported` at runtime. - // @ts-ignore + // @ts-expect-error ts(2554) Expected 0 arguments, but got 1. It refers to the Web API Window object, but on Hermes we expect 1 argument. // eslint-disable-next-line no-undef print('SES: Skipping async generators, unsupported on Hermes'); // Note: `console` is not a JS built-in, so Hermes engine throws: From df5a0e8677432afc12255bfcb67903045d1597c1 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 11 Sep 2024 15:27:20 +0100 Subject: [PATCH 102/115] chore(ses): remove Hermes CI Node matrix and use 22.x --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8997279da2..a6f7a69a97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -240,7 +240,6 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x, 22.x] platform: [ubuntu-latest] steps: @@ -250,10 +249,10 @@ jobs: # without this, setup-node errors on mismatched yarn versions - run: corepack enable - - name: Use Node.js ${{ matrix.node-version }} + - name: Use Node.js 22.x uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 22.x cache: yarn - name: Echo node version From 75bc6f1fa1b556a385c6a9a344419b4324edd8da Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 17 Sep 2024 13:26:20 +0100 Subject: [PATCH 103/115] chore(ses): correct Hermes script output Co-authored-by: Christopher Hiller --- packages/ses/scripts/hermes.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermes.sh b/packages/ses/scripts/hermes.sh index 45b24e1a19..30864824e8 100755 --- a/packages/ses/scripts/hermes.sh +++ b/packages/ses/scripts/hermes.sh @@ -22,7 +22,7 @@ esac HERMESC="../../node_modules/hermes-engine-cli/$OS_DIR/hermesc" HERMES="../../node_modules/hermes-engine-cli/$OS_DIR/hermes" -echo "Catenating: dist/ses-hermes.cjs + test/hermes-smoke.js" +echo "Concatenating: dist/ses-hermes.cjs + test/hermes-smoke.js" cat dist/ses-hermes.cjs test/hermes-smoke.js > test/hermes-smoke-dist.js echo "Generated: test/hermes-smoke-dist.js" From 8d2a15200ccd38db46eabcca3dcbb4475ee6cb3c Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:09:00 +0100 Subject: [PATCH 104/115] refactor(ses): add terse type to bundle script Co-authored-by: Christopher Hiller --- packages/ses/scripts/bundle.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ses/scripts/bundle.js b/packages/ses/scripts/bundle.js index 037577c57d..08811e7017 100644 --- a/packages/ses/scripts/bundle.js +++ b/packages/ses/scripts/bundle.js @@ -60,6 +60,7 @@ const writeBundle = async ({ buildType } = {}) => { console.log(`-- Building '${buildType}' version of SES --`); console.log(`Bundle size: ${versionedBundle.length} bytes`); + /** @type {string|undefined} */ let terse; if (terseFilePaths.length) { const { code } = await minify(versionedBundle, { From eb7f63a0bc5f27e88bfd20df8c063d40a7f52797 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:11:27 +0100 Subject: [PATCH 105/115] chore(ses): remove redundant node version output CI step --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6f7a69a97..b522bf40db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -255,9 +255,6 @@ jobs: node-version: 22.x cache: yarn - - name: Echo node version - run: node --version - - name: Install dependencies run: yarn install --immutable From 56e466001cab2ccd2c45f0d6a888138ee755a05d Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Tue, 17 Sep 2024 16:45:25 +0100 Subject: [PATCH 106/115] refactor(ses): use text encoder/decoder default values (utf-8) --- packages/ses/scripts/hermesTransforms.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index cc71f58300..df1721ef94 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -8,9 +8,8 @@ import * as t from '@babel/types'; const traverse = babelTraverse.default || babelTraverse; const generate = babelGenerate.default || babelGenerate; -const decoder = new TextDecoder('utf-8'); -// @ts-expect-error TS2554 Expected 0 arguments, but got 1 -const encoder = new TextEncoder('utf-8'); +const decoder = new TextDecoder(); +const encoder = new TextEncoder(); const asyncArrowEliminator = { ArrowFunctionExpression(path) { From 431bff3d2d18ea5dabf160b3d03d45e31d119f69 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:01:22 +0100 Subject: [PATCH 107/115] refactor(ses): update Hermes transform from async to sync --- packages/ses/scripts/hermesTransforms.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index df1721ef94..842e238940 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -48,13 +48,7 @@ const asyncArrowEliminator = { }; export const hermesTransforms = { - mjs: async ( - sourceBytes, - specifier, - location, - _packageLocation, - { sourceMap }, - ) => { + mjs: (sourceBytes, specifier, location, _packageLocation, { sourceMap }) => { const transforms = { ...asyncArrowEliminator, // Some transforms might be added based on the specifier later From af3a420338b0fb2967cc9ceefacc83b0600b3860 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:59:54 +0100 Subject: [PATCH 108/115] refactor(ses): remove hermes bin symlinks script --- packages/ses/package.json | 1 - packages/ses/scripts/hermes-bin-symlinks.sh | 34 --------------------- 2 files changed, 35 deletions(-) delete mode 100755 packages/ses/scripts/hermes-bin-symlinks.sh diff --git a/packages/ses/package.json b/packages/ses/package.json index 389813e882..21e2e9c87a 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -82,7 +82,6 @@ "qt": "ava", "test": "tsd && ava", "test:hermes": "./scripts/hermes.sh", - "test:create-hermes-bin-symlinks": "./scripts/hermes-bin-symlinks.sh", "postpack": "git clean -f '*.d.ts*' '*.tsbuildinfo'" }, "dependencies": { diff --git a/packages/ses/scripts/hermes-bin-symlinks.sh b/packages/ses/scripts/hermes-bin-symlinks.sh deleted file mode 100755 index 1dc08b161a..0000000000 --- a/packages/ses/scripts/hermes-bin-symlinks.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -OS="$(uname -s)" - -case "$OS" in - Linux*) - OS_DIR="linux64-bin" - ;; - Darwin*) - OS_DIR="osx-bin" - ;; - CYGWIN*|MINGW*|MSYS*) - OS_DIR="win64-bin" - ;; - *) - echo "Unsupported OS: $OS" - exit 1 - ;; -esac - -# Path from 'packages/ses' -cd ../../node_modules/.bin - -if [[ "$OS" == linux* || "$OS" == Darwin* ]]; then - ln -s ../hermes-engine-cli/$OS_DIR/hbcdump hbcdump - ln -s ../hermes-engine-cli/$OS_DIR/hdb hdb - ln -s ../hermes-engine-cli/$OS_DIR/hermes hermes - ln -s ../hermes-engine-cli/$OS_DIR/hermesc hermesc -elif [[ "$OS" == CYGWIN* || "$OS" == MINGW* || "$OS" == MSYS* ]]; then - mklink -s ../hermes-engine-cli/$OS_DIR/hbcdump.exe hbcdump - mklink -s ../hermes-engine-cli/$OS_DIR/hdb.exe hdb - mklink -s ../hermes-engine-cli/$OS_DIR/hermes.exe hermes - mklink -s ../hermes-engine-cli/$OS_DIR/hermesc.exe hermesc -fi From 7bef992a1911bd77bb0920a05d0f0dd06a3f2c5a Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 19 Sep 2024 17:12:24 +0100 Subject: [PATCH 109/115] chore(ses): unpin hermes-engine-cli in package.json Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- packages/ses/package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ses/package.json b/packages/ses/package.json index 21e2e9c87a..05e284e136 100644 --- a/packages/ses/package.json +++ b/packages/ses/package.json @@ -100,7 +100,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.29.1", - "hermes-engine-cli": "0.12.0", + "hermes-engine-cli": "^0.12.0", "prettier": "^3.2.5", "sinon": "^15.1.0", "terser": "^5.16.6", diff --git a/yarn.lock b/yarn.lock index cce210a6ba..a33892d23a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5611,7 +5611,7 @@ __metadata: languageName: node linkType: hard -"hermes-engine-cli@npm:0.12.0": +"hermes-engine-cli@npm:^0.12.0": version: 0.12.0 resolution: "hermes-engine-cli@npm:0.12.0" checksum: 10c0/53a00336632cc7a743e9a88a5199865cf922d118f42f15bed4d2ed2fee635acd0d4d8563803b47e7c1bc2d17650281eb9188be8cfdaa25887243cfee840523be @@ -9211,7 +9211,7 @@ __metadata: eslint-config-prettier: "npm:^9.1.0" eslint-plugin-eslint-comments: "npm:^3.2.0" eslint-plugin-import: "npm:^2.29.1" - hermes-engine-cli: "npm:0.12.0" + hermes-engine-cli: "npm:^0.12.0" prettier: "npm:^3.2.5" sinon: "npm:^15.1.0" terser: "npm:^5.16.6" From 0bff9a058663e9ffec09af5ccd085cd191a63429 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:18:55 +0100 Subject: [PATCH 110/115] refactor(ses): note @babel/traverse todo for `node -r esm` compat --- packages/ses/scripts/hermesTransforms.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ses/scripts/hermesTransforms.js b/packages/ses/scripts/hermesTransforms.js index 842e238940..0ad0acfb6b 100644 --- a/packages/ses/scripts/hermesTransforms.js +++ b/packages/ses/scripts/hermesTransforms.js @@ -4,7 +4,11 @@ import babelGenerate from '@agoric/babel-generator'; import babelTraverse from '@babel/traverse'; import * as t from '@babel/types'; -// @ts-expect-error TS2339 Property 'default' does not exist +// TODO The following is sufficient on Node.js, but for compatibility with +// `node -r esm`, we must use the pattern below. +// Remove after https://github.com/Agoric/agoric-sdk/issues/8671. +// OR, upgrading to Babel 8 probably addresses this defect. +// @ts-expect-error TS2339 Property 'default' does not exist. const traverse = babelTraverse.default || babelTraverse; const generate = babelGenerate.default || babelGenerate; From a8e65934080b280d18b3e9cdce338883d59126c0 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:05:07 +0100 Subject: [PATCH 111/115] refactor(ses): commons async gen fn instance to avoid name dance Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- packages/ses/src/commons.js | 57 +++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index d1eee0d478..ea3f9ad568 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -379,31 +379,34 @@ export const FERAL_STACK_GETTER = feralStackGetter; */ export const FERAL_STACK_SETTER = feralStackSetter; -// Test for async generator function syntax support. -let AsyncGeneratorNewFunctionInstance; -try { - // Wrapping one in an new Function lets the `hermesc` binary file - // parse the Metro js bundle without SyntaxError, to generate the - // optimised Hermes bytecode bundle, when `gradlew` is called to - // assemble the release build APK for React Native prod Android apps. - // Delaying the error until runtime lets us customise lockdown behaviour. - AsyncGeneratorNewFunctionInstance = new FERAL_FUNCTION( - 'return (async function* AsyncGeneratorFunctionInstance() {})', - )(); -} catch (e) { - // @ts-expect-error ts(2339) Property 'jsEngine' does not exist on type 'Error'. However it exists on Hermes. - if (Error.prototype.jsEngine === 'hermes' && e.name === 'SyntaxError') { - // Swallows Hermes error `async generators are unsupported` at runtime. - // @ts-expect-error ts(2554) Expected 0 arguments, but got 1. It refers to the Web API Window object, but on Hermes we expect 1 argument. - // eslint-disable-next-line no-undef - print('SES: Skipping async generators, unsupported on Hermes'); - // Note: `console` is not a JS built-in, so Hermes engine throws: - // Uncaught ReferenceError: Property 'console' doesn't exist - // See: https://github.com/facebook/hermes/issues/675 - // However React Native provides a `console` implementation: - // https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/InitializeCore.js - } else { - throw e; +// eslint-disable-next-line consistent-return +const getAsyncGeneratorFunctionInstance = () => { + // Test for async generator function syntax support. + try { + // Wrapping one in an new Function lets the `hermesc` binary file + // parse the Metro js bundle without SyntaxError, to generate the + // optimised Hermes bytecode bundle, when `gradlew` is called to + // assemble the release build APK for React Native prod Android apps. + // Delaying the error until runtime lets us customise lockdown behaviour. + return new FERAL_FUNCTION( + 'return (async function* AsyncGeneratorFunctionInstance() {})', + )(); + } catch (e) { + // @ts-expect-error ts(2339) Property 'jsEngine' does not exist on type 'Error'. However it exists on Hermes. + if (Error.prototype.jsEngine === 'hermes' && e.name === 'SyntaxError') { + // Swallows Hermes error `async generators are unsupported` at runtime. + // @ts-expect-error ts(2554) Expected 0 arguments, but got 1. It refers to the Web API Window object, but on Hermes we expect 1 argument. + // eslint-disable-next-line no-undef + print('SES: Skipping async generators, unsupported on Hermes'); + // Note: `console` is not a JS built-in, so Hermes engine throws: + // Uncaught ReferenceError: Property 'console' doesn't exist + // See: https://github.com/facebook/hermes/issues/675 + // However React Native provides a `console` implementation: + // https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/InitializeCore.js + } else { + throw e; + } } -} -export const AsyncGeneratorFunctionInstance = AsyncGeneratorNewFunctionInstance; +}; +export const AsyncGeneratorFunctionInstance = + getAsyncGeneratorFunctionInstance(); From 6e1cb4994a85f5b2dc53e87fd4abda30f2c6beb2 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:19:21 +0100 Subject: [PATCH 112/115] refactor(ses): commons async gen fn instance consistent return --- packages/ses/src/commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index ea3f9ad568..4a4dbee76e 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -379,7 +379,6 @@ export const FERAL_STACK_GETTER = feralStackGetter; */ export const FERAL_STACK_SETTER = feralStackSetter; -// eslint-disable-next-line consistent-return const getAsyncGeneratorFunctionInstance = () => { // Test for async generator function syntax support. try { @@ -403,6 +402,7 @@ const getAsyncGeneratorFunctionInstance = () => { // See: https://github.com/facebook/hermes/issues/675 // However React Native provides a `console` implementation: // https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/InitializeCore.js + return undefined; } else { throw e; } From f543b169e040572de545a1ce6c0900e4e37920f8 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:56:09 +0100 Subject: [PATCH 113/115] fix(ses): commons async gen fn instance catch condition on Hermes VM --- packages/ses/src/commons.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index 4a4dbee76e..e986f250e7 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -391,8 +391,7 @@ const getAsyncGeneratorFunctionInstance = () => { 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); } catch (e) { - // @ts-expect-error ts(2339) Property 'jsEngine' does not exist on type 'Error'. However it exists on Hermes. - if (Error.prototype.jsEngine === 'hermes' && e.name === 'SyntaxError') { + if (e.name === 'SyntaxError') { // Swallows Hermes error `async generators are unsupported` at runtime. // @ts-expect-error ts(2554) Expected 0 arguments, but got 1. It refers to the Web API Window object, but on Hermes we expect 1 argument. // eslint-disable-next-line no-undef From 2dc851c0bfa1971f89cc561b0f7b4279cccfcd96 Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:06:01 +0100 Subject: [PATCH 114/115] refactor(ses): document Error.prototype.jsEngine in commons --- packages/ses/src/commons.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index e986f250e7..f51dbd312a 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -391,6 +391,8 @@ const getAsyncGeneratorFunctionInstance = () => { 'return (async function* AsyncGeneratorFunctionInstance() {})', )(); } catch (e) { + // Note: `Error.prototype.jsEngine` is only set by React Native runtime, not Hermes: + // https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/hermes/executor/HermesExecutorFactory.cpp#L224-L230 if (e.name === 'SyntaxError') { // Swallows Hermes error `async generators are unsupported` at runtime. // @ts-expect-error ts(2554) Expected 0 arguments, but got 1. It refers to the Web API Window object, but on Hermes we expect 1 argument. From 9112d4532e461c8fd1d39e46a8a6506138e432ec Mon Sep 17 00:00:00 2001 From: LeoTM <1881059+leotm@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:12:48 +0100 Subject: [PATCH 115/115] refactor(ses): commons async gen fn instance update comment --- packages/ses/src/commons.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ses/src/commons.js b/packages/ses/src/commons.js index f51dbd312a..b09d7a9476 100644 --- a/packages/ses/src/commons.js +++ b/packages/ses/src/commons.js @@ -401,7 +401,7 @@ const getAsyncGeneratorFunctionInstance = () => { // Note: `console` is not a JS built-in, so Hermes engine throws: // Uncaught ReferenceError: Property 'console' doesn't exist // See: https://github.com/facebook/hermes/issues/675 - // However React Native provides a `console` implementation: + // However React Native provides a `console` implementation when setting up error handling: // https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/InitializeCore.js return undefined; } else {