feat(ses): Expand TypeScript coverage for Compartment and lockdown
MODIFY
packages/ses/index.d.ts
packages/ses/index.d.ts
/**
* Transitively freeze an object.
*/
-type Harden = <T>(x: T) => T;
-
-declare var harden: Harden;
+import type { Hardener } from '@agoric/make-hardener';
+import { makeLockdown } from './src/lockdown-shim.js';
+import { makeCompartmentConstructor } from './src/compartment-shim.js';
namespace global {
- declare var harden: Harden;
+ declare let harden : Hardener<T>;
+ declare let lockdown : ReturnType<makeLockdown>;
+ declare let Compartment : ReturnType<makeCompartmentConstructor>;
}

MODIFY
packages/ses/jsconfig.json
packages/ses/jsconfig.json
"strictNullChecks": true,
"moduleResolution": "node"
},
- "include": ["src/**/*.js"]
+ "include": ["src/**/*.js", "index.d.ts"]
}

MODIFY
packages/ses/src/compartment-shim.js
packages/ses/src/compartment-shim.js
+// @ts-check
+
// This module exports both Compartment and StaticModuleRecord because they
// communicate through the moduleAnalyses private side-table.
import {
@@ -22,6 +24,10 @@ import {
// privateFields captures the private state for each compartment.
const privateFields = new WeakMap();
+/**
+ * @typedef {(source: string) => string} Transform
+ */
+
export const CompartmentPrototype = {
constructor: InertCompartment,
@@ -37,7 +43,11 @@ export const CompartmentPrototype = {
* @param {string} source is a JavaScript program grammar construction.
* @param {Object} [options]
* @param {Array<Transform>} [options.transforms]
- * @param {bool} [options.sloppyGlobalsMode]
+ * @param {boolean} [options.sloppyGlobalsMode]
+ * @param {Object} [options.__moduleShimLexicals__]
+ * @param {boolean} [options.__evadeHtmlCommentTest__]
+ * @param {boolean} [options.__evadeImportExpressionTest__]
+ * @param {boolean} [options.__rejectSomeDirectEvalExpressions__]
*/
evaluate(source, options = {}) {
// Perform this check first to avoid unecessary sanitizing.
@@ -106,13 +116,22 @@ defineProperties(InertCompartment, {
prototype: { value: CompartmentPrototype },
});
+/**
+ * @template CompartmentConstructor
+ * @callback CompartmentConstructorMaker
+ * @param {CompartmentConstructorMaker<CompartmentConstructor>} targetMakeCompartmentConstructor
+ * @param {Object} intrinsics
+ * @param {(object: Object) => void} nativeBrander
+ * @returns CompartmentConstructor
+ */
+
+/** @type {CompartmentConstructorMaker<Compartment>} */
export const makeCompartmentConstructor = (
targetMakeCompartmentConstructor,
intrinsics,
nativeBrander,
) => {
/**
- * Compartment()
* Each Compartment constructor is a global. A host that wants to execute
* code in a context bound to a new global creates a new compartment.
*

MODIFY
packages/ses/src/error/console.js
packages/ses/src/error/console.js
@@ -115,6 +115,9 @@ const makeLoggingConsoleKit = () => {
// Use an arrow function so that it doesn't come with its own name in
// its printed form. Instead, we're hoping that tooling uses only
// the `.name` property set below.
+ /**
+ * @param {...any} args
+ */
const method = (...args) => {
logArray.push([name, ...args]);
};
@@ -188,6 +191,11 @@ const makeCausalConsole = (baseConsole, loggedErrorHandler) => {
return `${err.name}#${errNum}`;
};
+ /**
+ * @param {ReadonlyArray<any>} logArgs
+ * @param {Array<any>} subErrorsSink
+ * @returns {any}
+ */
const extractErrorArgs = (logArgs, subErrorsSink) => {
const argTags = logArgs.map(arg => {
if (arg instanceof Error) {
@@ -254,6 +262,9 @@ const makeCausalConsole = (baseConsole, loggedErrorHandler) => {
logSubErrors(tagError(error), subErrors);
};
+ /**
+ * @param {Error} error
+ */
const logError = error => {
if (errorsLogged.has(error)) {
return;
@@ -292,6 +303,9 @@ const makeCausalConsole = (baseConsole, loggedErrorHandler) => {
};
const levelMethods = consoleLevelMethods.map(([level, _]) => {
+ /**
+ * @param {...any} logArgs
+ */
const levelMethod = (...logArgs) => {
const subErrors = [];
const argTags = extractErrorArgs(logArgs, subErrors);
@@ -306,6 +320,9 @@ const makeCausalConsole = (baseConsole, loggedErrorHandler) => {
([name, _]) => name in baseConsole,
);
const otherMethods = otherMethodNames.map(([name, _]) => {
+ /**
+ * @param {...any} args
+ */
const otherMethod = (...args) => {
// @ts-ignore
baseConsole[name](...args);
@@ -328,6 +345,9 @@ const filterConsole = (baseConsole, filter, _topic = undefined) => {
// TODO do something with optional topic string
const whilelist = consoleWhitelist.filter(([name, _]) => name in baseConsole);
const methods = whilelist.map(([name, severity]) => {
+ /**
+ * @param {...any} args
+ */
const method = (...args) => {
if (severity === undefined || filter.canLog(severity)) {
// @ts-ignore

MODIFY
packages/ses/src/error/internal-types.js
packages/ses/src/error/internal-types.js
// @ts-check
-/// <reference types="ses"/>
/**
* @typedef {readonly any[]} LogArgs

MODIFY
packages/ses/src/error/types.js
packages/ses/src/error/types.js
-// @ts-check
-/// <reference types="ses"/>
-
// Much of this file is duplicated at
// https://github.com/Agoric/agoric-sdk/blob/master/packages/assert/src/types.js
// Coordinate edits until we refactor to avoid this duplication
+// @ts-check
+
/**
* @callback BaseAssert
* The `assert` function itself.

MODIFY
packages/ses/src/lockdown-shim.js
packages/ses/src/lockdown-shim.js
// See the License for the specific language governing permissions and
// limitations under the License.
+// @ts-check
+
import makeHardener from '@agoric/make-hardener';
import { keys } from './commons.js';
import { makeIntrinsicsCollector } from './intrinsics.js';
@@ -31,6 +33,19 @@ import { tameConsole } from './error/tame-console.js';
import tameErrorConstructor from './error/tame-error-constructor.js';
import { assert } from './error/assert.js';
+/**
+ * @typedef {{
+ * dateTaming?: 'safe' | 'unsafe',
+ * errorTaming?: 'safe' | 'unsafe',
+ * mathTaming?: 'safe' | 'unsafe',
+ * regExpTaming?: 'safe' | 'unsafe',
+ * localeTaming?: 'safe' | 'unsafe',
+ * consoleTaming?: 'safe' | 'unsafe',
+ * overrideTaming?: 'min' | 'moderate',
+ * stackFiltering?: 'concise' | 'verbose',
+ * }} LockdownOptions
+ */
+
const { details: d, quote: q } = assert;
let firstOptions;
@@ -43,6 +58,11 @@ let lockedDown = false;
// Gate it on lockdown.
const lockdownHarden = makeHardener();
+/**
+ * @template T
+ * @param {T} ref
+ * @returns {T}
+ */
export const harden = ref => {
assert(lockedDown, 'Cannot harden before lockdown');
return lockdownHarden(ref);
@@ -50,6 +70,37 @@ export const harden = ref => {
const alreadyHardenedIntrinsics = () => false;
+/**
+ * @callback Transform
+ * @param {string} source
+ * @returns {string}
+ */
+
+/**
+ * @callback CompartmentConstructor
+ * @param {Object} endowments
+ * @param {Object} moduleMap
+ * @param {Object} [options]
+ * @param {Array<Transform>} [options.transforms]
+ * @param {Array<Transform>} [options.__shimTransforms__]
+ * @param {Object} [options.globalLexicals]
+ */
+
+/**
+ * @callback CompartmentConstructorMaker
+ * @param {CompartmentConstructorMaker} targetMakeCompartmentConstructor
+ * @param {Object} intrinsics
+ * @param {(func: Function) => void} nativeBrander
+ * @returns {CompartmentConstructor}
+ */
+
+/**
+ * @param {CompartmentConstructorMaker} makeCompartmentConstructor
+ * @param {Object} compartmentPrototype
+ * @param {() => Object} getAnonymousIntrinsics
+ * @param {LockdownOptions} [options]
+ * @returns {() => {}} repairIntrinsics
+ */
export function repairIntrinsics(
makeCompartmentConstructor,
compartmentPrototype,
@@ -80,7 +131,7 @@ export function repairIntrinsics(
// is useful. See
// [`stackFiltering` options](https://github.com/Agoric/SES-shim/blob/master/packages/ses/lockdown-options.md#stackfiltering-options)
// for an explanation.
- options = { ...firstOptions, ...options };
+ options = /** @type {LockdownOptions} */ ({ ...firstOptions, ...options });
const {
dateTaming = 'safe',
errorTaming = 'safe',
@@ -153,7 +204,7 @@ export function repairIntrinsics(
optGetStackString = intrinsics['%InitialGetStackString%'];
}
const consoleRecord = tameConsole(consoleTaming, optGetStackString);
- globalThis.console = consoleRecord.console;
+ globalThis.console = /** @type {Console} */ (consoleRecord.console);
// Replace *Locale* methods with their non-locale equivalents
tameLocaleMethods(intrinsics, localeTaming);
@@ -212,11 +263,19 @@ export function repairIntrinsics(
return hardenIntrinsics;
}
+/**
+ * @param {CompartmentConstructorMaker} makeCompartmentConstructor
+ * @param {Object} compartmentPrototype
+ * @param {() => Object} getAnonymousIntrinsics
+ */
export const makeLockdown = (
makeCompartmentConstructor,
compartmentPrototype,
getAnonymousIntrinsics,
) => {
+ /**
+ * @param {LockdownOptions} [options]
+ */
const lockdown = (options = {}) => {
const maybeHardenIntrinsics = repairIntrinsics(
makeCompartmentConstructor,

feat(ses): Expand TypeScript coverage for Compartment and lockdown (#584)