lavamoat-core
Advanced tools
Comparing version 14.4.1 to 15.0.0
# Changelog | ||
## [15.0.0](https://github.com/LavaMoat/LavaMoat/compare/lavamoat-core-v14.4.1...lavamoat-core-v15.0.0) (2023-10-18) | ||
### ⚠ BREAKING CHANGES | ||
* The minimum supported Node.js version is now v16.20.0. | ||
### Features | ||
* **core:** add overrideTaming: 'severe' for improved developer experience under lavamoat ([#730](https://github.com/LavaMoat/LavaMoat/issues/730)) ([20e4f76](https://github.com/LavaMoat/LavaMoat/commit/20e4f764dfdabcf21c7e72ad45fcfeaf45fd2b6c)) | ||
* node20 ([ef3a0da](https://github.com/LavaMoat/LavaMoat/commit/ef3a0da9960d7f5734e3d4180ebafdae2432a260)) | ||
### Bug Fixes | ||
* drop Node.js v14 ([#729](https://github.com/LavaMoat/LavaMoat/issues/729)) ([10c667b](https://github.com/LavaMoat/LavaMoat/commit/10c667bd88eaabf60a8fd8e4493cc7676848b201)) | ||
### Dependencies | ||
* The following workspace dependencies were updated | ||
* dependencies | ||
* lavamoat-tofu bumped from ^6.2.1 to ^7.0.0 | ||
## [14.4.1](https://github.com/LavaMoat/LavaMoat/compare/lavamoat-core-v14.4.0...lavamoat-core-v14.4.1) (2023-09-14) | ||
@@ -4,0 +28,0 @@ |
@@ -38,6 +38,6 @@ // import { | ||
assert.fail( | ||
d`Please report unexpected scope handler trap: ${q(String(prop))}`, | ||
d`Please report unexpected scope handler trap: ${q(String(prop))}` | ||
) | ||
}, | ||
}), | ||
}) | ||
) | ||
@@ -81,3 +81,3 @@ | ||
`getOwnPropertyDescriptor trap on scopeTerminatorHandler for ${quotedProp}`, | ||
new TypeError().stack, | ||
new TypeError().stack | ||
) | ||
@@ -94,4 +94,4 @@ return undefined | ||
alwaysThrowHandler, | ||
getOwnPropertyDescriptors(scopeProxyHandlerProperties), | ||
), | ||
getOwnPropertyDescriptors(scopeProxyHandlerProperties) | ||
) | ||
) | ||
@@ -101,3 +101,3 @@ | ||
immutableObject, | ||
strictScopeTerminatorHandler, | ||
strictScopeTerminatorHandler | ||
) | ||
@@ -104,0 +104,0 @@ |
{ | ||
"name": "lavamoat-core", | ||
"version": "14.4.1", | ||
"version": "15.0.0", | ||
"description": "LavaMoat kernel and utils", | ||
@@ -10,7 +10,7 @@ "main": "src/index.js", | ||
"engines": { | ||
"node": ">=14.0.0 <19.0.0" | ||
"node": "^16.20.0 || ^18.0.0 || ^20.0.0" | ||
}, | ||
"dependencies": { | ||
"json-stable-stringify": "^1.0.2", | ||
"lavamoat-tofu": "^6.2.1", | ||
"lavamoat-tofu": "^7.0.0", | ||
"merge-deep": "^3.0.3" | ||
@@ -39,4 +39,3 @@ }, | ||
"timeout": "30s" | ||
}, | ||
"gitHead": "5fb4a8824b4100150f891fabf17448a77de48498" | ||
} | ||
} |
# lavamoat-core | ||
LavaMoat kernel and utils. | ||
LavaMoat kernel and utils. |
@@ -10,3 +10,5 @@ // the contents of this file will be copied into the prelude template | ||
function endowmentsToolkit({ createFunctionWrapper = defaultCreateFunctionWrapper } = {}) { | ||
function endowmentsToolkit({ | ||
createFunctionWrapper = defaultCreateFunctionWrapper, | ||
} = {}) { | ||
return { | ||
@@ -31,3 +33,8 @@ getEndowmentsForConfig, | ||
*/ | ||
function getEndowmentsForConfig(sourceRef, packagePolicy, unwrapTo, unwrapFrom) { | ||
function getEndowmentsForConfig( | ||
sourceRef, | ||
packagePolicy, | ||
unwrapTo, | ||
unwrapFrom | ||
) { | ||
if (!packagePolicy.globals) { | ||
@@ -39,30 +46,58 @@ return {} | ||
const explicitlyBanned = [] | ||
Object.entries(packagePolicy.globals).forEach(([path, packagePolicyValue]) => { | ||
const pathParts = path.split('.') | ||
// disallow dunder proto in path | ||
const pathContainsDunderProto = pathParts.some(pathPart => pathPart === '__proto__') | ||
if (pathContainsDunderProto) { | ||
throw new Error(`Lavamoat - "__proto__" disallowed when creating minimal view. saw "${path}"`) | ||
Object.entries(packagePolicy.globals).forEach( | ||
([path, packagePolicyValue]) => { | ||
const pathParts = path.split('.') | ||
// disallow dunder proto in path | ||
const pathContainsDunderProto = pathParts.some( | ||
(pathPart) => pathPart === '__proto__' | ||
) | ||
if (pathContainsDunderProto) { | ||
throw new Error( | ||
`Lavamoat - "__proto__" disallowed when creating minimal view. saw "${path}"` | ||
) | ||
} | ||
// false means no access. It's necessary so that overrides can also be used to tighten the policy | ||
if (packagePolicyValue === false) { | ||
explicitlyBanned.push(path) | ||
return | ||
} | ||
// write access handled elsewhere | ||
if (packagePolicyValue === 'write') { | ||
return | ||
} | ||
if (packagePolicyValue !== true) { | ||
throw new Error( | ||
`LavaMoat - unrecognizable policy value (${typeof packagePolicyValue}) for path "${path}"` | ||
) | ||
} | ||
whitelistedReads.push(path) | ||
} | ||
// false means no access. It's necessary so that overrides can also be used to tighten the policy | ||
if (packagePolicyValue === false) { | ||
explicitlyBanned.push(path) | ||
return | ||
} | ||
// write access handled elsewhere | ||
if (packagePolicyValue === 'write') { | ||
return | ||
} | ||
if (packagePolicyValue !== true) { | ||
throw new Error(`LavaMoat - unrecognizable policy value (${typeof packagePolicyValue}) for path "${path}"`) | ||
} | ||
whitelistedReads.push(path) | ||
}) | ||
return makeMinimalViewOfRef(sourceRef, whitelistedReads, unwrapTo, unwrapFrom, explicitlyBanned) | ||
) | ||
return makeMinimalViewOfRef( | ||
sourceRef, | ||
whitelistedReads, | ||
unwrapTo, | ||
unwrapFrom, | ||
explicitlyBanned | ||
) | ||
} | ||
function makeMinimalViewOfRef(sourceRef, paths, unwrapTo, unwrapFrom, explicitlyBanned = []) { | ||
function makeMinimalViewOfRef( | ||
sourceRef, | ||
paths, | ||
unwrapTo, | ||
unwrapFrom, | ||
explicitlyBanned = [] | ||
) { | ||
const targetRef = {} | ||
paths.forEach(path => { | ||
copyValueAtPath('', path.split('.'), explicitlyBanned, sourceRef, targetRef, unwrapTo, unwrapFrom) | ||
paths.forEach((path) => { | ||
copyValueAtPath( | ||
'', | ||
path.split('.'), | ||
explicitlyBanned, | ||
sourceRef, | ||
targetRef, | ||
unwrapTo, | ||
unwrapFrom | ||
) | ||
}) | ||
@@ -79,3 +114,11 @@ return targetRef | ||
function copyValueAtPath(visitedPath, pathParts, explicitlyBanned, sourceRef, targetRef, unwrapTo = sourceRef, unwrapFrom = targetRef) { | ||
function copyValueAtPath( | ||
visitedPath, | ||
pathParts, | ||
explicitlyBanned, | ||
sourceRef, | ||
targetRef, | ||
unwrapTo = sourceRef, | ||
unwrapFrom = targetRef | ||
) { | ||
if (pathParts.length === 0) { | ||
@@ -87,3 +130,6 @@ throw new Error('unable to copy, must have pathParts, was empty') | ||
// get the property from any depth in the property chain | ||
const { prop: sourcePropDesc } = getPropertyDescriptorDeep(sourceRef, nextPart) | ||
const { prop: sourcePropDesc } = getPropertyDescriptorDeep( | ||
sourceRef, | ||
nextPart | ||
) | ||
@@ -100,3 +146,5 @@ // if source missing the value to copy, just skip it | ||
if (!('value' in targetPropDesc)) { | ||
throw new Error(`unable to copy on to targetRef, targetRef has a getter at "${nextPart}"`) | ||
throw new Error( | ||
`unable to copy on to targetRef, targetRef has a getter at "${nextPart}"` | ||
) | ||
} | ||
@@ -107,3 +155,5 @@ // value must be extensible (cant write properties onto it) | ||
if (valueType !== 'object' && valueType !== 'function') { | ||
throw new Error(`unable to copy on to targetRef, targetRef value is not an obj or func "${nextPart}"`) | ||
throw new Error( | ||
`unable to copy on to targetRef, targetRef value is not an obj or func "${nextPart}"` | ||
) | ||
} | ||
@@ -135,3 +185,9 @@ } | ||
} | ||
copyValueAtPath(currentPath, remainingParts, explicitlyBanned, nextSourceRef, nextTargetRef) | ||
copyValueAtPath( | ||
currentPath, | ||
remainingParts, | ||
explicitlyBanned, | ||
nextSourceRef, | ||
nextTargetRef | ||
) | ||
return | ||
@@ -150,3 +206,7 @@ } | ||
// wrapper setter/getter with correct receiver | ||
const wrapperPropDesc = applyGetSetPropDescTransforms(sourcePropDesc, unwrapFrom, unwrapTo) | ||
const wrapperPropDesc = applyGetSetPropDescTransforms( | ||
sourcePropDesc, | ||
unwrapFrom, | ||
unwrapTo | ||
) | ||
Reflect.defineProperty(targetRef, nextPart, wrapperPropDesc) | ||
@@ -166,3 +226,3 @@ return | ||
// otherwise add workaround for functions to swap back to the sourceal "this" reference | ||
const unwrapTest = thisValue => thisValue === unwrapFrom | ||
const unwrapTest = (thisValue) => thisValue === unwrapFrom | ||
const newValue = createFunctionWrapper(sourceValue, unwrapTest, unwrapTo) | ||
@@ -189,3 +249,5 @@ const newPropDesc = { | ||
} else { | ||
throw new Error('getEndowmentsForConfig - property descriptor missing a getter') | ||
throw new Error( | ||
'getEndowmentsForConfig - property descriptor missing a getter' | ||
) | ||
} | ||
@@ -196,10 +258,26 @@ return { sourceValue, sourceWritable } | ||
function applyEndowmentPropDescTransforms(propDesc, unwrapFromCompartmentGlobalThis, unwrapToGlobalThis) { | ||
function applyEndowmentPropDescTransforms( | ||
propDesc, | ||
unwrapFromCompartmentGlobalThis, | ||
unwrapToGlobalThis | ||
) { | ||
let newPropDesc = propDesc | ||
newPropDesc = applyFunctionPropDescTransform(newPropDesc, unwrapFromCompartmentGlobalThis, unwrapToGlobalThis) | ||
newPropDesc = applyGetSetPropDescTransforms(newPropDesc, unwrapFromCompartmentGlobalThis, unwrapToGlobalThis) | ||
newPropDesc = applyFunctionPropDescTransform( | ||
newPropDesc, | ||
unwrapFromCompartmentGlobalThis, | ||
unwrapToGlobalThis | ||
) | ||
newPropDesc = applyGetSetPropDescTransforms( | ||
newPropDesc, | ||
unwrapFromCompartmentGlobalThis, | ||
unwrapToGlobalThis | ||
) | ||
return newPropDesc | ||
} | ||
function applyGetSetPropDescTransforms(sourcePropDesc, unwrapFromGlobalThis, unwrapToGlobalThis) { | ||
function applyGetSetPropDescTransforms( | ||
sourcePropDesc, | ||
unwrapFromGlobalThis, | ||
unwrapToGlobalThis | ||
) { | ||
const wrappedPropDesc = { ...sourcePropDesc } | ||
@@ -210,3 +288,4 @@ if (sourcePropDesc.get) { | ||
// replace the "receiver" value if it points to fake parent | ||
const receiverRef = receiver === unwrapFromGlobalThis ? unwrapToGlobalThis : receiver | ||
const receiverRef = | ||
receiver === unwrapFromGlobalThis ? unwrapToGlobalThis : receiver | ||
// sometimes getters replace themselves with static properties, as seen wih the FireFox runtime | ||
@@ -221,3 +300,7 @@ const result = Reflect.apply(sourcePropDesc.get, receiverRef, []) | ||
// "getter.originalValue" property being available | ||
return createFunctionWrapper(result, (thisValue) => thisValue === unwrapFromGlobalThis, unwrapToGlobalThis) | ||
return createFunctionWrapper( | ||
result, | ||
(thisValue) => thisValue === unwrapFromGlobalThis, | ||
unwrapToGlobalThis | ||
) | ||
} else { | ||
@@ -232,3 +315,4 @@ return result | ||
const receiver = this | ||
const receiverRef = receiver === unwrapFromGlobalThis ? unwrapToGlobalThis : receiver | ||
const receiverRef = | ||
receiver === unwrapFromGlobalThis ? unwrapToGlobalThis : receiver | ||
return Reflect.apply(sourcePropDesc.set, receiverRef, [value]) | ||
@@ -240,3 +324,7 @@ } | ||
function applyFunctionPropDescTransform(propDesc, unwrapFromCompartmentGlobalThis, unwrapToGlobalThis) { | ||
function applyFunctionPropDescTransform( | ||
propDesc, | ||
unwrapFromCompartmentGlobalThis, | ||
unwrapToGlobalThis | ||
) { | ||
if (!('value' in propDesc && typeof propDesc.value === 'function')) { | ||
@@ -251,7 +339,10 @@ return propDesc | ||
} | ||
const newFn = createFunctionWrapper(propDesc.value, unwrapTest, unwrapToGlobalThis) | ||
const newFn = createFunctionWrapper( | ||
propDesc.value, | ||
unwrapTest, | ||
unwrapToGlobalThis | ||
) | ||
return { ...propDesc, value: newFn } | ||
} | ||
function getPropertyDescriptorDeep(target, key) { | ||
@@ -282,3 +373,7 @@ let receiver = target | ||
function copyWrappedGlobals(globalRef, target, globalThisRefs = ['globalThis']) { | ||
function copyWrappedGlobals( | ||
globalRef, | ||
target, | ||
globalThisRefs = ['globalThis'] | ||
) { | ||
// find the relevant endowment sources | ||
@@ -288,6 +383,10 @@ const globalProtoChain = getPrototypeChain(globalRef) | ||
// this should always be the last index, but we check just in case | ||
const commonPrototypeIndex = globalProtoChain.findIndex(globalProtoChainEntry => globalProtoChainEntry === Object.prototype) | ||
const commonPrototypeIndex = globalProtoChain.findIndex( | ||
(globalProtoChainEntry) => globalProtoChainEntry === Object.prototype | ||
) | ||
if (commonPrototypeIndex === -1) { | ||
// TODO: fix this error message | ||
throw new Error('Lavamoat - unable to find common prototype between Compartment and globalRef') | ||
throw new Error( | ||
'Lavamoat - unable to find common prototype between Compartment and globalRef' | ||
) | ||
} | ||
@@ -299,5 +398,5 @@ // we will copy endowments from all entries in the prototype chain, excluding Object.prototype | ||
// call on contents of endowmentsSources directly instead of in new array instances. If there is a lazy getter it only changes the original prop desc. | ||
endowmentSources.forEach(source => { | ||
endowmentSources.forEach((source) => { | ||
const descriptors = Object.getOwnPropertyDescriptors(source) | ||
Object.values(descriptors).forEach(desc => { | ||
Object.values(descriptors).forEach((desc) => { | ||
if ('get' in desc) { | ||
@@ -307,3 +406,3 @@ try { | ||
Reflect.apply(desc.get, globalRef, []) | ||
} catch { } | ||
} catch {} | ||
} | ||
@@ -313,5 +412,11 @@ }) | ||
const endowmentSourceDescriptors = endowmentSources.map(globalProtoChainEntry => Object.getOwnPropertyDescriptors(globalProtoChainEntry)) | ||
const endowmentSourceDescriptors = endowmentSources.map( | ||
(globalProtoChainEntry) => | ||
Object.getOwnPropertyDescriptors(globalProtoChainEntry) | ||
) | ||
// flatten propDesc collections with precedence for globalThis-end of the prototype chain | ||
const endowmentDescriptorsFlat = Object.assign(Object.create(null), ...endowmentSourceDescriptors.reverse()) | ||
const endowmentDescriptorsFlat = Object.assign( | ||
Object.create(null), | ||
...endowmentSourceDescriptors.reverse() | ||
) | ||
// expose all own properties of globalRef, including non-enumerable | ||
@@ -322,7 +427,11 @@ Object.entries(endowmentDescriptorsFlat) | ||
// ignore circular globalThis refs | ||
.filter(([key]) => !(globalThisRefs.includes(key))) | ||
.filter(([key]) => !globalThisRefs.includes(key)) | ||
// define property on compartment global | ||
.forEach(([key, desc]) => { | ||
// unwrap functions, setters/getters & apply scope proxy workaround | ||
const wrappedPropDesc = applyEndowmentPropDescTransforms(desc, target, globalRef) | ||
const wrappedPropDesc = applyEndowmentPropDescTransforms( | ||
desc, | ||
target, | ||
globalRef | ||
) | ||
Reflect.defineProperty(target, key, wrappedPropDesc) | ||
@@ -346,3 +455,6 @@ }) | ||
let current = value | ||
while (current && (typeof current === 'object' || typeof current === 'function')) { | ||
while ( | ||
current && | ||
(typeof current === 'object' || typeof current === 'function') | ||
) { | ||
protoChain.push(current) | ||
@@ -367,4 +479,7 @@ current = Reflect.getPrototypeOf(current) | ||
} | ||
Object.defineProperties(newValue, Object.getOwnPropertyDescriptors(sourceValue)) | ||
Object.defineProperties( | ||
newValue, | ||
Object.getOwnPropertyDescriptors(sourceValue) | ||
) | ||
return newValue | ||
} |
@@ -9,8 +9,26 @@ // The "prelude" is the kernel of a browserify bundle. It initializes the modules and | ||
const path = require('path') | ||
const kernelTemplate = fs.readFileSync(path.join(__dirname, '/kernelTemplate.js'), 'utf-8') | ||
const kernelCoreTemplate = fs.readFileSync(path.join(__dirname, '/kernelCoreTemplate.js'), 'utf-8') | ||
const sesSrc = fs.readFileSync(path.join(__dirname, '/../lib/lockdown.umd.js'), 'utf-8') | ||
const endowmentsToolkitSrc = fs.readFileSync(path.join(__dirname, '/endowmentsToolkit.js'), 'utf-8') | ||
const makePrepareRealmGlobalFromConfigSrc = fs.readFileSync(path.join(__dirname, '/makePrepareRealmGlobalFromConfig.js'), 'utf-8') | ||
const strictScopeTerminatorSrc = fs.readFileSync(path.join(__dirname, '/../lib/strict-scope-terminator.js'), 'utf-8') | ||
const kernelTemplate = fs.readFileSync( | ||
path.join(__dirname, '/kernelTemplate.js'), | ||
'utf-8' | ||
) | ||
const kernelCoreTemplate = fs.readFileSync( | ||
path.join(__dirname, '/kernelCoreTemplate.js'), | ||
'utf-8' | ||
) | ||
const sesSrc = fs.readFileSync( | ||
path.join(__dirname, '/../lib/lockdown.umd.js'), | ||
'utf-8' | ||
) | ||
const endowmentsToolkitSrc = fs.readFileSync( | ||
path.join(__dirname, '/endowmentsToolkit.js'), | ||
'utf-8' | ||
) | ||
const makePrepareRealmGlobalFromConfigSrc = fs.readFileSync( | ||
path.join(__dirname, '/makePrepareRealmGlobalFromConfig.js'), | ||
'utf-8' | ||
) | ||
const strictScopeTerminatorSrc = fs.readFileSync( | ||
path.join(__dirname, '/../lib/strict-scope-terminator.js'), | ||
'utf-8' | ||
) | ||
@@ -25,7 +43,7 @@ module.exports = { | ||
function getSesShimSrc () { | ||
function getSesShimSrc() { | ||
return sesSrc | ||
} | ||
function getStrictScopeTerminatorShimSrc () { | ||
function getStrictScopeTerminatorShimSrc() { | ||
return strictScopeTerminatorSrc | ||
@@ -35,3 +53,3 @@ } | ||
// takes the kernelTemplate and populates it with the libraries | ||
function generateKernel (_opts = {}) { | ||
function generateKernel(_opts = {}) { | ||
const opts = Object.assign({}, _opts) | ||
@@ -43,3 +61,7 @@ const kernelCode = generateKernelCore() | ||
output = stringReplace(output, '__createKernelCore__', kernelCode) | ||
output = stringReplace(output, '__lavamoatDebugOptions__', JSON.stringify({debugMode: !!opts.debugMode})) | ||
output = stringReplace( | ||
output, | ||
'__lavamoatDebugOptions__', | ||
JSON.stringify({ debugMode: !!opts.debugMode }) | ||
) | ||
// eslint-disable-next-line no-prototype-builtins | ||
@@ -51,8 +73,11 @@ if (opts?.hasOwnProperty('scuttleGlobalThis')) { | ||
if (opts.scuttleGlobalThisExceptions) { | ||
console.warn('Lavamoat - "scuttleGlobalThisExceptions" is deprecated. Use "scuttleGlobalThis.exceptions" instead.') | ||
console.warn( | ||
'Lavamoat - "scuttleGlobalThisExceptions" is deprecated. Use "scuttleGlobalThis.exceptions" instead.' | ||
) | ||
if (scuttleGlobalThis === true) { | ||
scuttleGlobalThis = {enabled: true} | ||
scuttleGlobalThis = { enabled: true } | ||
} | ||
} | ||
const exceptions = scuttleGlobalThis?.exceptions || opts.scuttleGlobalThisExceptions | ||
const exceptions = | ||
scuttleGlobalThis?.exceptions || opts.scuttleGlobalThisExceptions | ||
scuttleGlobalThis.exceptions = exceptions | ||
@@ -65,5 +90,9 @@ if (exceptions) { | ||
} | ||
output = stringReplace(output, '__lavamoatSecurityOptions__', JSON.stringify({ | ||
scuttleGlobalThis, | ||
})) | ||
output = stringReplace( | ||
output, | ||
'__lavamoatSecurityOptions__', | ||
JSON.stringify({ | ||
scuttleGlobalThis, | ||
}) | ||
) | ||
} | ||
@@ -75,11 +104,23 @@ | ||
// takes the kernelCoreTemplate and populates it with the libraries | ||
function generateKernelCore () { | ||
function generateKernelCore() { | ||
let output = kernelCoreTemplate | ||
output = replaceTemplateRequire(output, 'endowmentsToolkit', endowmentsToolkitSrc) | ||
output = replaceTemplateRequire(output, 'makePrepareRealmGlobalFromConfig', makePrepareRealmGlobalFromConfigSrc) | ||
output = replaceTemplateRequire(output, 'strict-scope-terminator', strictScopeTerminatorSrc) | ||
output = replaceTemplateRequire( | ||
output, | ||
'endowmentsToolkit', | ||
endowmentsToolkitSrc | ||
) | ||
output = replaceTemplateRequire( | ||
output, | ||
'makePrepareRealmGlobalFromConfig', | ||
makePrepareRealmGlobalFromConfigSrc | ||
) | ||
output = replaceTemplateRequire( | ||
output, | ||
'strict-scope-terminator', | ||
strictScopeTerminatorSrc | ||
) | ||
return output | ||
} | ||
function replaceTemplateRequire (code, moduleName, src) { | ||
function replaceTemplateRequire(code, moduleName, src) { | ||
const wrappedSrc = wrapWithReturnCjsExports(moduleName, src) | ||
@@ -91,8 +132,9 @@ code = stringReplace(code, `templateRequire('${moduleName}')`, wrappedSrc) | ||
// this wraps the content of a commonjs module with an IIFE that returns the module.exports | ||
function wrapWithReturnCjsExports (label, src) { | ||
function wrapWithReturnCjsExports(label, src) { | ||
if (String(label).includes('\n')) { | ||
throw new Error('Lavamoat - "wrapWithReturnCjsExports" does not allow labels with newlines') | ||
throw new Error( | ||
'Lavamoat - "wrapWithReturnCjsExports" does not allow labels with newlines' | ||
) | ||
} | ||
return ( | ||
`// define ${label} | ||
return `// define ${label} | ||
(function(){ | ||
@@ -109,3 +151,2 @@ const global = globalRef | ||
})()` | ||
) | ||
} | ||
@@ -115,4 +156,4 @@ | ||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter | ||
function stringReplace (src, target, replacement) { | ||
function stringReplace(src, target, replacement) { | ||
return src.split(target).join(replacement) | ||
} |
@@ -10,3 +10,7 @@ const EventEmitter = require('events') | ||
codeSampleFromAstNode, | ||
utils: { mergePolicy: mergeGlobalsPolicy, mapToObj, reduceToTopmostApiCallsFromStrings }, | ||
utils: { | ||
mergePolicy: mergeGlobalsPolicy, | ||
mapToObj, | ||
reduceToTopmostApiCallsFromStrings, | ||
}, | ||
} = require('lavamoat-tofu') | ||
@@ -19,3 +23,3 @@ const { mergePolicy } = require('./mergePolicy') | ||
function createModuleInspector (opts = {}) { | ||
function createModuleInspector(opts = {}) { | ||
const moduleIdToModuleRecord = new Map() | ||
@@ -39,3 +43,6 @@ // "packageToModules" does not include builtin modules | ||
function inspectModule (moduleRecord, { isBuiltin, includeDebugInfo = false } = {}) { | ||
function inspectModule( | ||
moduleRecord, | ||
{ isBuiltin, includeDebugInfo = false } = {} | ||
) { | ||
const { packageName, specifier, type } = moduleRecord | ||
@@ -66,3 +73,3 @@ // record the module | ||
// eslint-disable-next-line no-unused-vars | ||
function inspectBuiltinModule (moduleRecord) { | ||
function inspectBuiltinModule(moduleRecord) { | ||
// builtins themselves do not require any configuration | ||
@@ -72,3 +79,3 @@ // packages that import builtins need to add that to their configuration | ||
function inspectNativeModule (moduleRecord) { | ||
function inspectNativeModule(moduleRecord) { | ||
// LavaMoat does attempt to sandbox native modules | ||
@@ -84,3 +91,6 @@ // packages with native modules need to specify that in the policy file | ||
function inspectJsModule (moduleRecord, { isBuiltin, includeDebugInfo = false }) { | ||
function inspectJsModule( | ||
moduleRecord, | ||
{ isBuiltin, includeDebugInfo = false } | ||
) { | ||
const { packageName, specifier } = moduleRecord | ||
@@ -116,9 +126,11 @@ let moduleDebug | ||
// get ast (parse or use cached) | ||
const ast = moduleRecord.ast || parse(moduleRecord.content, { | ||
// esm support | ||
sourceType: 'module', | ||
// someone must have been doing this | ||
allowReturnOutsideFunction: true, | ||
errorRecovery: true, | ||
}) | ||
const ast = | ||
moduleRecord.ast || | ||
parse(moduleRecord.content, { | ||
// esm support | ||
sourceType: 'module', | ||
// someone must have been doing this | ||
allowReturnOutsideFunction: true, | ||
errorRecovery: true, | ||
}) | ||
if (includeDebugInfo && ast.errors && ast.errors.length) { | ||
@@ -132,3 +144,9 @@ moduleDebug.parseErrors = ast.errors | ||
// get builtin package usage | ||
inspectForImports(ast, moduleRecord, packageName, isBuiltin, includeDebugInfo) | ||
inspectForImports( | ||
ast, | ||
moduleRecord, | ||
packageName, | ||
isBuiltin, | ||
includeDebugInfo | ||
) | ||
// ensure module ast is cleaned up | ||
@@ -138,7 +156,11 @@ delete moduleRecord.ast | ||
function inspectForEnvironment (ast, moduleRecord, includeDebugInfo) { | ||
function inspectForEnvironment(ast, moduleRecord, includeDebugInfo) { | ||
const { packageName } = moduleRecord | ||
const compatWarnings = inspectSesCompat(ast, packageName) | ||
const { primordialMutations, strictModeViolations, dynamicRequires } = compatWarnings | ||
const hasResults = primordialMutations.length > 0 || strictModeViolations.length > 0 || dynamicRequires.length > 0 | ||
const { primordialMutations, strictModeViolations, dynamicRequires } = | ||
compatWarnings | ||
const hasResults = | ||
primordialMutations.length > 0 || | ||
strictModeViolations.length > 0 || | ||
dynamicRequires.length > 0 | ||
if (!hasResults) { | ||
@@ -152,5 +174,11 @@ return | ||
// fix serialization | ||
primordialMutations: primordialMutations.map(({ node: { loc } }) => ({ node: { loc } })), | ||
strictModeViolations: strictModeViolations.map(({ node: { loc } }) => ({ node: { loc } })), | ||
dynamicRequires: dynamicRequires.map(({ node: { loc } }) => ({ node: { loc } })), | ||
primordialMutations: primordialMutations.map(({ node: { loc } }) => ({ | ||
node: { loc }, | ||
})), | ||
strictModeViolations: strictModeViolations.map(({ node: { loc } }) => ({ | ||
node: { loc }, | ||
})), | ||
dynamicRequires: dynamicRequires.map(({ node: { loc } }) => ({ | ||
node: { loc }, | ||
})), | ||
} | ||
@@ -163,5 +191,11 @@ } else { | ||
const samples = jsonStringify({ | ||
primordialMutations: primordialMutations.map(({ node }) => codeSampleFromAstNode(node, moduleRecord)), | ||
strictModeViolations: strictModeViolations.map(({ node }) => codeSampleFromAstNode(node, moduleRecord)), | ||
dynamicRequires: dynamicRequires.map(({ node }) => codeSampleFromAstNode(node, moduleRecord)), | ||
primordialMutations: primordialMutations.map(({ node }) => | ||
codeSampleFromAstNode(node, moduleRecord) | ||
), | ||
strictModeViolations: strictModeViolations.map(({ node }) => | ||
codeSampleFromAstNode(node, moduleRecord) | ||
), | ||
dynamicRequires: dynamicRequires.map(({ node }) => | ||
codeSampleFromAstNode(node, moduleRecord) | ||
), | ||
}) | ||
@@ -174,3 +208,3 @@ const errMsg = `Incompatible code detected in package "${packageName}" file "${moduleRecord.file}". Violations:\n${samples}` | ||
function inspectForGlobals (ast, moduleRecord, packageName, includeDebugInfo) { | ||
function inspectForGlobals(ast, moduleRecord, packageName, includeDebugInfo) { | ||
const commonJsRefs = ['require', 'module', 'exports', 'arguments'] | ||
@@ -202,3 +236,9 @@ const globalObjPrototypeRefs = Object.getOwnPropertyNames(Object.prototype) | ||
function inspectForImports (ast, moduleRecord, packageName, isBuiltin, includeDebugInfo) { | ||
function inspectForImports( | ||
ast, | ||
moduleRecord, | ||
packageName, | ||
isBuiltin, | ||
includeDebugInfo | ||
) { | ||
// get all requested names that resolve to isBuiltin | ||
@@ -226,3 +266,3 @@ const namesForBuiltins = Object.entries(moduleRecord.importMap) | ||
function generatePolicy ({ policyOverride, includeDebugInfo } = {}) { | ||
function generatePolicy({ policyOverride, includeDebugInfo } = {}) { | ||
const resources = {} | ||
@@ -239,5 +279,10 @@ const policy = { resources } | ||
// get dependencies, ignoring builtins | ||
const packageDeps = aggregateDeps({ packageModules, moduleIdToModuleRecord }) | ||
const packageDeps = aggregateDeps({ | ||
packageModules, | ||
moduleIdToModuleRecord, | ||
}) | ||
if (packageDeps.length) { | ||
packages = Object.fromEntries(packageDeps.map(depPackageName => [depPackageName, true])) | ||
packages = Object.fromEntries( | ||
packageDeps.map((depPackageName) => [depPackageName, true]) | ||
) | ||
} | ||
@@ -249,3 +294,3 @@ // get globals | ||
// read/write syntax highlighting | ||
Object.keys(globals).forEach(key => { | ||
Object.keys(globals).forEach((key) => { | ||
if (globals[key] === 'read') { | ||
@@ -260,3 +305,3 @@ globals[key] = true | ||
builtin = {} | ||
reduceToTopmostApiCallsFromStrings(builtinImports).forEach(path => { | ||
reduceToTopmostApiCallsFromStrings(builtinImports).forEach((path) => { | ||
builtin[path] = true | ||
@@ -300,25 +345,27 @@ }) | ||
function aggregateDeps ({ packageModules, moduleIdToModuleRecord }) { | ||
function aggregateDeps({ packageModules, moduleIdToModuleRecord }) { | ||
const deps = new Set() | ||
// get all dep package from the "packageModules" collection of modules | ||
Object.values(packageModules).forEach((moduleRecord) => { | ||
Object.entries(moduleRecord.importMap).forEach(([requestedName, specifier]) => { | ||
// skip entries where resolution was skipped | ||
if (!specifier) { | ||
return | ||
} | ||
// get packageName from module record, or guess | ||
const moduleRecord = moduleIdToModuleRecord.get(specifier) | ||
if (moduleRecord) { | ||
// builtin modules are ignored here, handled elsewhere | ||
if (moduleRecord.type === 'builtin') { | ||
Object.entries(moduleRecord.importMap).forEach( | ||
([requestedName, specifier]) => { | ||
// skip entries where resolution was skipped | ||
if (!specifier) { | ||
return | ||
} | ||
deps.add(moduleRecord.packageName) | ||
return | ||
// get packageName from module record, or guess | ||
const moduleRecord = moduleIdToModuleRecord.get(specifier) | ||
if (moduleRecord) { | ||
// builtin modules are ignored here, handled elsewhere | ||
if (moduleRecord.type === 'builtin') { | ||
return | ||
} | ||
deps.add(moduleRecord.packageName) | ||
return | ||
} | ||
// moduleRecord missing, guess package name | ||
const packageName = guessPackageName(requestedName) | ||
deps.add(packageName) | ||
} | ||
// moduleRecord missing, guess package name | ||
const packageName = guessPackageName(requestedName) | ||
deps.add(packageName) | ||
}) | ||
) | ||
// ensure the package is not listed as its own dependency | ||
@@ -333,4 +380,5 @@ deps.delete(moduleRecord.packageName) | ||
// for when you encounter a requestedName that was not inspected, likely because resolution was skipped for that module | ||
function guessPackageName (requestedName) { | ||
const isNotPackageName = requestedName.startsWith('/') || requestedName.startsWith('.') | ||
function guessPackageName(requestedName) { | ||
const isNotPackageName = | ||
requestedName.startsWith('/') || requestedName.startsWith('.') | ||
if (isNotPackageName) { | ||
@@ -347,3 +395,3 @@ return `<unknown:${requestedName}>` | ||
function getDefaultPaths (policyName) { | ||
function getDefaultPaths(policyName) { | ||
const policiesDir = 'lavamoat' | ||
@@ -350,0 +398,0 @@ const policyDir = path.join(policiesDir, policyName) |
@@ -1,4 +0,2 @@ | ||
const { | ||
generateKernel, | ||
} = require('./generateKernel') | ||
const { generateKernel } = require('./generateKernel') | ||
const { createModuleInspector, getDefaultPaths } = require('./generatePolicy') | ||
@@ -5,0 +3,0 @@ const { parseForPolicy } = require('./parseForPolicy') |
@@ -63,2 +63,4 @@ // LavaMoat Prelude | ||
stackFiltering: 'verbose', | ||
// prevents most common override mistake cases from tripping up users | ||
overrideTaming: 'severe', | ||
} | ||
@@ -65,0 +67,0 @@ |
@@ -7,3 +7,3 @@ const fs = require('fs') | ||
async function readPolicyFile ({ debugMode, policyPath }) { | ||
async function readPolicyFile({ debugMode, policyPath }) { | ||
if (debugMode) { | ||
@@ -16,6 +16,6 @@ console.warn(`Lavamoat looking for policy at'${policyPath}'`) | ||
async function loadPolicy ({ debugMode, policyPath }) { | ||
async function loadPolicy({ debugMode, policyPath }) { | ||
let policy = { resources: {} } | ||
if (fs.existsSync(policyPath)) { | ||
policy = readPolicyFile ({ debugMode, policyPath }) | ||
policy = readPolicyFile({ debugMode, policyPath }) | ||
} else { | ||
@@ -29,3 +29,7 @@ if (debugMode) { | ||
async function loadPolicyAndApplyOverrides({ debugMode, policyPath, policyOverridePath }) { | ||
async function loadPolicyAndApplyOverrides({ | ||
debugMode, | ||
policyPath, | ||
policyOverridePath, | ||
}) { | ||
const policy = await loadPolicy({ debugMode, policyPath }) | ||
@@ -37,3 +41,6 @@ let lavamoatPolicy = policy | ||
} | ||
const policyOverride = await readPolicyFile({ debugMode, policyPath: policyOverridePath }) | ||
const policyOverride = await readPolicyFile({ | ||
debugMode, | ||
policyPath: policyOverridePath, | ||
}) | ||
lavamoatPolicy = mergePolicy(policy, policyOverride) | ||
@@ -40,0 +47,0 @@ // TODO: Only write if merge results in changes. |
@@ -6,3 +6,3 @@ module.exports = makeGeneralUtils | ||
*/ | ||
function makeGeneralUtils () { | ||
function makeGeneralUtils() { | ||
return { | ||
@@ -12,3 +12,3 @@ createFunctionWrapper, | ||
function createFunctionWrapper (sourceValue, unwrapTest, unwrapTo) { | ||
function createFunctionWrapper(sourceValue, unwrapTest, unwrapTo) { | ||
const newValue = function (...args) { | ||
@@ -25,5 +25,8 @@ if (new.target) { | ||
} | ||
Object.defineProperties(newValue, Object.getOwnPropertyDescriptors(sourceValue)) | ||
Object.defineProperties( | ||
newValue, | ||
Object.getOwnPropertyDescriptors(sourceValue) | ||
) | ||
return newValue | ||
} | ||
} |
module.exports = { makeInitStatsHook } | ||
function makeInitStatsHook ({ onStatsReady }) { | ||
function makeInitStatsHook({ onStatsReady }) { | ||
let statModuleStack = [] | ||
return reportStatsHook | ||
function reportStatsHook (event, moduleId) { | ||
function reportStatsHook(event, moduleId) { | ||
if (event === 'start') { | ||
@@ -13,7 +13,7 @@ // record start | ||
const statRecord = { | ||
'name': moduleId, | ||
'value': null, | ||
'children': [], | ||
'startTime': startTime, | ||
'endTime': null, | ||
name: moduleId, | ||
value: null, | ||
children: [], | ||
startTime: startTime, | ||
endTime: null, | ||
} | ||
@@ -32,3 +32,7 @@ // add as child to current | ||
if (currentStat.name !== moduleId) { | ||
console.error(`stats hook misaligned "${currentStat.name}", "${moduleId}" ${statModuleStack.map(e => e.name).join()}`) | ||
console.error( | ||
`stats hook misaligned "${ | ||
currentStat.name | ||
}", "${moduleId}" ${statModuleStack.map((e) => e.name).join()}` | ||
) | ||
} | ||
@@ -48,3 +52,2 @@ currentStat.endTime = endTime | ||
} | ||
} |
@@ -10,3 +10,3 @@ // the contents of this file will be copied into the prelude template | ||
function makePrepareRealmGlobalFromConfig ({ createFunctionWrapper }) { | ||
function makePrepareRealmGlobalFromConfig({ createFunctionWrapper }) { | ||
return { | ||
@@ -18,5 +18,10 @@ prepareCompartmentGlobalFromConfig, | ||
function getTopLevelReadAccessFromPackageConfig (globalsConfig) { | ||
function getTopLevelReadAccessFromPackageConfig(globalsConfig) { | ||
const result = Object.entries(globalsConfig) | ||
.filter(([key, value]) => value === 'read' || value === true || (value === 'write' && key.split('.').length > 1)) | ||
.filter( | ||
([key, value]) => | ||
value === 'read' || | ||
value === true || | ||
(value === 'write' && key.split('.').length > 1) | ||
) | ||
.map(([key]) => key.split('.')[0]) | ||
@@ -27,5 +32,7 @@ // return unique array | ||
function getTopLevelWriteAccessFromPackageConfig (globalsConfig) { | ||
function getTopLevelWriteAccessFromPackageConfig(globalsConfig) { | ||
const result = Object.entries(globalsConfig) | ||
.filter(([key, value]) => value === 'write' && key.split('.').length === 1) | ||
.filter( | ||
([key, value]) => value === 'write' && key.split('.').length === 1 | ||
) | ||
.map(([key]) => key) | ||
@@ -35,7 +42,15 @@ return result | ||
function prepareCompartmentGlobalFromConfig (packageCompartment, globalsConfig, endowments, globalStore, globalThisRefs) { | ||
function prepareCompartmentGlobalFromConfig( | ||
packageCompartment, | ||
globalsConfig, | ||
endowments, | ||
globalStore, | ||
globalThisRefs | ||
) { | ||
const packageCompartmentGlobal = packageCompartment.globalThis | ||
// lookup top level read + write access keys | ||
const topLevelWriteAccessKeys = getTopLevelWriteAccessFromPackageConfig(globalsConfig) | ||
const topLevelReadAccessKeys = getTopLevelReadAccessFromPackageConfig(globalsConfig) | ||
const topLevelWriteAccessKeys = | ||
getTopLevelWriteAccessFromPackageConfig(globalsConfig) | ||
const topLevelReadAccessKeys = | ||
getTopLevelReadAccessFromPackageConfig(globalsConfig) | ||
@@ -50,5 +65,5 @@ // NOTE: getters for read should only ever be needed on props marked for 'write' (unless we want to allow sloppy behavior from the root compartment modifying everything...) | ||
// allow read access via globalStore or packageCompartmentGlobal | ||
topLevelReadAccessKeys.forEach(key => { | ||
topLevelReadAccessKeys.forEach((key) => { | ||
Object.defineProperty(packageCompartmentGlobal, key, { | ||
get () { | ||
get() { | ||
if (globalStore.has(key)) { | ||
@@ -60,5 +75,7 @@ return globalStore.get(key) | ||
}, | ||
set () { | ||
set() { | ||
// TODO: there should be a config to throw vs silently ignore | ||
console.warn(`LavaMoat: ignoring write attempt to read-access global "${key}"`) | ||
console.warn( | ||
`LavaMoat: ignoring write attempt to read-access global "${key}"` | ||
) | ||
}, | ||
@@ -70,5 +87,5 @@ }) | ||
// read access via globalStore or packageCompartmentGlobal | ||
topLevelWriteAccessKeys.forEach(key => { | ||
topLevelWriteAccessKeys.forEach((key) => { | ||
Object.defineProperty(packageCompartmentGlobal, key, { | ||
get () { | ||
get() { | ||
if (globalStore.has(key)) { | ||
@@ -80,3 +97,3 @@ return globalStore.get(key) | ||
}, | ||
set (value) { | ||
set(value) { | ||
globalStore.set(key, value) | ||
@@ -90,3 +107,3 @@ }, | ||
// set circular globalRefs | ||
globalThisRefs.forEach(key => { | ||
globalThisRefs.forEach((key) => { | ||
// if globalRef is actually an endowment, ignore | ||
@@ -108,8 +125,11 @@ if (topLevelReadAccessKeys.includes(key)) { | ||
const fn = origFunction(...args) | ||
const unwrapTest = thisValue => thisValue === undefined | ||
const unwrapTest = (thisValue) => thisValue === undefined | ||
return createFunctionWrapper(fn, unwrapTest, packageCompartmentGlobal) | ||
} | ||
Object.defineProperties(newFunction, Object.getOwnPropertyDescriptors(origFunction)) | ||
Object.defineProperties( | ||
newFunction, | ||
Object.getOwnPropertyDescriptors(origFunction) | ||
) | ||
packageCompartmentGlobal.Function = newFunction | ||
} | ||
} |
@@ -1,2 +0,6 @@ | ||
const { reduceToTopmostApiCalls, objToMap, mapToObj } = require('lavamoat-tofu/src/util') | ||
const { | ||
reduceToTopmostApiCalls, | ||
objToMap, | ||
mapToObj, | ||
} = require('lavamoat-tofu/src/util') | ||
const mergeDeep = require('merge-deep') | ||
@@ -6,3 +10,3 @@ | ||
function mergePolicy (policyA, policyB) { | ||
function mergePolicy(policyA, policyB) { | ||
const mergedPolicy = mergeDeep(policyA, policyB) | ||
@@ -20,3 +24,3 @@ Object.values(mergedPolicy.resources).forEach((packagePolicy) => { | ||
function dedupePolicyPaths (packagePolicy) { | ||
function dedupePolicyPaths(packagePolicy) { | ||
const itemMap = objToMap(packagePolicy) | ||
@@ -23,0 +27,0 @@ reduceToTopmostApiCalls(itemMap) |
@@ -1,4 +0,3 @@ | ||
class LavamoatModuleRecord { | ||
constructor ({ | ||
constructor({ | ||
specifier, | ||
@@ -5,0 +4,0 @@ file, |
@@ -17,3 +17,3 @@ const { createModuleInspector } = require('./generatePolicy') | ||
*/ | ||
async function parseForPolicy ({ | ||
async function parseForPolicy({ | ||
moduleSpecifier, | ||
@@ -27,3 +27,7 @@ importHook, | ||
}) { | ||
for await (const moduleRecord of eachNodeInTree({ moduleSpecifier, importHook, shouldImport })) { | ||
for await (const moduleRecord of eachNodeInTree({ | ||
moduleSpecifier, | ||
importHook, | ||
shouldImport, | ||
})) { | ||
// inspect each module | ||
@@ -30,0 +34,0 @@ inspector.inspectModule(moduleRecord) |
@@ -1,4 +0,8 @@ | ||
const { applyTransforms, evadeHtmlCommentTest, evadeImportExpressionTest } = require('../lib/transforms.umd.js') | ||
const { | ||
applyTransforms, | ||
evadeHtmlCommentTest, | ||
evadeImportExpressionTest, | ||
} = require('../lib/transforms.umd.js') | ||
function applySourceTransforms (source) { | ||
function applySourceTransforms(source) { | ||
return applyTransforms(source, [ | ||
@@ -11,3 +15,3 @@ evadeHtmlCommentTest, | ||
function evadeDirectEvalExpressions (source) { | ||
function evadeDirectEvalExpressions(source) { | ||
/* eslint-disable-next-line prefer-regex-literals */ | ||
@@ -14,0 +18,0 @@ const someDirectEvalPattern = new RegExp('\\beval(\\s*\\()', 'g') |
@@ -15,3 +15,3 @@ // specifier = exact unique module name | ||
*/ | ||
async function walk ({ | ||
async function walk({ | ||
moduleSpecifier, | ||
@@ -44,3 +44,3 @@ importHook, | ||
// NOTE: i think this is depth first in a way that doesnt take advantage of concurrency | ||
async function * eachNodeInTree ({ | ||
async function* eachNodeInTree({ | ||
moduleSpecifier, | ||
@@ -47,0 +47,0 @@ importHook, |
@@ -12,3 +12,4 @@ /* eslint-disable n/prefer-global/buffer */ | ||
defineOne: () => { | ||
let abc = null; let xyz = null | ||
let abc = null | ||
let xyz = null | ||
try { | ||
@@ -85,3 +86,4 @@ abc = require('abc') | ||
// this test ensures "Buffer.prototype.slice" is copied in a way that allows "this" to be overridden | ||
module.exports.overrideCheck = (buf) => Buffer.prototype.slice.call(buf, 1, 2)[0] === buf[1] | ||
module.exports.overrideCheck = (buf) => | ||
Buffer.prototype.slice.call(buf, 1, 2)[0] === buf[1] | ||
// this test ensures "Buffer.prototype.slice" is copied in a way that allows "this" to be overridden | ||
@@ -125,5 +127,7 @@ module.exports.thisCheck = () => thisChecker.check() | ||
thisChecker: (() => { | ||
const parent = {}; parent.check = function () { | ||
const parent = {} | ||
parent.check = function () { | ||
return this === parent | ||
}; return parent | ||
} | ||
return parent | ||
})(), | ||
@@ -130,0 +134,0 @@ someClass: { SomeClass: class SomeClass {} }, |
const test = require('ava') | ||
const { | ||
createScenarioFromScaffold, | ||
runScenario, | ||
} = require('./util') | ||
const { createScenarioFromScaffold, runScenario } = require('./util') | ||
@@ -7,0 +4,0 @@ test('circularDeps - multi-module circular deps dont inf loop', async (t) => { |
@@ -37,18 +37,38 @@ const test = require('ava') | ||
{ | ||
const sourceProp = Object.getOwnPropertyDescriptor(sourceGlobal.Buffer, 'from') | ||
const resultProp = Object.getOwnPropertyDescriptor(resultGlobal.Buffer, 'from') | ||
const sourceProp = Object.getOwnPropertyDescriptor( | ||
sourceGlobal.Buffer, | ||
'from' | ||
) | ||
const resultProp = Object.getOwnPropertyDescriptor( | ||
resultGlobal.Buffer, | ||
'from' | ||
) | ||
t.is(typeof resultProp.value, 'function') | ||
t.deepEqual(resultProp, { | ||
...sourceProp, | ||
value: resultProp.value, | ||
}, 'prop descriptor matches (except value)') | ||
t.deepEqual( | ||
resultProp, | ||
{ | ||
...sourceProp, | ||
value: resultProp.value, | ||
}, | ||
'prop descriptor matches (except value)' | ||
) | ||
} | ||
{ | ||
const sourceProp = Object.getOwnPropertyDescriptor(sourceGlobal.Buffer, 'isBuffer') | ||
const resultProp = Object.getOwnPropertyDescriptor(resultGlobal.Buffer, 'isBuffer') | ||
const sourceProp = Object.getOwnPropertyDescriptor( | ||
sourceGlobal.Buffer, | ||
'isBuffer' | ||
) | ||
const resultProp = Object.getOwnPropertyDescriptor( | ||
resultGlobal.Buffer, | ||
'isBuffer' | ||
) | ||
t.is(typeof resultProp.value, 'function') | ||
t.deepEqual(resultProp, { | ||
...sourceProp, | ||
value: resultProp.value, | ||
}, 'prop descriptor matches (except value)') | ||
t.deepEqual( | ||
resultProp, | ||
{ | ||
...sourceProp, | ||
value: resultProp.value, | ||
}, | ||
'prop descriptor matches (except value)' | ||
) | ||
} | ||
@@ -59,5 +79,7 @@ }) | ||
const getEndowmentsForConfig = prepareTest() | ||
const sourceGlobal = { get abc () { | ||
return { xyz: 42 } | ||
} } | ||
const sourceGlobal = { | ||
get abc() { | ||
return { xyz: 42 } | ||
}, | ||
} | ||
const config = { | ||
@@ -74,8 +96,12 @@ globals: { | ||
const { enumerable, configurable } = sourceProp | ||
t.deepEqual(resultProp, { | ||
enumerable, | ||
configurable, | ||
value: resultProp.value, | ||
writable: true, | ||
}, 'prop descriptor matches (except value)') | ||
t.deepEqual( | ||
resultProp, | ||
{ | ||
enumerable, | ||
configurable, | ||
value: resultProp.value, | ||
writable: true, | ||
}, | ||
'prop descriptor matches (except value)' | ||
) | ||
} | ||
@@ -151,3 +177,8 @@ }) | ||
} | ||
const resultGlobal = getEndowmentsForConfig(sourceGlobal, config, unwrapTo, unwrapFrom) | ||
const resultGlobal = getEndowmentsForConfig( | ||
sourceGlobal, | ||
config, | ||
unwrapTo, | ||
unwrapFrom | ||
) | ||
const getter = Reflect.getOwnPropertyDescriptor(resultGlobal, 'xyz').get | ||
@@ -170,3 +201,3 @@ | ||
abc: function () { | ||
return this | ||
return this | ||
}, | ||
@@ -196,4 +227,4 @@ } | ||
const sourceGlobal = { | ||
setTimeout () { | ||
return this | ||
setTimeout() { | ||
return this | ||
}, | ||
@@ -200,0 +231,0 @@ } |
@@ -11,17 +11,24 @@ /* eslint-disable no-undef, no-unused-vars, no-unused-expressions, no-extend-native */ | ||
t.deepEqual(config, { | ||
resources: { | ||
test: { | ||
globals: { | ||
'location.href': true, | ||
t.deepEqual( | ||
config, | ||
{ | ||
resources: { | ||
test: { | ||
globals: { | ||
'location.href': true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, 'config matched expected') | ||
'config matched expected' | ||
) | ||
}) | ||
test('generatePolicy - config with debugInfo', async (t) => { | ||
const config = await createConfigForTest(function () { | ||
location.href | ||
}, { includeDebugInfo: true }) | ||
const config = await createConfigForTest( | ||
function () { | ||
location.href | ||
}, | ||
{ includeDebugInfo: true } | ||
) | ||
@@ -31,16 +38,21 @@ const testModuleFile = './node_modules/test/index.js' | ||
t.deepEqual(testPackageConfigDebugInfo, { | ||
moduleRecord: { | ||
specifier: testModuleFile, | ||
file: testModuleFile, | ||
type: 'js', | ||
content: '(function () {\n location.href\n })()', | ||
importMap: {}, | ||
packageName: 'test', | ||
moduleInitializer: undefined, | ||
t.deepEqual( | ||
testPackageConfigDebugInfo, | ||
{ | ||
moduleRecord: { | ||
specifier: testModuleFile, | ||
file: testModuleFile, | ||
type: 'js', | ||
// this is brittle | ||
content: '(function () {\n location.href\n })()', | ||
importMap: {}, | ||
packageName: 'test', | ||
moduleInitializer: undefined, | ||
}, | ||
globals: { | ||
'location.href': 'read', | ||
}, | ||
}, | ||
globals: { | ||
'location.href': 'read', | ||
}, | ||
}, 'config matched expected') | ||
'config matched expected' | ||
) | ||
}) | ||
@@ -56,11 +68,15 @@ | ||
t.deepEqual(config, { | ||
resources: { | ||
test: { | ||
globals: { | ||
nonIgnoredGlobal: true, | ||
t.deepEqual( | ||
config, | ||
{ | ||
resources: { | ||
test: { | ||
globals: { | ||
nonIgnoredGlobal: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, 'config matched expected') | ||
'config matched expected' | ||
) | ||
}) | ||
@@ -74,12 +90,16 @@ | ||
t.deepEqual(config, { | ||
resources: { | ||
test: { | ||
globals: { | ||
'location.href': true, | ||
XMLHttpRequest: true, | ||
t.deepEqual( | ||
config, | ||
{ | ||
resources: { | ||
test: { | ||
globals: { | ||
'location.href': true, | ||
XMLHttpRequest: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, 'config matches expected') | ||
'config matches expected' | ||
) | ||
}) | ||
@@ -92,5 +112,9 @@ | ||
t.deepEqual(config, { | ||
resources: {}, | ||
}, 'config matches expected') | ||
t.deepEqual( | ||
config, | ||
{ | ||
resources: {}, | ||
}, | ||
'config matches expected' | ||
) | ||
}) | ||
@@ -103,5 +127,9 @@ | ||
t.deepEqual(config, { | ||
resources: {}, | ||
}, 'config matches expected') | ||
t.deepEqual( | ||
config, | ||
{ | ||
resources: {}, | ||
}, | ||
'config matches expected' | ||
) | ||
}) | ||
@@ -114,5 +142,9 @@ | ||
t.deepEqual(config, { | ||
resources: {}, | ||
}, 'config matches expected') | ||
t.deepEqual( | ||
config, | ||
{ | ||
resources: {}, | ||
}, | ||
'config matches expected' | ||
) | ||
}) | ||
@@ -119,0 +151,0 @@ |
const test = require('ava') | ||
const { | ||
createScenarioFromScaffold, | ||
runScenario, | ||
} = require('./util') | ||
const { createScenarioFromScaffold, runScenario } = require('./util') | ||
@@ -21,3 +18,3 @@ test('globals - ensure global property this-value unwrapped', async (t) => { | ||
return (this === scenario.globalThis || this === scenario.vmContext) | ||
return this === scenario.globalThis || this === scenario.vmContext | ||
}, | ||
@@ -36,6 +33,10 @@ }, | ||
const testResult = await runScenario({ scenario }) | ||
t.deepEqual(testResult, { | ||
direct: true, | ||
indirect: false, | ||
}, 'expected result, did not error') | ||
t.deepEqual( | ||
testResult, | ||
{ | ||
direct: true, | ||
indirect: false, | ||
}, | ||
'expected result, did not error' | ||
) | ||
}) | ||
@@ -64,3 +65,5 @@ | ||
// chrome: Uncaught TypeError: Illegal invocation | ||
throw new TypeError('\'get document\' called on an object that does not implement interface Window') | ||
throw new TypeError( | ||
"'get document' called on an object that does not implement interface Window" | ||
) | ||
} | ||
@@ -93,3 +96,2 @@ return { | ||
test('globals - ensure circular refs on package compartment global', async (t) => { | ||
@@ -130,6 +132,8 @@ const scenario = createScenarioFromScaffold({ | ||
context: { | ||
setTimeout () { | ||
setTimeout() { | ||
if (this !== scenario.globalThis && this !== scenario.vmContext) { | ||
// chrome: Uncaught TypeError: Illegal invocation | ||
throw new TypeError('\'setTimeout\' called on an object that does not implement interface Window') | ||
throw new TypeError( | ||
"'setTimeout' called on an object that does not implement interface Window" | ||
) | ||
} | ||
@@ -166,3 +170,3 @@ }, | ||
abc: function () { | ||
return this | ||
return this | ||
}, | ||
@@ -181,9 +185,13 @@ }, | ||
const testResult = await runScenario({ scenario }) | ||
t.deepEqual(testResult, { | ||
typeof: true, | ||
isUndefined: true, | ||
isTrue: true, | ||
is42: true, | ||
isXyz: true, | ||
}, 'expected result, did not error') | ||
t.deepEqual( | ||
testResult, | ||
{ | ||
typeof: true, | ||
isUndefined: true, | ||
isTrue: true, | ||
is42: true, | ||
isXyz: true, | ||
}, | ||
'expected result, did not error' | ||
) | ||
}) | ||
@@ -207,3 +215,3 @@ | ||
globals: { | ||
'abc': true, | ||
abc: true, | ||
}, | ||
@@ -226,3 +234,3 @@ }, | ||
abc: function () { | ||
return 42 | ||
return 42 | ||
}, | ||
@@ -234,3 +242,3 @@ }, | ||
globals: { | ||
'abc': false, | ||
abc: false, | ||
}, | ||
@@ -241,3 +249,5 @@ }, | ||
}) | ||
await t.throwsAsync(runScenario({ scenario }), { message: 'globalThis.abc is not a function' }) | ||
await t.throwsAsync(runScenario({ scenario }), { | ||
message: 'globalThis.abc is not a function', | ||
}) | ||
}) | ||
@@ -253,3 +263,3 @@ | ||
abc: function () { | ||
return 42 | ||
return 42 | ||
}, | ||
@@ -261,3 +271,3 @@ }, | ||
globals: { | ||
'abc': true, | ||
abc: true, | ||
}, | ||
@@ -271,3 +281,3 @@ }, | ||
globals: { | ||
'abc': false, | ||
abc: false, | ||
}, | ||
@@ -278,3 +288,5 @@ }, | ||
}) | ||
await t.throwsAsync(runScenario({ scenario }), { message: 'globalThis.abc is not a function' }) | ||
await t.throwsAsync(runScenario({ scenario }), { | ||
message: 'globalThis.abc is not a function', | ||
}) | ||
}) | ||
@@ -287,3 +299,3 @@ | ||
context: { | ||
a: { ok: 42, b: { c: () => 42, notOk:41 }}, | ||
a: { ok: 42, b: { c: () => 42, notOk: 41 } }, | ||
}, | ||
@@ -294,5 +306,5 @@ config: { | ||
globals: { | ||
'a': true, | ||
a: true, | ||
'a.b': false, | ||
'a.b.c':true, | ||
'a.b.c': true, | ||
}, | ||
@@ -320,3 +332,2 @@ }, | ||
t.is(testResult.a_b_notOk, false) | ||
}) | ||
@@ -328,4 +339,4 @@ | ||
context: { | ||
a: { b: { c: () => 42, notOk:41 }}, | ||
x: { notOk:41, y: () => 42 }, | ||
a: { b: { c: () => 42, notOk: 41 } }, | ||
x: { notOk: 41, y: () => 42 }, | ||
}, | ||
@@ -337,4 +348,4 @@ config: { | ||
'a.b': false, | ||
'a.b.c':true, | ||
'x': false, | ||
'a.b.c': true, | ||
x: false, | ||
'x.y': true, | ||
@@ -372,3 +383,3 @@ }, | ||
context: { | ||
a: { ok: 42, b: { c: () => 42, notOk:41 }}, | ||
a: { ok: 42, b: { c: () => 42, notOk: 41 } }, | ||
}, | ||
@@ -379,3 +390,3 @@ config: { | ||
globals: { | ||
'a': true, | ||
a: true, | ||
'a.b': false, | ||
@@ -415,3 +426,3 @@ }, | ||
function exportLazyGetter(object, prop, getter) { | ||
let redefine = value => { | ||
let redefine = (value) => { | ||
if (value === undefined) { | ||
@@ -437,7 +448,7 @@ delete object[prop] | ||
get: function() { | ||
get: function () { | ||
return redefine(getter.call(this)) | ||
}, | ||
set: function(value) { | ||
set: function (value) { | ||
redefine(value) | ||
@@ -453,3 +464,3 @@ }, | ||
globals: { | ||
'chrome': true, | ||
chrome: true, | ||
}, | ||
@@ -456,0 +467,0 @@ }, |
@@ -5,94 +5,104 @@ /* eslint-disable no-undef, no-unused-vars, no-unused-expressions, no-extend-native */ | ||
testMerge('merge with resources', { | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: true, | ||
xyz: false, | ||
'a.b.c': true, | ||
testMerge( | ||
'merge with resources', | ||
{ | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: true, | ||
xyz: false, | ||
'a.b.c': true, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
}, | ||
}, { | ||
resources: { | ||
babel: { | ||
globals: { | ||
def: true, | ||
ghi: false, | ||
'a.b': true, | ||
{ | ||
resources: { | ||
babel: { | ||
globals: { | ||
def: true, | ||
ghi: false, | ||
'a.b': true, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
}, | ||
}, { | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: true, | ||
xyz: false, | ||
def: true, | ||
ghi: false, | ||
'a.b': true, | ||
{ | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: true, | ||
xyz: false, | ||
def: true, | ||
ghi: false, | ||
'a.b': true, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
}, | ||
}) | ||
} | ||
) | ||
testMerge('overrides to disallow', { | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: true, | ||
xyz: false, | ||
'a.b': true, | ||
'q.w.e': true, | ||
testMerge( | ||
'overrides to disallow', | ||
{ | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: true, | ||
xyz: false, | ||
'a.b': true, | ||
'q.w.e': true, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
builtin: { | ||
derp: true, | ||
qwerty: false, | ||
}, | ||
}, | ||
}, | ||
}, { | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: false, | ||
'a.b.c': false, // this is not supported | ||
'q.w': false, | ||
{ | ||
resources: { | ||
babel: { | ||
globals: { | ||
abc: false, | ||
'a.b.c': false, // this is not supported | ||
'q.w': false, | ||
}, | ||
builtin: { | ||
derp: false, | ||
}, | ||
}, | ||
builtin: { | ||
derp: false, | ||
}, | ||
}, | ||
}, | ||
}, { | ||
resources: { | ||
babel: { | ||
builtin: { | ||
derp: false, | ||
qwerty: false, | ||
{ | ||
resources: { | ||
babel: { | ||
builtin: { | ||
derp: false, | ||
qwerty: false, | ||
}, | ||
globals: { | ||
'a.b': true, | ||
abc: false, | ||
'q.w': false, | ||
xyz: false, | ||
}, | ||
}, | ||
globals: { | ||
'a.b': true, | ||
abc: false, | ||
'q.w': false, | ||
xyz: false, | ||
}, | ||
}, | ||
}, | ||
}) | ||
} | ||
) | ||
function testMerge (label, configA, configB, expectedResultObj) { | ||
function testMerge(label, configA, configB, expectedResultObj) { | ||
test(label, (t) => { | ||
@@ -99,0 +109,0 @@ const result = mergePolicy(configA, configB) |
@@ -8,3 +8,5 @@ const test = require('ava') | ||
console.log(`Running Core Scenario: ${scenario.name}`) | ||
await runAndTestScenario(t, scenario, ({ scenario }) => runScenario({ scenario })) | ||
await runAndTestScenario(t, scenario, ({ scenario }) => | ||
runScenario({ scenario }) | ||
) | ||
} | ||
@@ -16,4 +18,6 @@ }) | ||
console.log(`Running Core Scenario: ${scenario.name}`) | ||
await runAndTestScenario(t, scenario, ({ scenario }) => runScenario({ scenario, runWithPrecompiledModules: true })) | ||
await runAndTestScenario(t, scenario, ({ scenario }) => | ||
runScenario({ scenario, runWithPrecompiledModules: true }) | ||
) | ||
} | ||
}) |
@@ -1,2 +0,5 @@ | ||
const { createScenarioFromScaffold, autoConfigForScenario } = require('../util.js') | ||
const { | ||
createScenarioFromScaffold, | ||
autoConfigForScenario, | ||
} = require('../util.js') | ||
@@ -3,0 +6,0 @@ module.exports = [ |
@@ -12,3 +12,3 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
module.exports = function (n) { | ||
return n * 111 | ||
return n * 111 | ||
} | ||
@@ -26,3 +26,3 @@ }, | ||
// https://github.com/feross/buffer/blob/795bbb5bda1b39f1370ebd784bea6107b087e3a7/index.js#L611 | ||
function Buffer (_arg, _encodingOrOffset, _length) {} | ||
function Buffer(_arg, _encodingOrOffset, _length) {} | ||
Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype) | ||
@@ -43,4 +43,4 @@ Object.setPrototypeOf(Buffer, Uint8Array) | ||
const abc = new Function('this.value = this.derp()') | ||
abc.prototype.derp = function() { | ||
return 123 | ||
abc.prototype.derp = function () { | ||
return 123 | ||
} | ||
@@ -47,0 +47,0 @@ const xyz = new abc() |
@@ -221,3 +221,3 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
resources: { | ||
'$root$': { | ||
$root$: { | ||
packages: { | ||
@@ -241,3 +241,3 @@ two: true, | ||
resources: { | ||
'$root$': { | ||
$root$: { | ||
packages: { | ||
@@ -244,0 +244,0 @@ two: true, |
@@ -66,3 +66,3 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
t.is(isRecent(result.non), true) | ||
function isRecent (time) { | ||
function isRecent(time) { | ||
// more recent than 2020-01-01T00:00:00.000Z | ||
@@ -69,0 +69,0 @@ return time > 1577836800000 |
@@ -10,10 +10,10 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
try { | ||
testResults.objCheckThis = this.Object === Object | ||
} catch (_) { } | ||
testResults.objCheckThis = this.Object === Object | ||
} catch (_) {} | ||
try { | ||
testResults.objCheckGlobal = globalThis.Object === Object | ||
} catch (_) { } | ||
testResults.objCheckGlobal = globalThis.Object === Object | ||
} catch (_) {} | ||
try { | ||
testResults.thisIsExports = exports === this | ||
} catch (_) { } | ||
testResults.thisIsExports = exports === this | ||
} catch (_) {} | ||
module.exports = testResults | ||
@@ -55,3 +55,7 @@ }, | ||
// test webpack result against globalThis | ||
module.exports = { match: g === globalThis, type: typeof g, error: error && error.message } | ||
module.exports = { | ||
match: g === globalThis, | ||
type: typeof g, | ||
error: error && error.message, | ||
} | ||
}, | ||
@@ -58,0 +62,0 @@ expectedResult: { match: true, type: 'object' }, |
@@ -28,3 +28,3 @@ const autogen = require('./autogen') | ||
async function * loadScenarios () { | ||
async function* loadScenarios() { | ||
for (const scenarioCreator of scenarios) { | ||
@@ -31,0 +31,0 @@ yield await scenarioCreator() |
@@ -56,3 +56,3 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
class ModernClass { | ||
constructor () { | ||
constructor() { | ||
this.abc = 123 | ||
@@ -78,3 +78,3 @@ } | ||
class NewClass extends BaseClass { | ||
constructor () { | ||
constructor() { | ||
super() | ||
@@ -91,3 +91,3 @@ this.abc = 456 | ||
class BaseClass { | ||
constructor () { | ||
constructor() { | ||
this.abc = 123 | ||
@@ -190,3 +190,3 @@ } | ||
resources: { | ||
'$root$': { | ||
$root$: { | ||
packages: { | ||
@@ -193,0 +193,0 @@ one: true, |
@@ -1,2 +0,5 @@ | ||
const { createScenarioFromScaffold, autoConfigForScenario } = require('../util.js') | ||
const { | ||
createScenarioFromScaffold, | ||
autoConfigForScenario, | ||
} = require('../util.js') | ||
@@ -23,3 +26,15 @@ const one = () => { | ||
enabled: true, | ||
exceptions: ['WebAssembly', 'process', '/[0-9]+/', 'Set', 'Reflect', 'Object', 'console', 'Array', 'RegExp', 'Date', 'Math'], | ||
exceptions: [ | ||
'WebAssembly', | ||
'process', | ||
'/[0-9]+/', | ||
'Set', | ||
'Reflect', | ||
'Object', | ||
'console', | ||
'Array', | ||
'RegExp', | ||
'Date', | ||
'Math', | ||
], | ||
}, | ||
@@ -38,7 +53,12 @@ }, | ||
enabled: true, | ||
exceptions: ['WebAssembly', 'process', '/[0-9]+/' /*'Set', 'Reflect', 'Object', 'console', 'Array', 'RegExp', 'Date', 'Math'*/], | ||
exceptions: [ | ||
'WebAssembly', | ||
'process', | ||
'/[0-9]+/' /*'Set', 'Reflect', 'Object', 'console', 'Array', 'RegExp', 'Date', 'Math'*/, | ||
], | ||
}, | ||
}, | ||
expectedFailure: true, | ||
expectedFailureMessageRegex: /SES_UNHANDLED_REJECTION|inaccessible under scuttling mode./, | ||
expectedFailureMessageRegex: | ||
/SES_UNHANDLED_REJECTION|inaccessible under scuttling mode./, | ||
}) | ||
@@ -45,0 +65,0 @@ await autoConfigForScenario({ scenario }) |
@@ -9,11 +9,14 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
require('two') | ||
module.exports = { objectXyz: 'xyz' in Object, protoXyz: 'xyz' in Object.prototype } | ||
module.exports = { | ||
objectXyz: 'xyz' in Object, | ||
protoXyz: 'xyz' in Object.prototype, | ||
} | ||
}, | ||
defineTwo: () => { | ||
try { | ||
Object.xyz = 123 | ||
} catch (_) { } | ||
Object.xyz = 123 | ||
} catch (_) {} | ||
try { | ||
Object.protoype.xyz = 123 | ||
} catch (_) { } | ||
Object.protoype.xyz = 123 | ||
} catch (_) {} | ||
}, | ||
@@ -32,3 +35,3 @@ expectedResult: { objectXyz: false, protoXyz: false }, | ||
try { | ||
module.exports = setTimeout | ||
module.exports = setTimeout | ||
} catch (_) {} | ||
@@ -35,0 +38,0 @@ }, |
@@ -30,6 +30,9 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
defineTwo: () => { | ||
function SubError () {} | ||
function SubError() {} | ||
_inheritsLoose(SubError, TypeError) | ||
/* eslint-disable */ | ||
function _inheritsLoose (t, e) { t.prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e } | ||
function _inheritsLoose(t, e) { | ||
;(t.prototype = Object.create(e.prototype)), | ||
((t.prototype.constructor = t).__proto__ = e) | ||
} | ||
module.exports = SubError | ||
@@ -48,10 +51,13 @@ /* eslint-enable */ | ||
const SuperClass = require('two') | ||
function SubClass () {} | ||
function SubClass() {} | ||
_inheritsLoose(SubClass, SuperClass) | ||
module.exports = { SubClass } | ||
function _inheritsLoose (t, e) { t.prototype = Object.create(e.prototype), (t.prototype.constructor = t).__proto__ = e } | ||
function _inheritsLoose(t, e) { | ||
;(t.prototype = Object.create(e.prototype)), | ||
((t.prototype.constructor = t).__proto__ = e) | ||
} | ||
/* eslint-enable */ | ||
}, | ||
defineTwo: () => { | ||
function SuperClass () {} | ||
function SuperClass() {} | ||
module.exports = SuperClass | ||
@@ -58,0 +64,0 @@ }, |
287
test/util.js
@@ -1,2 +0,7 @@ | ||
const { parseForPolicy, LavamoatModuleRecord, generateKernel, getDefaultPaths } = require('../src/index.js') | ||
const { | ||
parseForPolicy, | ||
LavamoatModuleRecord, | ||
generateKernel, | ||
getDefaultPaths, | ||
} = require('../src/index.js') | ||
const mergeDeep = require('merge-deep') | ||
@@ -25,10 +30,14 @@ const { runInContext, createContext } = require('vm') | ||
async function generatePolicyFromFiles ({ files, ...opts }) { | ||
async function generatePolicyFromFiles({ files, ...opts }) { | ||
const config = await parseForPolicy({ | ||
moduleSpecifier: files.find(file => file.entry).specifier, | ||
moduleSpecifier: files.find((file) => file.entry).specifier, | ||
resolveHook: (requestedName, parentAddress) => { | ||
return files.find(file => file.specifier === parentAddress).importMap[requestedName] | ||
return files.find((file) => file.specifier === parentAddress).importMap[ | ||
requestedName | ||
] | ||
}, | ||
importHook: async (address) => { | ||
return new LavamoatModuleRecord(files.find(file => file.specifier === address)) | ||
return new LavamoatModuleRecord( | ||
files.find((file) => file.specifier === address) | ||
) | ||
}, | ||
@@ -43,3 +52,3 @@ isBuiltin: () => false, | ||
function createScenarioFromScaffold ({ | ||
function createScenarioFromScaffold({ | ||
name = 'template scenario', | ||
@@ -60,7 +69,11 @@ expectedResult = { | ||
t.truthy(err, `Scenario fails as expected: ${scenario.name} - ${err}`) | ||
t.regex(err.message, scenario.expectedFailureMessageRegex, 'Error message expects to match regex') | ||
t.regex( | ||
err.message, | ||
scenario.expectedFailureMessageRegex, | ||
'Error message expects to match regex' | ||
) | ||
} else { | ||
if (err) { | ||
t.fail(`Unexpected error in scenario: ${scenario.name} - ${err}`) | ||
throw (err) | ||
throw err | ||
} | ||
@@ -71,7 +84,14 @@ } | ||
if (scenario.testType === 'truthy') { | ||
t.assert(result, `${scenario.name} - scenario gives expected truthy result`) | ||
t.assert( | ||
result, | ||
`${scenario.name} - scenario gives expected truthy result` | ||
) | ||
} else if (scenario.testType === 'falsy') { | ||
t.falsy(result, `${scenario.name} - scenario gives expected falsy result`) | ||
} else { | ||
t.deepEqual(result, scenario.expectedResult, `${scenario.name} - scenario gives expected result`) | ||
t.deepEqual( | ||
result, | ||
scenario.expectedResult, | ||
`${scenario.name} - scenario gives expected result` | ||
) | ||
} | ||
@@ -84,3 +104,3 @@ }, | ||
context = {}, | ||
opts = {scuttleGlobalThis: {}}, | ||
opts = { scuttleGlobalThis: {} }, | ||
config, | ||
@@ -96,3 +116,3 @@ configOverride, | ||
} = {}) { | ||
function _defineEntry () { | ||
function _defineEntry() { | ||
const testResult = require('one') | ||
@@ -102,7 +122,7 @@ console.log(JSON.stringify(testResult, null, 2)) | ||
function _defineOne () { | ||
function _defineOne() { | ||
module.exports = require('two') | ||
} | ||
function _defineTwo () { | ||
function _defineTwo() { | ||
module.exports = { | ||
@@ -113,3 +133,3 @@ value: 'this is module two', | ||
function _defineThree () { | ||
function _defineThree() { | ||
module.exports = { | ||
@@ -132,11 +152,14 @@ value: 'this is module three', | ||
'package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
one: '1.0.0', | ||
two: '1.0.0', | ||
three: '1.0.0', | ||
content: `${JSON.stringify( | ||
{ | ||
dependencies: { | ||
one: '1.0.0', | ||
two: '1.0.0', | ||
three: '1.0.0', | ||
}, | ||
devDependencies: {}, | ||
}, | ||
devDependencies: { | ||
}, | ||
}, null, 2)}`, | ||
null, | ||
2 | ||
)}`, | ||
}, | ||
@@ -152,8 +175,12 @@ 'node_modules/one/index.js': { | ||
'node_modules/one/package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
two: '1.0.0', | ||
three: '1.0.0', | ||
content: `${JSON.stringify( | ||
{ | ||
dependencies: { | ||
two: '1.0.0', | ||
three: '1.0.0', | ||
}, | ||
}, | ||
}, null, 2)}`, | ||
null, | ||
2 | ||
)}`, | ||
}, | ||
@@ -168,7 +195,11 @@ 'node_modules/two/index.js': { | ||
'node_modules/two/package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
three: '1.0.0', | ||
content: `${JSON.stringify( | ||
{ | ||
dependencies: { | ||
three: '1.0.0', | ||
}, | ||
}, | ||
}, null, 2)}`, | ||
null, | ||
2 | ||
)}`, | ||
}, | ||
@@ -183,7 +214,11 @@ 'node_modules/three/index.js': { | ||
'node_modules/three/package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
one: '1.0.0', | ||
content: `${JSON.stringify( | ||
{ | ||
dependencies: { | ||
one: '1.0.0', | ||
}, | ||
}, | ||
}, null, 2)}`, | ||
null, | ||
2 | ||
)}`, | ||
}, | ||
@@ -195,17 +230,20 @@ ...files, | ||
if (defaultPolicy) { | ||
_config = mergeDeep({ | ||
resources: { | ||
one: { | ||
packages: { | ||
two: true, | ||
three: true, | ||
_config = mergeDeep( | ||
{ | ||
resources: { | ||
one: { | ||
packages: { | ||
two: true, | ||
three: true, | ||
}, | ||
}, | ||
}, | ||
two: { | ||
packages: { | ||
three: true, | ||
two: { | ||
packages: { | ||
three: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, config) | ||
config | ||
) | ||
} else { | ||
@@ -215,11 +253,14 @@ _config = config | ||
const _configOverride = mergeDeep({ | ||
resources: { | ||
one: { | ||
packages: { | ||
five: true, | ||
const _configOverride = mergeDeep( | ||
{ | ||
resources: { | ||
one: { | ||
packages: { | ||
five: true, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, configOverride) | ||
configOverride | ||
) | ||
@@ -247,6 +288,6 @@ return { | ||
function createHookedConsole () { | ||
function createHookedConsole() { | ||
let hasResolved = false | ||
let resolve | ||
const firstLogEventPromise = new Promise(_resolve => { | ||
const firstLogEventPromise = new Promise((_resolve) => { | ||
resolve = _resolve | ||
@@ -277,6 +318,3 @@ }) | ||
async function runScenario ({ | ||
scenario, | ||
runWithPrecompiledModules = false, | ||
}) { | ||
async function runScenario({ scenario, runWithPrecompiledModules = false }) { | ||
const { | ||
@@ -296,3 +334,12 @@ entries, | ||
Object.assign(scenario.context, { console: hookedConsole }) | ||
const { result: createKernel, vmGlobalThis, vmContext, vmFeralFunction } = evaluateWithSourceUrl('LavaMoat/core-test/kernel', kernelSrc, scenario.context) | ||
const { | ||
result: createKernel, | ||
vmGlobalThis, | ||
vmContext, | ||
vmFeralFunction, | ||
} = evaluateWithSourceUrl( | ||
'LavaMoat/core-test/kernel', | ||
kernelSrc, | ||
scenario.context | ||
) | ||
// root global for test realm | ||
@@ -321,3 +368,5 @@ scenario.globalThis = vmGlobalThis | ||
// append the source or prepare the precompiledInitializer | ||
const intializerSource = `(function(exports, require, module, __filename, __dirname){\n${applySourceTransforms(moduleRecord.content)}\n})` | ||
const intializerSource = `(function(exports, require, module, __filename, __dirname){\n${applySourceTransforms( | ||
moduleRecord.content | ||
)}\n})` | ||
if (runWithPrecompiledModules) { | ||
@@ -346,3 +395,3 @@ moduleData.precompiledInitializer = vmFeralFunction(` | ||
entries.forEach(id => kernel.internalRequire(id)) | ||
entries.forEach((id) => kernel.internalRequire(id)) | ||
const testResult = await firstLogEventPromise | ||
@@ -352,5 +401,9 @@ return testResult | ||
async function prepareScenarioOnDisk ({ scenario, policyName = 'policies', projectDir }) { | ||
async function prepareScenarioOnDisk({ | ||
scenario, | ||
policyName = 'policies', | ||
projectDir, | ||
}) { | ||
if (projectDir === undefined) { | ||
({ path: projectDir } = await tmp.dir()) | ||
;({ path: projectDir } = await tmp.dir()) | ||
} | ||
@@ -360,19 +413,36 @@ const filesToWrite = Object.values(scenario.files) | ||
const defaultPaths = getDefaultPaths(policyName) | ||
const primaryPath = typeof scenario.opts.policy === 'string' ? scenario.opts.policy : defaultPaths.primary | ||
filesToWrite.push({ file: primaryPath, content: stringify(scenario.config) }) | ||
const primaryPath = | ||
typeof scenario.opts.policy === 'string' | ||
? scenario.opts.policy | ||
: defaultPaths.primary | ||
filesToWrite.push({ | ||
file: primaryPath, | ||
content: stringify(scenario.config), | ||
}) | ||
if (scenario.configOverride) { | ||
const overridePath = typeof scenario.opts.policyOverride === 'string' ? scenario.opts.policyOverride : defaultPaths.override | ||
filesToWrite.push({ file: overridePath, content: stringify(scenario.configOverride) }) | ||
const overridePath = | ||
typeof scenario.opts.policyOverride === 'string' | ||
? scenario.opts.policyOverride | ||
: defaultPaths.override | ||
filesToWrite.push({ | ||
file: overridePath, | ||
content: stringify(scenario.configOverride), | ||
}) | ||
} | ||
} | ||
await Promise.all(filesToWrite.map(async (file) => { | ||
const fullPath = path.join(projectDir, file.file) | ||
const dirname = path.dirname(fullPath) | ||
await fs.mkdir(dirname, { recursive: true }) | ||
await fs.writeFile(fullPath, file.content) | ||
})) | ||
return { projectDir, policyDir: path.join(projectDir, `/lavamoat/${policyName}/`) } | ||
await Promise.all( | ||
filesToWrite.map(async (file) => { | ||
const fullPath = path.join(projectDir, file.file) | ||
const dirname = path.dirname(fullPath) | ||
await fs.mkdir(dirname, { recursive: true }) | ||
await fs.writeFile(fullPath, file.content) | ||
}) | ||
) | ||
return { | ||
projectDir, | ||
policyDir: path.join(projectDir, `/lavamoat/${policyName}/`), | ||
} | ||
} | ||
function fillInFileDetails (files) { | ||
function fillInFileDetails(files) { | ||
Object.entries(files).forEach(([file, fileObj]) => { | ||
@@ -390,3 +460,3 @@ fileObj.file = fileObj.file || file | ||
function moduleDataForBuiltin (builtinObj, name) { | ||
function moduleDataForBuiltin(builtinObj, name) { | ||
return { | ||
@@ -403,3 +473,7 @@ id: name, | ||
function prepareModuleInitializerArgs (requireRelativeWithContext, moduleObj, moduleData) { | ||
function prepareModuleInitializerArgs( | ||
requireRelativeWithContext, | ||
moduleObj, | ||
moduleData | ||
) { | ||
const require = requireRelativeWithContext | ||
@@ -411,3 +485,5 @@ const module = moduleObj | ||
require.resolve = (requestedName) => { | ||
throw new Error('require.resolve not implemented in lavamoat-core test harness') | ||
throw new Error( | ||
'require.resolve not implemented in lavamoat-core test harness' | ||
) | ||
} | ||
@@ -417,4 +493,3 @@ return [exports, require, module, __filename, __dirname] | ||
function evaluateWithSourceUrl (filename, content, context) { | ||
function evaluateWithSourceUrl(filename, content, context) { | ||
const vmContext = createContext() | ||
@@ -424,3 +499,6 @@ const vmGlobalThis = runInContext('this', vmContext) | ||
Object.defineProperties(vmGlobalThis, Object.getOwnPropertyDescriptors(context)) | ||
Object.defineProperties( | ||
vmGlobalThis, | ||
Object.getOwnPropertyDescriptors(context) | ||
) | ||
@@ -448,22 +526,25 @@ // circular ref (used when globalThis is not present) | ||
async function createConfigForTest (testFn, opts = {}) { | ||
const files = [{ | ||
type: 'js', | ||
specifier: './entry.js', | ||
file: './entry.js', | ||
packageName: '$root$', | ||
importMap: { | ||
test: './node_modules/test/index.js', | ||
async function createConfigForTest(testFn, opts = {}) { | ||
const files = [ | ||
{ | ||
type: 'js', | ||
specifier: './entry.js', | ||
file: './entry.js', | ||
packageName: '$root$', | ||
importMap: { | ||
test: './node_modules/test/index.js', | ||
}, | ||
content: 'require("test")', | ||
entry: true, | ||
}, | ||
content: 'require("test")', | ||
entry: true, | ||
}, { | ||
// non-entry | ||
type: 'js', | ||
specifier: './node_modules/test/index.js', | ||
file: './node_modules/test/index.js', | ||
packageName: 'test', | ||
importMap: {}, | ||
content: `(${testFn})()`, | ||
}] | ||
{ | ||
// non-entry | ||
type: 'js', | ||
specifier: './node_modules/test/index.js', | ||
file: './node_modules/test/index.js', | ||
packageName: 'test', | ||
importMap: {}, | ||
content: `(${testFn})()`, | ||
}, | ||
] | ||
const policy = await generatePolicyFromFiles({ files, ...opts }) | ||
@@ -473,3 +554,3 @@ return policy | ||
async function autoConfigForScenario ({ scenario, opts = {} }) { | ||
async function autoConfigForScenario({ scenario, opts = {} }) { | ||
const files = Object.values(scenario.files) | ||
@@ -480,3 +561,3 @@ const policy = await generatePolicyFromFiles({ files, ...opts }) | ||
function convertOptsToArgs ({ scenario }) { | ||
function convertOptsToArgs({ scenario }) { | ||
const { entries } = scenario | ||
@@ -483,0 +564,0 @@ if (entries.length !== 1) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
540813
14395
4
+ Added@babel/helper-environment-visitor@7.24.7(transitive)
+ Added@babel/helper-function-name@7.24.7(transitive)
+ Added@babel/helper-hoist-variables@7.24.7(transitive)
+ Added@babel/helper-split-export-declaration@7.24.7(transitive)
+ Added@babel/parser@7.24.6(transitive)
+ Added@babel/traverse@7.24.6(transitive)
+ Added@babel/types@7.24.6(transitive)
+ Added@types/babel__traverse@7.20.6(transitive)
+ Addedlavamoat-core@15.4.0(transitive)
+ Addedlavamoat-tofu@7.3.0(transitive)
+ Addedto-fast-properties@2.0.0(transitive)
+ Addedtype-fest@4.15.0(transitive)
- Removed@babel/traverse@7.25.9(transitive)
- Removedlavamoat-tofu@6.2.1(transitive)
Updatedlavamoat-tofu@^7.0.0