Skip to content

Commit

Permalink
chore: updates based on endojs/endo#1838
Browse files Browse the repository at this point in the history
  • Loading branch information
boneskull committed Nov 8, 2023
1 parent fbca5f5 commit fb7b0da
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 82 deletions.
88 changes: 87 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions packages/endomoat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"main": "src/index.js",
"license": "MIT",
"dependencies": {
"@endo/compartment-mapper": "^0.9.2",
"@endo/evasive-transform": "^0.1.3",
"@types/node": "^20.8.5",
"ses": "^0.18.8",
"type-fest": "^4.4.0"
Expand All @@ -29,7 +31,8 @@
"author": "Lavamoat Project",
"homepage": "https://github.com/LavaMoat/LavaMoat/tree/main/packages/endomoat",
"engines": {
"node": ">=14.0.0"
"node": "^16.20.0 || ^18.0.0 || ^20.0.0",
"npm": ">=7.0.0"
},
"ava": {
"files": [
Expand All @@ -39,8 +42,7 @@
},
"exports": {
".": "./src/index.js",
"./attenuator/default": "./src/default-attenuator.js",
"./attenuator/property": "./src/property-attenuator.js"
"./attenuator": "./src/default-attenuator.js"
},
"private": true
}
109 changes: 55 additions & 54 deletions packages/endomoat/src/default-attenuator.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,66 @@
import { ENDO_ROOT_POLICY as ROOT_POLICY } from './constants.js'
import {
copyWrappedGlobals,
getEndowmentsForConfig,
// @ts-expect-error - needs exports
} from 'lavamoat-core/src/endowmentsToolkit.js'
// @ts-expect-error - needs exports
import * as EndowmentsToolkit from 'lavamoat-core/src/endowmentsToolkit.js'

const { copyWrappedGlobals, getEndowmentsForConfig } = EndowmentsToolkit

const { keys, fromEntries, defineProperties, getOwnPropertyDescriptors } =
Object

/** @type {object} */
let rootCompartmentGlobalThis

export default {
/**
* @type {import('@endo/compartment-mapper').GlobalAttenuatorFn<[import('./policy-converter.js').LavaMoatPackagePolicy['globals']]>}
*/
attenuateGlobals(params, originalGlobalThis, packageCompartmentGlobalThis) {
const policy = params[0]
if (!policy) {
return
}
console.debug('attenuateGlobals called', params)
if (policy === ROOT_POLICY) {
rootCompartmentGlobalThis = packageCompartmentGlobalThis
// ^ this is a little dumb, but only a little - assuming importLocation is called only once in parallel. The thing is - even if it isn't, the new one will have a new copy of this module anyway.
// That is unless we decide to use `modules` for passing the attenuator, in which case we have an attenuator defined outside of Endo and we can scope it as we wish. Tempting. Slightly less secure, because if we have a prototype pollution or RCE in the attenuator, we're exposing the outside instead of the attenuators compartment.
copyWrappedGlobals(originalGlobalThis, packageCompartmentGlobalThis, [
'globalThis',
'global',
])
} else {
// TODO: getEndowmentsForConfig doesn't implement support for "write"
const endowments = getEndowmentsForConfig(
rootCompartmentGlobalThis,
policy,
// rootCompartmentGlobalThis, // Not sure if it works, but with this as a 3rd argument, in theory, each compartment would unwrap functions to the root conpartment's globalThis, where all copied functions are set up to unwrap to actual globalThis
// instead I'm opting for a single unwrap since we now have access to the actual globalThis
originalGlobalThis,
packageCompartmentGlobalThis
)

defineProperties(
packageCompartmentGlobalThis,
getOwnPropertyDescriptors(endowments)
)
}
// Write is per field not for all globals. It'll need to be implemented in getEndowmentsForConfig or the defineProperties step afterwards when it gets handled by another function from endowmentsToolkit (the latter more likely)
// - if (policy === WRITE_POLICY) {
// - throw new Error('Not yet implemented')
// - }
},
/**
* @type {import('@endo/compartment-mapper').GlobalAttenuatorFn<[import('./policy-converter.js').LavaMoatPackagePolicy['globals']]>}
*/
export function attenuateGlobals(
params,
originalGlobalThis,
packageCompartmentGlobalThis
) {
const policy = params[0]
if (!policy) {
return
}
console.debug('attenuateGlobals called', params)
if (policy === ROOT_POLICY) {
rootCompartmentGlobalThis = packageCompartmentGlobalThis
// ^ this is a little dumb, but only a little - assuming importLocation is called only once in parallel. The thing is - even if it isn't, the new one will have a new copy of this module anyway.
// That is unless we decide to use `modules` for passing the attenuator, in which case we have an attenuator defined outside of Endo and we can scope it as we wish. Tempting. Slightly less secure, because if we have a prototype pollution or RCE in the attenuator, we're exposing the outside instead of the attenuators compartment.
copyWrappedGlobals(originalGlobalThis, packageCompartmentGlobalThis, [
'globalThis',
'global',
])
} else {
// TODO: getEndowmentsForConfig doesn't implement support for "write"
const endowments = getEndowmentsForConfig(
rootCompartmentGlobalThis,
policy,
// rootCompartmentGlobalThis, // Not sure if it works, but with this as a 3rd argument, in theory, each compartment would unwrap functions to the root conpartment's globalThis, where all copied functions are set up to unwrap to actual globalThis
// instead I'm opting for a single unwrap since we now have access to the actual globalThis
originalGlobalThis,
packageCompartmentGlobalThis
)

/**
* Picks stuff in the policy out of the original object
* @type {import('@endo/compartment-mapper').ModuleAttenuatorFn<[import('./policy-converter.js').LavaMoatPackagePolicy['packages']]>}
*/
attenuateModule(params, originalObject) {
console.debug('attenuateModule called', params)
const ns = fromEntries(
keys(params).map((key) => [key, /** @type {any} */ (originalObject)[key]])
defineProperties(
packageCompartmentGlobalThis,
getOwnPropertyDescriptors(endowments)
)
return ns
},
}
// Write is per field not for all globals. It'll need to be implemented in getEndowmentsForConfig or the defineProperties step afterwards when it gets handled by another function from endowmentsToolkit (the latter more likely)
// - if (policy === WRITE_POLICY) {
// - throw new Error('Not yet implemented')
// - }
}

/**
* Picks stuff in the policy out of the original object
* @type {import('@endo/compartment-mapper').ModuleAttenuatorFn<[import('./policy-converter.js').LavaMoatPackagePolicy['packages']]>}
*/
export function attenuateModule(params, originalObject) {
console.debug('attenuateModule called', params)
const ns = fromEntries(
keys(params).map((key) => [key, /** @type {any} */ (originalObject)[key]])
)
return ns
}
32 changes: 22 additions & 10 deletions packages/endomoat/src/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import 'ses'
import { evadeCensor } from '@endo/evasive-transform'
import { toEndoPolicy } from './policy-converter.js'
import fs from 'node:fs'
import { importLocation } from '@endo/compartment-mapper'

export * from './policy-converter.js'
export * from './constants.js'

import { toEndoPolicy } from './policy-converter.js'

import fs from 'fs'

import { importLocation } from '@endo/compartment-mapper'
const textDecoder = new TextDecoder()
const textEncoder = new TextEncoder()

// TODO: need function which accepts filepath and policy
// use a hardcoded policy for now
Expand Down Expand Up @@ -45,11 +46,22 @@ export const run = async (entrypointPath, policy) => {
policy: toEndoPolicy(policy),
globals: globalThis,
importHook,
modules: {
USE_ME_AS_DEFAULT_ATTENUATOR_NAME: {
attenuateGlobals: () => {
console.log('lol, this works')
},
moduleTransforms: {
async mjs(
sourceBytes,
specifier,
location,
_packageLocation,
{ sourceMap }
) {
const source = textDecoder.decode(sourceBytes)
const { code, map } = await evadeCensor(source, {
sourceMap,
sourceUrl: new URL(specifier, location).href,
sourceType: 'module',
})
const objectBytes = textEncoder.encode(code)
return { bytes: objectBytes, parser: 'mjs', map }
},
},
})
Expand Down
10 changes: 7 additions & 3 deletions packages/endomoat/src/policy-converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const { entries, fromEntries } = Object
* @typedef {import('@endo/compartment-mapper').PackagePolicy<LavaMoatPackagePolicyItem, LavaMoatGlobalPolicyItem>} LavaMoatPackagePolicy
*/

const DEFAULT_ATTENUATOR = '@lavamoat/endomoat/attenuator/default'
const DEFAULT_ATTENUATOR = '@lavamoat/endomoat/attenuator'

/**
* Converts LavaMoat `ResourcePolicy.builtins` to Endo's `PackagePolicy.builtins`
Expand Down Expand Up @@ -135,7 +135,7 @@ export function toEndoPolicy(lmPolicy) {
/** @type {LavaMoatEndoPolicy} */
const endoPolicy = {
//TODO: generate a policy resource for the default attenuator
defaultAttenuator: DEFAULT_ATTENUATOR,
defaultAttenuator: DEFAULT_ATTENUATOR,
entry: {
[RSRC_POLICY_GLOBALS]: [ENDO_ROOT_POLICY],
[RSRC_POLICY_PKGS]: ENDO_WILDCARD_POLICY,
Expand All @@ -150,7 +150,11 @@ export function toEndoPolicy(lmPolicy) {
),
}
// add this to make endo allow the attenuator at all, TODO: generate this from the policy or build into Endo
endoPolicy.resources['@lavamoat/endomoat'] = {}
endoPolicy.resources['@lavamoat/endomoat'] = {
[RSRC_POLICY_PKGS]: ENDO_WILDCARD_POLICY,
[RSRC_POLICY_GLOBALS]: ENDO_WILDCARD_POLICY,
[RSRC_POLICY_BUILTINS]: ENDO_WILDCARD_POLICY,
}

return endoPolicy
}
8 changes: 3 additions & 5 deletions packages/endomoat/test/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ import { run } from '../src/index.js'

import path from 'path'


test('run a file', async t => {
test('run a file', async (t) => {
const entryFile = new URL('./fixtures/main/app.js', import.meta.url).href
const policy = {
resources: {}
resources: {},
}
debugger;
const result = await run(entryFile, policy)
t.deepEqual(result, {
hello: 'world'
hello: 'world',
})
})
10 changes: 4 additions & 6 deletions packages/endomoat/test/policy-converter.spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import test from 'ava'
import {
ENDO_ROOT_POLICY,
ENDO_WILDCARD_POLICY,
} from '../src/index.js'
import { ENDO_ROOT_POLICY, ENDO_WILDCARD_POLICY } from '../src/index.js'

import { toEndoPolicy } from '../src/policy-converter.js'

Expand Down Expand Up @@ -31,20 +28,21 @@ test('toEndoPolicy - basic', (t) => {
* @type {import('@endo/compartment-mapper').Policy<LavaMoatPackagePolicyItem>}
*/
const expected = {
defaultAttenuator: '@lavamoat/endomoat/attenuator/default',
defaultAttenuator: '@lavamoat/endomoat/attenuator',
entry: {
globals: [ENDO_ROOT_POLICY],
noGlobalFreeze: true,
packages: ENDO_WILDCARD_POLICY,
builtins: ENDO_WILDCARD_POLICY,
},
resources: {
'@lavamoat/endomoat': {},
a: {
packages: { b: true },
globals: { console: true },
builtins: {
fs: {
attenuate: '@lavamoat/endomoat/attenuator/property',
attenuate: '@lavamoat/endomoat/attenuator',
params: ['readFile'],
},
},
Expand Down

0 comments on commit fb7b0da

Please sign in to comment.