From 317c6800d6b561bc99323149282da501804b0157 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Mon, 8 Apr 2024 14:13:29 -0700 Subject: [PATCH] fix(endomoat): create policy for the default attenuator ...instead of just allowing everything. --- packages/endomoat/package.json | 3 +- .../endomoat/scripts/update-own-policy.js | 29 +++++++++++++++++ packages/endomoat/scripts/use-self/index.js | 1 + .../endomoat/scripts/use-self/package.json | 9 ++++++ packages/endomoat/src/index.js | 2 +- packages/endomoat/src/policy-converter.js | 31 ++++++++++--------- packages/endomoat/src/policy-override.json | 18 +++++++++++ .../endomoat/test/policy-converter.spec.js | 23 +++++++++++--- 8 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 packages/endomoat/scripts/update-own-policy.js create mode 100644 packages/endomoat/scripts/use-self/index.js create mode 100644 packages/endomoat/scripts/use-self/package.json create mode 100644 packages/endomoat/src/policy-override.json diff --git a/packages/endomoat/package.json b/packages/endomoat/package.json index 7c29b2c7dc..151ce296a6 100644 --- a/packages/endomoat/package.json +++ b/packages/endomoat/package.json @@ -36,7 +36,8 @@ "scripts": { "lint:deps": "depcheck", "test": "npm run test:run", - "test:run": "ava" + "test:run": "ava", + "update-policy": "node ./scripts/update-own-policy.js" }, "dependencies": { "@endo/compartment-mapper": "1.1.4", diff --git a/packages/endomoat/scripts/update-own-policy.js b/packages/endomoat/scripts/update-own-policy.js new file mode 100644 index 0000000000..c2b20baf67 --- /dev/null +++ b/packages/endomoat/scripts/update-own-policy.js @@ -0,0 +1,29 @@ +/** + * This script generates a policy for endomoat itself. This is needed to allow + * the default attenuator to execute. + * + * The result of this is merged into the user-provided policy (or policies) + * during conversion to an Endo policy. Because the Endo policy is not + * persisted, making changes in endomoat won't break existing policies. + * + * By persisting the policy to disk, we tradeoff initial execution time for + * needing to update the policy before release. Is this a good idea? I don't + * know. + * + * @packageDocumentation + */ + +import { fileURLToPath } from 'node:url' +import { generateAndWritePolicy } from '../src/index.js' + +const PHONY_ENTRYPOINT = new URL('./use-self/index.js', import.meta.url) + +const POLICY_OVERRIDE_PATH = fileURLToPath( + new URL('../src/policy-override.json', import.meta.url) +) + +generateAndWritePolicy(PHONY_ENTRYPOINT, { + policyPath: POLICY_OVERRIDE_PATH, +}).then(() => { + console.error('Wrote %s', POLICY_OVERRIDE_PATH) +}) diff --git a/packages/endomoat/scripts/use-self/index.js b/packages/endomoat/scripts/use-self/index.js new file mode 100644 index 0000000000..9053eef34a --- /dev/null +++ b/packages/endomoat/scripts/use-self/index.js @@ -0,0 +1 @@ +import '@lavamoat/endomoat/attenuator' diff --git a/packages/endomoat/scripts/use-self/package.json b/packages/endomoat/scripts/use-self/package.json new file mode 100644 index 0000000000..a96641cb69 --- /dev/null +++ b/packages/endomoat/scripts/use-self/package.json @@ -0,0 +1,9 @@ +{ + "name": "use-self", + "version": "0.0.0", + "type": "module", + "main": "index.js", + "dependencies": { + "@lavamoat/endomoat": "file:../.." + } +} diff --git a/packages/endomoat/src/index.js b/packages/endomoat/src/index.js index a36c1182b2..6fcc67240f 100644 --- a/packages/endomoat/src/index.js +++ b/packages/endomoat/src/index.js @@ -73,7 +73,7 @@ export async function run(entrypointPath, policyOrOpts = {}, opts = {}) { policy = await generatePolicy(entrypointPath, generateOpts) } - const endoPolicy = toEndoPolicy(policy) + const endoPolicy = await toEndoPolicy(policy) const readPowers = makeReadPowers(runOpts.readPowers) const url = diff --git a/packages/endomoat/src/policy-converter.js b/packages/endomoat/src/policy-converter.js index 0598f37f25..6f7880f18a 100644 --- a/packages/endomoat/src/policy-converter.js +++ b/packages/endomoat/src/policy-converter.js @@ -1,3 +1,4 @@ +import { mergePolicy } from 'lavamoat-core' import { LAVAMOAT_PKG_POLICY_ROOT, LAVAMOAT_PKG_POLICY_VALUE_DYNAMIC, @@ -8,6 +9,7 @@ import { RSRC_POLICY_GLOBALS, RSRC_POLICY_PKGS, } from './constants.js' +import { readPolicy } from './policy.js' const { isArray } = Array const { entries, fromEntries } = Object @@ -68,7 +70,8 @@ function toEndoRsrcPkgsPolicyBuiltins(item) { * Converts LavaMoat `ResourcePolicy.packages` to Endo's * `PackagePolicy.packages` * - * @param {Record} [item] - A value in `ResourcePolicy` + * @param {import('lavamoat-core').PackagePolicy} [item] - A value in + * `ResourcePolicy` * @returns {import('./types.js').LavaMoatPackagePolicy['packages']} */ function toEndoRsrcPkgsPolicyPkgs(item) { @@ -132,9 +135,9 @@ function toEndoRsrcPkgsPolicyGlobals(item) { function toEndoRsrcPkgsPolicy(resources) { /** @type {import('./types.js').LavaMoatPackagePolicy} */ const pkgPolicy = { - packages: toEndoRsrcPkgsPolicyPkgs(resources.packages), - globals: toEndoRsrcPkgsPolicyGlobals(resources.globals), - builtins: toEndoRsrcPkgsPolicyBuiltins(resources.builtin), + [RSRC_POLICY_PKGS]: toEndoRsrcPkgsPolicyPkgs(resources.packages), + [RSRC_POLICY_GLOBALS]: toEndoRsrcPkgsPolicyGlobals(resources.globals), + [RSRC_POLICY_BUILTINS]: toEndoRsrcPkgsPolicyBuiltins(resources.builtin), } return pkgPolicy } @@ -143,12 +146,18 @@ function toEndoRsrcPkgsPolicy(resources) { * Converts a LavaMoat policy to an Endo policy * * @param {import('lavamoat-core').LavaMoatPolicy} lmPolicy - * @returns {import('./types.js').LavaMoatEndoPolicy} + * @returns {Promise} */ -export function toEndoPolicy(lmPolicy) { +export async function toEndoPolicy(lmPolicy) { + // policy for self; needed for attenuator + const overrides = await readPolicy( + new URL('./policy-override.json', import.meta.url) + ) + + const finalLMPolicy = mergePolicy(lmPolicy, overrides) + /** @type {import('./types.js').LavaMoatEndoPolicy} */ const endoPolicy = { - //TODO: generate a policy resource for the default attenuator defaultAttenuator: DEFAULT_ATTENUATOR, entry: { [RSRC_POLICY_GLOBALS]: [POLICY_ITEM_ROOT], @@ -157,18 +166,12 @@ export function toEndoPolicy(lmPolicy) { noGlobalFreeze: true, }, resources: fromEntries( - entries(lmPolicy.resources ?? {}).map(([rsrcName, rsrcPolicy]) => [ + entries(finalLMPolicy.resources ?? {}).map(([rsrcName, rsrcPolicy]) => [ rsrcName, toEndoRsrcPkgsPolicy(rsrcPolicy), ]) ), } - // add this to make endo allow the attenuator at all, TODO: generate this from the policy or build into Endo - endoPolicy.resources['@lavamoat/endomoat'] = { - [RSRC_POLICY_PKGS]: POLICY_ITEM_WILDCARD, - [RSRC_POLICY_GLOBALS]: POLICY_ITEM_WILDCARD, - [RSRC_POLICY_BUILTINS]: POLICY_ITEM_WILDCARD, - } return endoPolicy } diff --git a/packages/endomoat/src/policy-override.json b/packages/endomoat/src/policy-override.json new file mode 100644 index 0000000000..bc7de83a61 --- /dev/null +++ b/packages/endomoat/src/policy-override.json @@ -0,0 +1,18 @@ +{ + "resources": { + "lavamoat-core": { + "globals": { + "console.warn": true + } + }, + "@lavamoat/endomoat": { + "packages": { + "lavamoat-core": true + }, + "builtin": { + "node:console": true, + "node:path": true + } + } + } +} diff --git a/packages/endomoat/test/policy-converter.spec.js b/packages/endomoat/test/policy-converter.spec.js index 50664eaecc..7ed56343d3 100644 --- a/packages/endomoat/test/policy-converter.spec.js +++ b/packages/endomoat/test/policy-converter.spec.js @@ -9,7 +9,7 @@ import { toEndoPolicy } from '../src/policy-converter.js' * import('../src/types.js').RootPolicy} LavaMoatPackagePolicyItem */ -test('toEndoPolicy - basic', (t) => { +test('toEndoPolicy - basic', async (t) => { /** @type {import('lavamoat-core').LavaMoatPolicy} */ const lmPolicy = { resources: { @@ -38,10 +38,22 @@ test('toEndoPolicy - basic', (t) => { builtins: POLICY_ITEM_WILDCARD, }, resources: { + 'lavamoat-core': { + globals: { + 'console.warn': true, + }, + builtins: undefined, + packages: undefined, + }, '@lavamoat/endomoat': { - globals: POLICY_ITEM_WILDCARD, - packages: POLICY_ITEM_WILDCARD, - builtins: POLICY_ITEM_WILDCARD, + packages: { + 'lavamoat-core': true, + }, + globals: undefined, + builtins: { + 'node:console': true, + 'node:path': true, + }, }, a: { packages: { b: true }, @@ -56,5 +68,6 @@ test('toEndoPolicy - basic', (t) => { }, } - t.deepEqual(toEndoPolicy(lmPolicy), expected) + const actual = await toEndoPolicy(lmPolicy) + t.deepEqual(actual, expected) })