lavamoat-core
Advanced tools
Comparing version 11.0.1 to 12.0.0
{ | ||
"extends": "../../.eslintrc.json" | ||
"extends": "../../.eslintrc.json", | ||
"ignorePatterns": ["./lib/**/*.js"] | ||
} |
{ | ||
"name": "lavamoat-core", | ||
"version": "11.0.1", | ||
"version": "12.0.0", | ||
"description": "LavaMoat kernel and utils", | ||
@@ -15,5 +15,4 @@ "main": "src/index.js", | ||
"json-stable-stringify": "^1.0.1", | ||
"lavamoat-tofu": "^6.0.0", | ||
"merge-deep": "^3.0.2", | ||
"resolve": "^1.15.1" | ||
"lavamoat-tofu": "^6.0.1", | ||
"merge-deep": "^3.0.2" | ||
}, | ||
@@ -24,11 +23,10 @@ "devDependencies": { | ||
"object.fromentries": "^2.0.2", | ||
"ses": "^0.12.3", | ||
"tmp-promise": "^3.0.2" | ||
}, | ||
"scripts": { | ||
"lint": "npm run lint:eslint && npm run lint:deps", | ||
"lint": "yarn lint:eslint && yarn lint:deps", | ||
"lint:eslint": "eslint \"src/**/*.js\" \"test/**/*.js\"", | ||
"lint:fix": "eslint src/**/*.js test/**/*.js --fix", | ||
"lint:deps": "depcheck", | ||
"test": "ava test/index.js --timeout=2m" | ||
"test": "ava --timeout=30s test/index.js" | ||
}, | ||
@@ -55,3 +53,3 @@ "author": "kumavis", | ||
], | ||
"gitHead": "4004c5668749f6dfc7c9ee0fab72ee28d71a968d" | ||
"gitHead": "efefc17dd7df5a94e90585c426fd06be4473a58d" | ||
} |
@@ -13,4 +13,5 @@ const EventEmitter = require('events') | ||
} = require('lavamoat-tofu') | ||
const { mergePolicy } = require('./mergePolicy') | ||
const rootSlug = '<root>' | ||
const rootSlug = '$root$' | ||
@@ -191,7 +192,7 @@ module.exports = { rootSlug, createModuleInspector, getDefaultPaths } | ||
function generatePolicy ({ isBuiltin, includeDebugInfo } = {}) { | ||
function generatePolicy ({ policyOverride, includeDebugInfo } = {}) { | ||
const resources = {} | ||
const config = { resources } | ||
const policy = { resources } | ||
Object.entries(packageToModules).forEach(([packageName, packageModules]) => { | ||
// the config/policy fields for each package | ||
// the policy fields for each package | ||
let globals, builtin, packages, native | ||
@@ -228,12 +229,12 @@ // skip for root modules (modules not from deps) | ||
} | ||
// skip package config if there are no settings needed | ||
// skip package policy if there are no settings needed | ||
if (!packages && !globals && !builtin) return | ||
// create minimal config object | ||
const config = {} | ||
if (packages) config.packages = packages | ||
if (globals) config.globals = globals | ||
if (builtin) config.builtin = builtin | ||
if (native) config.native = native | ||
// set config for package | ||
resources[packageName] = config | ||
// create minimal policy object | ||
const packagePolicy = {} | ||
if (packages) packagePolicy.packages = packages | ||
if (globals) packagePolicy.globals = globals | ||
if (builtin) packagePolicy.builtin = builtin | ||
if (native) packagePolicy.native = native | ||
// set policy for package | ||
resources[packageName] = packagePolicy | ||
}) | ||
@@ -243,6 +244,8 @@ | ||
if (includeDebugInfo) { | ||
config.debugInfo = debugInfo | ||
policy.debugInfo = debugInfo | ||
} | ||
return config | ||
// merge override policy | ||
const mergedPolicy = mergePolicy(policy, policyOverride) | ||
return mergedPolicy | ||
} | ||
@@ -249,0 +252,0 @@ } |
const { | ||
generateKernel | ||
} = require('./generateKernel') | ||
const { packageDataForModule, packageNameFromPath } = require('./packageData') | ||
const { createModuleInspector, getDefaultPaths } = require('./generatePolicy') | ||
@@ -15,5 +14,2 @@ const { parseForPolicy } = require('./parseForPolicy') | ||
generateKernel, | ||
// decorating moduleData with package data | ||
packageNameFromPath, | ||
packageDataForModule, | ||
// generating lavamoat config | ||
@@ -20,0 +16,0 @@ createModuleInspector, |
@@ -69,8 +69,14 @@ (function () { | ||
const rootPackageName = '<root>' | ||
const rootPackageName = '$root$' | ||
const rootPackageCompartment = createRootPackageCompartment(globalRef) | ||
return { | ||
const kernel = { | ||
internalRequire | ||
} | ||
if (debugMode) { | ||
kernel._getPolicyForPackage = getPolicyForPackage | ||
kernel._getCompartmentForPackage = getCompartmentForPackage | ||
} | ||
Object.freeze(kernel) | ||
return kernel | ||
@@ -103,3 +109,3 @@ // this function instantiaties a module from a moduleId. | ||
const { package: packageName, source: moduleSource } = moduleData | ||
if (!packageName) throw new Error(`LavaMoat - invalid packageName for module "${moduleId}"`) | ||
if (!packageName) throw new Error(`LavaMoat - missing packageName for module "${moduleId}"`) | ||
const packagePolicy = getPolicyForPackage(lavamoatConfig, packageName) | ||
@@ -183,3 +189,3 @@ | ||
if (moduleData.type === 'builtin') typeText = ' node builtin ' | ||
throw new Error(`LavaMoat - required${typeText}package not in whitelist: package "${parentModulePackageName}" requested "${packageName}" as "${requestedName}"`) | ||
throw new Error(`LavaMoat - required${typeText}package not in allowlist: package "${parentModulePackageName}" requested "${packageName}" as "${requestedName}"`) | ||
} | ||
@@ -186,0 +192,0 @@ |
const fs = require('fs') | ||
const { mergePolicy } = require('./mergePolicy') | ||
@@ -7,3 +6,3 @@ module.exports = { loadPolicy } | ||
async function loadPolicy ({ debugMode, policyPath, policyOverridePath }) { | ||
async function loadPolicy ({ debugMode, policyPath }) { | ||
let policy = { resources: {} } | ||
@@ -18,12 +17,3 @@ // try policy | ||
} | ||
// try policy override | ||
if (fs.existsSync(policyOverridePath)) { | ||
if (debugMode) console.warn(`Lavamoat looking for override policy at ${policyOverridePath}`) | ||
const configSource = fs.readFileSync(policyOverridePath, 'utf8') | ||
const overrideConfig = JSON.parse(configSource) | ||
policy = mergePolicy(policy, overrideConfig) | ||
} else { | ||
if (debugMode) console.warn('Lavamoat could not find policy override') | ||
} | ||
return policy | ||
} |
@@ -6,19 +6,19 @@ const { reduceToTopmostApiCalls, objToMap, mapToObj } = require('lavamoat-tofu/src/util') | ||
function mergePolicy (configA, configB) { | ||
const mergedConfig = mergeDeep(configA, configB) | ||
Object.values(mergedConfig.resources).forEach((packageConfig) => { | ||
if ('globals' in packageConfig) { | ||
packageConfig.globals = dedupeConfigPaths(packageConfig.globals) | ||
function mergePolicy (policyA, policyB) { | ||
const mergedPolicy = mergeDeep(policyA, policyB) | ||
Object.values(mergedPolicy.resources).forEach((packagePolicy) => { | ||
if ('globals' in packagePolicy) { | ||
packagePolicy.globals = dedupePolicyPaths(packagePolicy.globals) | ||
} | ||
if ('builtin' in packageConfig) { | ||
packageConfig.builtin = dedupeConfigPaths(packageConfig.builtin) | ||
if ('builtin' in packagePolicy) { | ||
packagePolicy.builtin = dedupePolicyPaths(packagePolicy.builtin) | ||
} | ||
}) | ||
return mergedConfig | ||
return mergedPolicy | ||
} | ||
function dedupeConfigPaths (packageConfig) { | ||
const itemMap = objToMap(packageConfig) | ||
function dedupePolicyPaths (packagePolicy) { | ||
const itemMap = objToMap(packagePolicy) | ||
reduceToTopmostApiCalls(itemMap) | ||
return mapToObj(itemMap) | ||
} |
@@ -8,3 +8,2 @@ | ||
packageName, | ||
packageVersion, | ||
content, | ||
@@ -19,3 +18,2 @@ importMap = {}, | ||
this.packageName = packageName | ||
this.packageVersion = packageVersion | ||
this.content = content | ||
@@ -22,0 +20,0 @@ this.importMap = importMap |
const { createModuleInspector } = require('./generatePolicy') | ||
const { walk } = require('./walk') | ||
const { eachNodeInTree } = require('./walk') | ||
module.exports = { parseForPolicy } | ||
/** | ||
* @function parseForPolicy | ||
* @param {object} options | ||
* @param {string} options.moduleSpecifier | ||
* @param {function} options.isBuiltin | ||
* @param {function} options.shouldImport | ||
* @param {bool} options.includeDebugInfo | ||
* @param {ModuleInspector} options.inspector | ||
* @returns {JSON} policy object | ||
*/ | ||
async function parseForPolicy ({ | ||
@@ -12,14 +22,12 @@ moduleSpecifier, | ||
includeDebugInfo, | ||
policyOverride, | ||
inspector = createModuleInspector({ isBuiltin, includeDebugInfo }) | ||
}) { | ||
await walk({ moduleSpecifier, importHook, visitorFn, shouldImport }) | ||
// after all modules, submit config | ||
const config = inspector.generatePolicy() | ||
// console.log(JSON.stringify(config, null, 2)) | ||
return config | ||
function visitorFn (moduleRecord) { | ||
for await (const moduleRecord of eachNodeInTree({ moduleSpecifier, importHook, shouldImport })) { | ||
// inspect each module | ||
inspector.inspectModule(moduleRecord) | ||
} | ||
// after all modules, submit policy | ||
const policy = inspector.generatePolicy({ policyOverride }) | ||
return policy | ||
} |
// specifier = exact unique module name | ||
// requestedName = what a module asks to import | ||
module.exports = { walk } | ||
module.exports = { walk, eachNodeInTree } | ||
/** | ||
* @function walk | ||
* @param {object} options | ||
* @param {string} options.moduleSpecifier | ||
* @param {function} options.importHook | ||
* @param {function} options.visitorFn | ||
* @param {function} options.shouldImport | ||
* @param {Set<string>} options.visitedSpecifiers | ||
*/ | ||
async function walk ({ | ||
@@ -10,2 +19,28 @@ moduleSpecifier, | ||
visitorFn, | ||
shouldImport, | ||
visitedSpecifiers | ||
}) { | ||
for await (const moduleRecord of eachNodeInTree({ | ||
moduleSpecifier, | ||
importHook, | ||
shouldImport, | ||
visitedSpecifiers | ||
})) { | ||
// walk next record | ||
visitorFn(moduleRecord) | ||
} | ||
} | ||
/** | ||
* @function eachNodeInTree | ||
* @param {object} options | ||
* @param {string} options.moduleSpecifier, | ||
* @param {function} options.importHook, | ||
* @param {bool} options.shouldImport, | ||
* @param {Set<string>} options.visitedSpecifiers | ||
* @returns {AsyncIterableIterator<LavamoatModuleRecord>} | ||
*/ | ||
async function * eachNodeInTree ({ | ||
moduleSpecifier, | ||
importHook, | ||
shouldImport = () => true, | ||
@@ -16,22 +51,21 @@ visitedSpecifiers = new Set() | ||
const moduleRecord = await importHook(moduleSpecifier) | ||
visitorFn(moduleRecord) | ||
yield moduleRecord | ||
// walk children | ||
await Promise.all(Object.values(moduleRecord.importMap).map(async (childSpecifier) => { | ||
for (const childSpecifier of Object.values(moduleRecord.importMap)) { | ||
// skip children that are set to null (resolution was skipped) | ||
if (childSpecifier === null) return | ||
if (childSpecifier === null) continue | ||
// skip modules we're told not to import | ||
if (!shouldImport(childSpecifier, moduleSpecifier)) return | ||
if (!shouldImport(childSpecifier, moduleSpecifier)) continue | ||
// dont revisit specifiers | ||
if (visitedSpecifiers.has(childSpecifier)) return | ||
if (visitedSpecifiers.has(childSpecifier)) continue | ||
visitedSpecifiers.add(childSpecifier) | ||
// continue walking child | ||
await walk({ | ||
yield* eachNodeInTree({ | ||
moduleSpecifier: childSpecifier, | ||
importHook, | ||
visitorFn, | ||
shouldImport, | ||
visitedSpecifiers | ||
}) | ||
})) | ||
} | ||
} |
@@ -38,3 +38,2 @@ /* eslint-disable no-undef, no-unused-vars, no-unused-expressions, no-extend-native */ | ||
packageName: 'test', | ||
packageVersion: '1.2.3', | ||
moduleInitializer: undefined | ||
@@ -41,0 +40,0 @@ }, |
@@ -159,2 +159,3 @@ const test = require('ava') | ||
// eslint-disable-next-line ava/no-async-fn-without-await | ||
test('getEndowmentsForConfig - endowing bind of a function', async (t) => { | ||
@@ -161,0 +162,0 @@ 'use strict' |
@@ -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 |
@@ -187,3 +187,3 @@ const { createScenarioFromScaffold } = require('../util.js') | ||
resources: { | ||
'<root>': { | ||
'$root$': { | ||
packages: { | ||
@@ -190,0 +190,0 @@ one: true |
@@ -1,2 +0,2 @@ | ||
const { parseForPolicy, LavamoatModuleRecord, generateKernel, packageNameFromPath, getDefaultPaths } = require('../src/index.js') | ||
const { parseForPolicy, LavamoatModuleRecord, generateKernel, getDefaultPaths } = require('../src/index.js') | ||
const mergeDeep = require('merge-deep') | ||
@@ -12,3 +12,3 @@ const { runInContext, createContext } = require('vm') | ||
module.exports = { | ||
generateConfigFromFiles, | ||
generateConfigFromFiles: generatePolicyFromFiles, | ||
createScenarioFromScaffold, | ||
@@ -27,3 +27,3 @@ runScenario, | ||
async function generateConfigFromFiles ({ files, ...opts }) { | ||
async function generatePolicyFromFiles ({ files, ...opts }) { | ||
const config = await parseForPolicy({ | ||
@@ -116,3 +116,3 @@ moduleSpecifier: files.find(file => file.entry).specifier, | ||
content: `(${defineEntry || _defineEntry}).call(this)`, | ||
packageName: '<root>', | ||
packageName: '$root$', | ||
importMap: { | ||
@@ -125,2 +125,13 @@ one: 'node_modules/one/index.js', | ||
}, | ||
'package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
one: '1.0.0', | ||
two: '1.0.0', | ||
three: '1.0.0', | ||
}, | ||
devDependencies: { | ||
} | ||
}, null, 2)}`, | ||
}, | ||
'node_modules/one/index.js': { | ||
@@ -134,2 +145,10 @@ packageName: 'one', | ||
}, | ||
'node_modules/one/package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
two: '1.0.0', | ||
three: '1.0.0', | ||
} | ||
}, null, 2)}`, | ||
}, | ||
'node_modules/two/index.js': { | ||
@@ -142,2 +161,9 @@ packageName: 'two', | ||
}, | ||
'node_modules/two/package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
three: '1.0.0', | ||
} | ||
}, null, 2)}`, | ||
}, | ||
'node_modules/three/index.js': { | ||
@@ -150,2 +176,9 @@ packageName: 'three', | ||
}, | ||
'node_modules/three/package.json': { | ||
content: `${JSON.stringify({ | ||
dependencies: { | ||
one: '1.0.0', | ||
} | ||
}, null, 2)}`, | ||
}, | ||
...files | ||
@@ -300,4 +333,6 @@ }) | ||
async function prepareScenarioOnDisk ({ scenario, policyName = 'policies' }) { | ||
const { path: projectDir } = await tmp.dir() | ||
async function prepareScenarioOnDisk ({ scenario, policyName = 'policies', projectDir }) { | ||
if (projectDir === undefined) { | ||
({ path: projectDir } = await tmp.dir()) | ||
} | ||
const filesToWrite = Object.values(scenario.files) | ||
@@ -323,8 +358,11 @@ if (!scenario.opts.writeAutoPolicy) { | ||
function fillInFileDetails (files) { | ||
Object.entries(files).forEach(([file, moduleRecord]) => { | ||
moduleRecord.file = moduleRecord.file || file | ||
moduleRecord.specifier = moduleRecord.file || file | ||
moduleRecord.packageName = moduleRecord.packageName || packageNameFromPath(file) || '<root>' | ||
moduleRecord.type = moduleRecord.type || 'js' | ||
moduleRecord.entry = Boolean(moduleRecord.entry) | ||
Object.entries(files).forEach(([file, fileObj]) => { | ||
fileObj.file = fileObj.file || file | ||
if (path.extname(file) === '.js') { | ||
// parse as LavamoatModuleRecord | ||
fileObj.specifier = fileObj.file || file | ||
fileObj.packageName = fileObj.packageName | ||
fileObj.type = fileObj.type || 'js' | ||
fileObj.entry = Boolean(fileObj.entry) | ||
} | ||
}) | ||
@@ -385,4 +423,3 @@ return files | ||
file: './entry.js', | ||
packageName: '<root>', | ||
packageVersion: '0.0.0', | ||
packageName: '$root$', | ||
importMap: { | ||
@@ -399,8 +436,7 @@ test: './node_modules/test/index.js' | ||
packageName: 'test', | ||
packageVersion: '1.2.3', | ||
importMap: {}, | ||
content: `(${testFn})()` | ||
}] | ||
const config = await generateConfigFromFiles({ files, ...opts }) | ||
return config | ||
const policy = await generatePolicyFromFiles({ files, ...opts }) | ||
return policy | ||
} | ||
@@ -410,4 +446,4 @@ | ||
const files = Object.values(scenario.files) | ||
const config = await generateConfigFromFiles({ files, ...opts }) | ||
scenario.config = config | ||
const policy = await generatePolicyFromFiles({ files, ...opts }) | ||
scenario.config = policy | ||
} | ||
@@ -414,0 +450,0 @@ |
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
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
1125807
4
4
43
12332
7
- Removedresolve@^1.15.1
- Removedis-core-module@2.15.1(transitive)
- Removedpath-parse@1.0.7(transitive)
- Removedresolve@1.22.8(transitive)
- Removedsupports-preserve-symlinks-flag@1.0.0(transitive)
Updatedlavamoat-tofu@^6.0.1