diff --git a/packages/endomoat/src/policy-gen/index.js b/packages/endomoat/src/policy-gen/index.js index 5715dfbc06..3488cacdd3 100644 --- a/packages/endomoat/src/policy-gen/index.js +++ b/packages/endomoat/src/policy-gen/index.js @@ -23,6 +23,7 @@ const { fromEntries, entries } = Object * readPowers?: * | import('@endo/compartment-mapper').ReadFn * | import('@endo/compartment-mapper').ReadPowers + * debug?: boolean * } * >} GeneratePolicyOptions */ @@ -31,9 +32,32 @@ const { fromEntries, entries } = Object * Generates a LavaMoat policy from a given entry point using * `@endo/compartment-mapper` * + * @overload * @param {string | URL} entrypointPath - * @param {GeneratePolicyOptions} opts + * @param {GeneratePolicyOptions} [opts] * @returns {Promise} + * @public + */ + +/** + * Generates a LavaMoat debug policy from a given entry point using + * `@endo/compartment-mapper` + * + * @overload + * @param {string | URL} entrypointPath + * @param {GeneratePolicyOptions & { debug: true }} opts + * @returns {Promise} + * @public + */ + +/** + * Generates a LavaMoat policy or debug policy from a given entry point using + * `@endo/compartment-mapper` + * + * @param {string | URL} entrypointPath + * @param {GeneratePolicyOptions} [opts] + * @returns {Promise} + * @public */ export async function generatePolicy( entrypointPath, @@ -48,11 +72,16 @@ export async function generatePolicy( const read = typeof readPowers === 'function' ? readPowers : readPowers.read + const baseOpts = { read, policyOverride } + + // this weird thing is to make TS happy about the overload + const opts = debug ? { debug: true, ...baseOpts } : baseOpts + return await PolicyGenerator.generatePolicy( compartmentMap, sources, renames, - { debug, read, policyOverride } + opts ) } @@ -65,6 +94,7 @@ export async function generatePolicy( * | import('@endo/compartment-mapper').ReadFn * | import('@endo/compartment-mapper').ReadPowers * }} opts + * @internal */ export async function loadCompartmentMap( entrypointPath, diff --git a/packages/endomoat/src/policy-gen/policy-generator-context.js b/packages/endomoat/src/policy-gen/policy-generator-context.js index cd00e31220..ca2df46864 100644 --- a/packages/endomoat/src/policy-gen/policy-generator-context.js +++ b/packages/endomoat/src/policy-gen/policy-generator-context.js @@ -45,7 +45,7 @@ export class PolicyGeneratorContext { /** * Internal cache for {@link LavamoatModuleRecord} objects * - * @type {import('./lmr-cache.js').LMRCache} + * @type {Readonly} */ #lmrCache @@ -61,7 +61,7 @@ export class PolicyGeneratorContext { * import('@endo/compartment-mapper').CompartmentDescriptor * >} compartment * @param {Readonly>} renames - * @param {import('./lmr-cache.js').LMRCache} lmrCache + * @param {Readonly} lmrCache * @param {Readonly} opts */ constructor( diff --git a/packages/endomoat/src/policy-gen/policy-generator.js b/packages/endomoat/src/policy-gen/policy-generator.js index 3de258386f..82828e7a24 100644 --- a/packages/endomoat/src/policy-gen/policy-generator.js +++ b/packages/endomoat/src/policy-gen/policy-generator.js @@ -10,7 +10,6 @@ const { entries } = Object * Options for {@link PolicyGenerator} and {@link PolicyGenerator.generatePolicy} * * @typedef PolicyGeneratorOptions - * @property {boolean} [debug] * @property {import('@endo/compartment-mapper').ReadFn} [read] * @property {import('lavamoat-core').LavaMoatPolicyOverrides} [policyOverride] */ @@ -19,9 +18,17 @@ const { entries } = Object * Service which generates a LavaMoat policy from a */ export class PolicyGenerator { - /** @type {LMRCache} */ + /** + * Cache of `LavamoatModuleRecord` objects + * + * @type {Readonly} + */ #lmrCache + /** + * Creates {@link PolicyGeneratorContext} instances for each compartment in + * `compartmentMap`. + * * @param {Readonly< * import('@endo/compartment-mapper').CompartmentMapDescriptor * >} compartmentMap @@ -33,30 +40,40 @@ export class PolicyGenerator { compartmentMap, sources, renames, - { - read = defaultReadPower, - debug: includeDebugInfo = false, - policyOverride, - } = {} + { read = defaultReadPower, policyOverride } = {} ) { /** + * Compartment sources + * * @type {Readonly} + * @internal */ this.sources = sources /** + * Compartment map + * * @type {Readonly< * import('@endo/compartment-mapper').CompartmentMapDescriptor * >} + * @internal */ this.compartmentMap = compartmentMap + /** + * Cache of `LavamoatModuleRecord` objects + */ this.#lmrCache = new LMRCache() const entryCompartment = compartmentMap.compartments[compartmentMap.entry.compartment] - /** @type {Map} */ + /** + * Mapping of compartment names to {@link PolicyGeneratorContext} instances + * + * @type {Readonly>} + * @internal + */ this.contexts = new Map( entries(compartmentMap.compartments).map( ([compartmentName, compartment]) => [ @@ -69,11 +86,14 @@ export class PolicyGenerator { ) ) - this.inspector = createModuleInspector({ - isBuiltin: nodeIsBuiltin, - includeDebugInfo, - }) - + /** + * Override policy, if any + * + * @type {Readonly< + * import('lavamoat-core').LavaMoatPolicyOverrides | undefined + * >} + * @internal + */ this.policyOverride = policyOverride } @@ -87,8 +107,6 @@ export class PolicyGenerator { async buildModuleRecords() { await Promise.resolve() - this.#lmrCache.clear() - let moduleRecords = /** @type {import('lavamoat-core').LavamoatModuleRecord[]} */ ( ( @@ -121,17 +139,21 @@ export class PolicyGenerator { } /** - * Inspects a compartment map and sources, then generates module records. + * Uses `inspector` to inspect a compartment map and sources. * + * @param {import('lavamoat-core').ModuleInspector} inspector Module inspector * @param {import('lavamoat-core').LavamoatModuleRecord[]} moduleRecords - * @returns {Promise} + * Module records + * @returns {import('lavamoat-core').ModuleInspector} The inspector * @internal */ - async inspectModuleRecords(moduleRecords) { + inspectModuleRecords(inspector, moduleRecords) { // FIXME: should we sort here? for (const record of moduleRecords) { - this.inspector.inspectModule(record) + inspector.inspectModule(record) } + + return inspector } /** @@ -144,14 +166,24 @@ export class PolicyGenerator { * 2. Inspect the module records using LavaMoat's `ModuleInspector` * 3. Generate the policy using the `ModuleInspector` * - * @returns {Promise} Generated policy + * @param {boolean} [debug] - If `true`, the result will be a debug policy + * @returns {Promise< + * | import('lavamoat-core').LavaMoatPolicy + * | import('lavamoat-core').LavaMoatPolicyDebug + * >} + * Generated policy + * @internal + * @todo Overload this to handle the `debug` parameter */ - async generatePolicy() { + async generatePolicy(debug) { const moduleRecords = await this.buildModuleRecords() - await this.inspectModuleRecords(moduleRecords) + const inspector = createModuleInspector({ + isBuiltin: nodeIsBuiltin, + includeDebugInfo: debug, + }) - return this.inspector.generatePolicy({ + return this.inspectModuleRecords(inspector, moduleRecords).generatePolicy({ policyOverride: this.policyOverride, }) } @@ -159,21 +191,51 @@ export class PolicyGenerator { /** * Instantiates a {@link PolicyGenerator} and generates a policy. * + * @overload * @param {Readonly< * import('@endo/compartment-mapper').CompartmentMapDescriptor * >} compartmentMap * @param {Readonly} sources * @param {Readonly>} renames - * @param {PolicyGeneratorOptions} opts + * @param {PolicyGeneratorOptions} [opts] + * @returns {Promise} Generated policy + */ + + /** + * Instantiates a {@link PolicyGenerator} and generates a debug policy. + * + * @overload + * @param {Readonly< + * import('@endo/compartment-mapper').CompartmentMapDescriptor + * >} compartmentMap + * @param {Readonly} sources + * @param {Readonly>} renames + * @param {PolicyGeneratorOptions & { debug: true }} opts + * @returns {Promise} Generated + * debug policy + * @public + */ + + /** + * Instantiates a {@link PolicyGenerator} and generates a policy. + * + * @param {Readonly< + * import('@endo/compartment-mapper').CompartmentMapDescriptor + * >} compartmentMap + * @param {Readonly} sources + * @param {Readonly>} renames + * @param {PolicyGeneratorOptions & { debug?: boolean }} [opts] * @returns {Promise} Generated policy + * @public */ static async generatePolicy(compartmentMap, sources, renames, opts) { + const { debug, ...restOpts } = opts ?? {} const generator = new PolicyGenerator( compartmentMap, sources, renames, - opts + restOpts ) - return generator.generatePolicy() + return generator.generatePolicy(debug) } }