diff --git a/packages/compartment-mapper/src/import-archive.js b/packages/compartment-mapper/src/import-archive.js index df61f0664a..c3248cfdad 100644 --- a/packages/compartment-mapper/src/import-archive.js +++ b/packages/compartment-mapper/src/import-archive.js @@ -95,6 +95,9 @@ const makeArchiveImportHookMaker = ( // module is a "builtin" module and the policy needs to be enforced. enforceModulePolicy(moduleSpecifier, compartmentDescriptor, { exit: true, + errorHint: `Blocked in loading. ${q( + moduleSpecifier, + )} was not in the archive and an attempt was made to load it as a builtin`, }); const record = await exitModuleImportHook(moduleSpecifier); if (record) { diff --git a/packages/compartment-mapper/src/import-hook.js b/packages/compartment-mapper/src/import-hook.js index e3a58029f8..af58c33b70 100644 --- a/packages/compartment-mapper/src/import-hook.js +++ b/packages/compartment-mapper/src/import-hook.js @@ -220,6 +220,9 @@ export const makeImportHookMaker = ( // hook returns something. Otherwise, we need to fall back to the 'cannot find' error below. enforceModulePolicy(moduleSpecifier, compartmentDescriptor, { exit: true, + errorHint: `Blocked in loading. ${q( + moduleSpecifier, + )} was not in the compartment map and an attempt was made to load it as a builtin`, }); if (archiveOnly) { // Return a place-holder. diff --git a/packages/compartment-mapper/src/link.js b/packages/compartment-mapper/src/link.js index 3ae1fcaf75..302e439379 100644 --- a/packages/compartment-mapper/src/link.js +++ b/packages/compartment-mapper/src/link.js @@ -19,7 +19,6 @@ import { parseExtension } from './extension.js'; import { enforceModulePolicy, ATTENUATORS_COMPARTMENT, - diagnoseMissingCompartmentError, attenuateGlobals, makeDeferredAttenuatorsProvider, } from './policy.js'; @@ -232,10 +231,14 @@ const makeModuleMapHook = ( return undefined; // fall through to import hook } if (foreignModuleSpecifier !== undefined) { + // archive goes through foreignModuleSpecifier for local modules too if (!moduleSpecifier.startsWith('./')) { - // archive goes through foreignModuleSpecifier for local modules too + // This code path seems to only be reached on subsequent imports of the same specifier in the same compartment. + // The check should be redundant and is only left here out of abundance of caution. enforceModulePolicy(moduleSpecifier, compartmentDescriptor, { exit: false, + errorHint: + 'This check should not be reachable. If you see this error, please file an issue.', }); } @@ -244,12 +247,7 @@ const makeModuleMapHook = ( throw Error( `Cannot import from missing compartment ${q( foreignCompartmentName, - )}${diagnoseMissingCompartmentError({ - moduleSpecifier, - compartmentDescriptor, - foreignModuleSpecifier, - foreignCompartmentName, - })}`, + )}}`, ); } return foreignCompartment.module(foreignModuleSpecifier); @@ -279,20 +277,17 @@ const makeModuleMapHook = ( throw Error( `Cannot import from missing compartment ${q( foreignCompartmentName, - )}${diagnoseMissingCompartmentError({ - moduleSpecifier, - compartmentDescriptor, - foreignModuleSpecifier, - foreignCompartmentName, - })}`, + )}`, ); } - // Despite all non-exit modules not allowed by policy being dropped - // while building the graph, this check is necessary because module - // is written back to the compartment map below. enforceModulePolicy(scopePrefix, compartmentDescriptor, { exit: false, + errorHint: `Blocked in linking. ${q( + moduleSpecifier, + )} is part of the compartment map and resolves to ${q( + foreignCompartmentName, + )}.`, }); // The following line is weird. // Information is flowing backward. diff --git a/packages/compartment-mapper/src/node-modules.js b/packages/compartment-mapper/src/node-modules.js index 611634faa2..056070f12a 100644 --- a/packages/compartment-mapper/src/node-modules.js +++ b/packages/compartment-mapper/src/node-modules.js @@ -566,7 +566,7 @@ const graphPackages = async ( * @param {Graph} graph * @param {Set} tags - build tags about the target environment * for selecting relevant exports, e.g., "browser" or "node". - * @param {object} policy + * @param {object|undefined} policy * @returns {CompartmentMapDescriptor} */ const translateGraph = ( @@ -611,11 +611,6 @@ const translateGraph = ( }, policy, ); - // do not include compartments for packages not covered by policy - if (policy && !packagePolicy) { - // eslint-disable-next-line no-continue - continue; - } /** * @param {string} dependencyName diff --git a/packages/compartment-mapper/src/policy-format.js b/packages/compartment-mapper/src/policy-format.js index 5f2f57e353..958ca2fb1f 100644 --- a/packages/compartment-mapper/src/policy-format.js +++ b/packages/compartment-mapper/src/policy-format.js @@ -122,7 +122,7 @@ export const assertPackagePolicy = (allegedPackagePolicy, path, url) => { const packagePolicy = Object(allegedPackagePolicy); assert( allegedPackagePolicy === packagePolicy && !isArray(allegedPackagePolicy), - `${path} must be an object, got ${allegedPackagePolicy}${inUrl}`, + `${path} must be an object, got ${q(allegedPackagePolicy)}${inUrl}`, ); const { packages, diff --git a/packages/compartment-mapper/src/policy.js b/packages/compartment-mapper/src/policy.js index 042c5c0001..8604bcb2ac 100644 --- a/packages/compartment-mapper/src/policy.js +++ b/packages/compartment-mapper/src/policy.js @@ -17,7 +17,7 @@ import { isAllowingEverything, } from './policy-format.js'; -const { entries, values, assign, keys, freeze } = Object; +const { create, entries, values, assign, keys, freeze } = Object; const q = JSON.stringify; /** @@ -113,29 +113,6 @@ export const dependencyAllowedByPolicy = (namingKit, packagePolicy) => { return !!policyLookupHelper(packagePolicy, 'packages', canonicalName); }; -const validateDependencies = (policy, canonicalName) => { - const packages = policy.resources[canonicalName].packages; - if (!packages || isAllowingEverything(packages)) { - return; - } - - const packageNames = keys(packages); - const attenuators = detectAttenuators(policy); - // Join attenuators with packageNames into a Set to deduplicate and check if all are listed in policy.resources - const allSpecifiers = new Set([...packageNames, ...attenuators]); - for (const specifier of allSpecifiers) { - if (!(specifier in policy.resources)) { - throw Error( - `Package ${q(specifier)} is allowed for ${q( - canonicalName, - )} to import but its policy is not defined. Please add a policy for ${q( - specifier, - )}`, - ); - } - } -}; - /** * Returns the policy applicable to the canonicalName of the package * @@ -154,20 +131,14 @@ export const getPolicyForPackage = (namingKit, policy) => { if (canonicalName === ATTENUATORS_COMPARTMENT) { return { defaultAttenuator: policy.defaultAttenuator, - packages: detectAttenuators(policy).reduce((packages, specifier) => { - packages[specifier] = true; - return packages; - }, {}), + packages: 'any', }; } - if (policy.resources && policy.resources[canonicalName]) { - validateDependencies(policy, canonicalName); + if (policy.resources && policy.resources[canonicalName] !== undefined) { return policy.resources[canonicalName]; } else { - console.warn( - `No policy for '${canonicalName}', omitting from compartment map.`, - ); - return undefined; + // Allow skipping policy entries for packages with no powers. + return create(null); } }; @@ -357,15 +328,25 @@ export const attenuateGlobals = ( freezeGlobalThisUnlessOptedOut(); }; +const diagnoseModulePolicy = errorHint => { + if (!errorHint) { + return ''; + } + return ` (info: ${errorHint})`; +}; /** * Throws if importing of the specifier is not allowed by the policy * * @param {string} specifier - * @param {object} compartmentDescriptor + * @param {import('./types.js').CompartmentDescriptor} compartmentDescriptor * @param {object} [info] */ -export const enforceModulePolicy = (specifier, compartmentDescriptor, info) => { - const { policy, modules } = compartmentDescriptor; +export const enforceModulePolicy = ( + specifier, + compartmentDescriptor, + info = {}, +) => { + const { policy, modules, label } = compartmentDescriptor; if (!policy) { return; } @@ -373,9 +354,11 @@ export const enforceModulePolicy = (specifier, compartmentDescriptor, info) => { if (!info.exit) { if (!modules[specifier]) { throw Error( - `Importing ${q(specifier)} was not allowed by policy packages:${q( + `Importing ${q(specifier)} in ${q( + label, + )} was not allowed by packages policy ${q( policy.packages, - )}`, + )}${diagnoseModulePolicy(info.errorHint)}`, ); } return; @@ -385,7 +368,7 @@ export const enforceModulePolicy = (specifier, compartmentDescriptor, info) => { throw Error( `Importing ${q(specifier)} was not allowed by policy builtins:${q( policy.builtins, - )}`, + )}${diagnoseModulePolicy(info.errorHint)}`, ); } }; @@ -459,61 +442,3 @@ export const attenuateModuleHook = async ( originalModuleRecord, }); }; - -const padDiagnosis = text => ` (${text})`; -/** - * Provide dignostic information for a missing compartment error - * - * @param {object} args - * @param {string} args.moduleSpecifier - * @param {object} args.compartmentDescriptor - * @param {string} args.foreignModuleSpecifier - * @param {string} args.foreignCompartmentName - * @returns {string} - */ -export const diagnoseMissingCompartmentError = ({ - moduleSpecifier, - compartmentDescriptor, - foreignModuleSpecifier, - foreignCompartmentName, -}) => { - const { policy, name, scopes } = compartmentDescriptor; - - if (policy) { - if (!policy.packages) { - return padDiagnosis( - `There were no allowed packages specified in policy for ${q(name)}`, - ); - } - if (name === ATTENUATORS_COMPARTMENT) { - return padDiagnosis( - `Attenuator ${q( - moduleSpecifier, - )} was imported but there is no policy resources entry defined for it.`, - ); - } - - const scopeNames = entries(scopes) - .filter(([_name, scope]) => scope.compartment === foreignCompartmentName) - .map(([scopeName]) => scopeName); - if (scopeNames.length === 1 && scopeNames[0] === moduleSpecifier) { - return padDiagnosis( - `Package ${q( - moduleSpecifier, - )} is missing. Are you sure there is an entry in policy resources specified for it?`, - ); - } else { - return padDiagnosis( - `Package ${q(moduleSpecifier)} resolves to ${q( - foreignModuleSpecifier, - )} in ${q( - foreignCompartmentName, - )} which seems disallowed by policy. There is likely an override defined that causes another package to be imported as ${q( - moduleSpecifier, - )}.`, - ); - } - } - // Omit diagnostics when parent package had no policy - it means there was no policy. - return ''; -}; diff --git a/packages/compartment-mapper/test/fixtures-policy/node_modules/@ohmyscope/bob/package.json b/packages/compartment-mapper/test/fixtures-policy/node_modules/@ohmyscope/bob/package.json index 403578c640..cd78a27338 100644 --- a/packages/compartment-mapper/test/fixtures-policy/node_modules/@ohmyscope/bob/package.json +++ b/packages/compartment-mapper/test/fixtures-policy/node_modules/@ohmyscope/bob/package.json @@ -6,6 +6,10 @@ "dependencies": { "alice": "1.0.0" }, + "exports": { + ".": "./index.js", + "./nested-export": "./index.js" + }, "scripts": { "preinstall": "echo DO NOT INSTALL TEST FIXTURES; exit -1" } diff --git a/packages/compartment-mapper/test/fixtures-policy/node_modules/app/index.js b/packages/compartment-mapper/test/fixtures-policy/node_modules/app/index.js index 330734f100..b3d836ee01 100644 --- a/packages/compartment-mapper/test/fixtures-policy/node_modules/app/index.js +++ b/packages/compartment-mapper/test/fixtures-policy/node_modules/app/index.js @@ -1,7 +1,8 @@ import { alice, carol } from 'alice/alice.js'; import bob from './bob.cjs'; import scopedBob from '@ohmyscope/bob'; +import nestedScopedBob from '@ohmyscope/bob/nested-export'; import builtins from './builtinsWithPolicy.js'; import builtins2 from 'alice/secondaryBuitins'; -export { alice, bob, carol, builtins, builtins2, scopedBob }; +export { alice, bob, carol, builtins, builtins2, scopedBob, nestedScopedBob }; diff --git a/packages/compartment-mapper/test/fixtures-policy/node_modules/myattenuator/package.json b/packages/compartment-mapper/test/fixtures-policy/node_modules/myattenuator/package.json index 5b7c3d3b18..d3590f94da 100644 --- a/packages/compartment-mapper/test/fixtures-policy/node_modules/myattenuator/package.json +++ b/packages/compartment-mapper/test/fixtures-policy/node_modules/myattenuator/package.json @@ -4,6 +4,9 @@ "main": "./index.js", "type": "module", "dependencies": {}, + "exports": { + "./attenuate": "./index.js" + }, "scripts": { "preinstall": "echo DO NOT INSTALL TEST FIXTURES; exit -1" } diff --git a/packages/compartment-mapper/test/snapshots/test-policy.js.md b/packages/compartment-mapper/test/snapshots/test-policy.js.md index 633219e399..a9c594bb84 100644 --- a/packages/compartment-mapper/test/snapshots/test-policy.js.md +++ b/packages/compartment-mapper/test/snapshots/test-policy.js.md @@ -4,113 +4,77 @@ The actual snapshot is saved in `test-policy.js.snap`. Generated by [AVA](https://avajs.dev). -## policy - insufficient policy detected early / loadLocation +## policy - attack - browser alias - with alias hint / loadLocation > Snapshot 1 - 'Package "alice>carol" is allowed for "alice" to import but its policy is not defined. Please add a policy for "alice>carol"' + 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Importing "dan" in "eve-v1.0.0" was not allowed by packages policy {"dan":true} (info: Blocked in linking. "dan" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/".)' -## policy - insufficient policy detected early / importLocation +## policy - attack - browser alias - with alias hint / importLocation > Snapshot 1 - 'Package "alice>carol" is allowed for "alice" to import but its policy is not defined. Please add a policy for "alice>carol"' + 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Importing "dan" in "eve-v1.0.0" was not allowed by packages policy {"dan":true} (info: Blocked in linking. "dan" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/".)' -## policy - insufficient policy detected early / makeArchive / parseArchive +## policy - attack - browser alias - with alias hint / makeArchive / parseArchive > Snapshot 1 - 'Package "alice>carol" is allowed for "alice" to import but its policy is not defined. Please add a policy for "alice>carol"' + 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Importing "dan" in "eve-v1.0.0" was not allowed by packages policy {"dan":true} (info: Blocked in linking. "dan" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/".)' -## policy - insufficient policy detected early / makeArchive / parseArchive with a prefix +## policy - attack - browser alias - with alias hint / makeArchive / parseArchive with a prefix > Snapshot 1 - 'Package "alice>carol" is allowed for "alice" to import but its policy is not defined. Please add a policy for "alice>carol"' + 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Importing "dan" in "eve-v1.0.0" was not allowed by packages policy {"dan":true} (info: Blocked in linking. "dan" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/".)' -## policy - insufficient policy detected early / writeArchive / loadArchive +## policy - attack - browser alias - with alias hint / writeArchive / loadArchive > Snapshot 1 - 'Package "alice>carol" is allowed for "alice" to import but its policy is not defined. Please add a policy for "alice>carol"' + 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Importing "dan" in "eve-v1.0.0" was not allowed by packages policy {"dan":true} (info: Blocked in linking. "dan" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/".)' -## policy - insufficient policy detected early / writeArchive / importArchive +## policy - attack - browser alias - with alias hint / writeArchive / importArchive > Snapshot 1 - 'Package "alice>carol" is allowed for "alice" to import but its policy is not defined. Please add a policy for "alice>carol"' + 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Importing "dan" in "eve-v1.0.0" was not allowed by packages policy {"dan":true} (info: Blocked in linking. "dan" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/".)' -## policy - malfunction resulting in missing compartment / loadLocation +## policy - disallowed package with error hint / loadLocation > Snapshot 1 - 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/" (Package "carol" is missing. Are you sure there is an entry in policy resources specified for it?)' + 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (2 underlying failures: Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".), Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".)' -## policy - malfunction resulting in missing compartment / importLocation +## policy - disallowed package with error hint / importLocation > Snapshot 1 - 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/" (Package "carol" is missing. Are you sure there is an entry in policy resources specified for it?)' + 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (2 underlying failures: Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".), Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".)' -## policy - malfunction resulting in missing compartment / makeArchive / parseArchive +## policy - disallowed package with error hint / makeArchive / parseArchive > Snapshot 1 - 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/" (Package "carol" is missing. Are you sure there is an entry in policy resources specified for it?)' + 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (2 underlying failures: Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".), Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".)' -## policy - malfunction resulting in missing compartment / makeArchive / parseArchive with a prefix +## policy - disallowed package with error hint / makeArchive / parseArchive with a prefix > Snapshot 1 - 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/" (Package "carol" is missing. Are you sure there is an entry in policy resources specified for it?)' + 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (2 underlying failures: Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".), Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".)' -## policy - malfunction resulting in missing compartment / writeArchive / loadArchive +## policy - disallowed package with error hint / writeArchive / loadArchive > Snapshot 1 - 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/" (Package "carol" is missing. Are you sure there is an entry in policy resources specified for it?)' + 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (2 underlying failures: Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".), Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".)' -## policy - malfunction resulting in missing compartment / writeArchive / importArchive +## policy - disallowed package with error hint / writeArchive / importArchive > Snapshot 1 - 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/" (Package "carol" is missing. Are you sure there is an entry in policy resources specified for it?)' - -## policy - attack - browser alias / loadLocation - -> Snapshot 1 - - 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" (Package "dan" resolves to "." in "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" which seems disallowed by policy. There is likely an override defined that causes another package to be imported as "dan".)' - -## policy - attack - browser alias / importLocation - -> Snapshot 1 - - 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" (Package "dan" resolves to "." in "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" which seems disallowed by policy. There is likely an override defined that causes another package to be imported as "dan".)' - -## policy - attack - browser alias / makeArchive / parseArchive - -> Snapshot 1 - - 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" (Package "dan" resolves to "." in "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" which seems disallowed by policy. There is likely an override defined that causes another package to be imported as "dan".)' - -## policy - attack - browser alias / makeArchive / parseArchive with a prefix - -> Snapshot 1 - - 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" (Package "dan" resolves to "." in "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" which seems disallowed by policy. There is likely an override defined that causes another package to be imported as "dan".)' - -## policy - attack - browser alias / writeArchive / loadArchive - -> Snapshot 1 - - 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" (Package "dan" resolves to "." in "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" which seems disallowed by policy. There is likely an override defined that causes another package to be imported as "dan".)' - -## policy - attack - browser alias / writeArchive / importArchive - -> Snapshot 1 - - 'Failed to load module "./attack.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (1 underlying failures: Cannot import from missing compartment "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" (Package "dan" resolves to "." in "file://.../compartment-mapper/test/fixtures-policy/node_modules/hackity/" which seems disallowed by policy. There is likely an override defined that causes another package to be imported as "dan".)' + 'Failed to load module "./index.js" in package "file://.../compartment-mapper/test/fixtures-policy/node_modules/app/" (2 underlying failures: Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".), Importing "carol" in "alice-v1.0.0" was not allowed by packages policy {"alice>carol":false} (info: Blocked in linking. "carol" is part of the compartment map and resolves to "file://.../compartment-mapper/test/fixtures-policy/node_modules/alice/node_modules/carol/".)' ## policy - attenuator error aggregation / loadLocation diff --git a/packages/compartment-mapper/test/snapshots/test-policy.js.snap b/packages/compartment-mapper/test/snapshots/test-policy.js.snap index 2c881675d2..2848cf1ebc 100644 Binary files a/packages/compartment-mapper/test/snapshots/test-policy.js.snap and b/packages/compartment-mapper/test/snapshots/test-policy.js.snap differ diff --git a/packages/compartment-mapper/test/test-policy.js b/packages/compartment-mapper/test/test-policy.js index 3f63566711..0203b620c0 100644 --- a/packages/compartment-mapper/test/test-policy.js +++ b/packages/compartment-mapper/test/test-policy.js @@ -98,6 +98,7 @@ const defaultExpectations = { redPill: 'undefined', purplePill: 'number', }, + nestedScopedBob: { scoped: 1 }, scopedBob: { scoped: 1 }, builtins: '{"a":1,"b":2,"default":{"a":1,"b":2}}', builtins2: '{"c":3,"default":{"c":3}}', @@ -109,6 +110,16 @@ const anyExpectations = { carol: { bluePill: 'number', redPill: 'number', purplePill: 'number' }, }, }; +const powerlessCarolExpectations = { + namespace: { + ...defaultExpectations.namespace, + carol: { + bluePill: 'undefined', + redPill: 'undefined', + purplePill: 'undefined', + }, + }, +}; const makeResultAssertions = expectations => @@ -159,59 +170,7 @@ scaffold( ); scaffold( - 'policy - insufficient policy detected early', - test, - fixture, - assertTestAlwaysThrows, - 2, // expected number of assertions - { - shouldFailBeforeArchiveOperations: true, - onError: (t, { error }) => { - t.regex(error.message, /carol.*policy.*add/); - t.snapshot(sanitizePaths(error.message)); - }, - addGlobals: globals, - policy: { - resources: { - '': { - ...policy.resources[''], - }, - alice: { - ...policy.resources.alice, - }, - }, - }, - tags: new Set(['browser']), - }, -); - -scaffold( - 'policy - malfunction resulting in missing compartment', - test, - fixture, - assertTestAlwaysThrows, - 2, // expected number of assertions - { - shouldFailBeforeArchiveOperations: true, - onError: (t, { error }) => { - t.regex(error.message, /carol.*is missing.*policy/); - t.snapshot(sanitizePaths(error.message)); - }, - addGlobals: globals, - policy: { - entry: policy.entry, - resources: { - ...policy.resources, - // not something that can would normally be specified, but passes policy validation while triggering an error later. - 'alice>carol': undefined, - }, - }, - tags: new Set(['browser']), - }, -); - -scaffold( - 'policy - attack - browser alias', + 'policy - attack - browser alias - with alias hint', test, fixtureAttack, assertTestAlwaysThrows, @@ -219,7 +178,8 @@ scaffold( { shouldFailBeforeArchiveOperations: true, onError: (t, { error }) => { - t.regex(error.message, /dan.*hackity.*disallowed/); + t.regex(error.message, /dan.*resolves.*hackity/); + // see the snapshot for the error hint in the message t.snapshot(sanitizePaths(error.message)); }, addGlobals: globals, @@ -278,6 +238,19 @@ const recursiveEdit = editor => originalPolicy => { }; return recur(policyToAlter); }; +const mutationEdit = editor => originalPolicy => { + const policyToAlter = JSON.parse(JSON.stringify(originalPolicy)); + editor(policyToAlter); + return policyToAlter; +}; + +const skipCarol = mutationEdit(policyToAlter => { + policyToAlter.resources['alice>carol'] = undefined; +}); + +const disallowCarol = mutationEdit(policyToAlter => { + policyToAlter.resources.alice.packages['alice>carol'] = false; +}); const addAttenuatorForAllGlobals = recursiveEdit((key, obj) => { if (key === 'globals') { @@ -306,6 +279,44 @@ const errorAttenuatorForAllGlobals = recursiveEdit((key, obj) => { } }); +const nestedAttenuator = recursiveEdit((key, obj) => { + if (key === 'attenuate') { + obj[key] = 'myattenuator/attenuate'; + } + if (key === 'resources') { + obj[key]['myattenuator/attenuate'] = obj[key].myattenuator; + } +}); + +scaffold( + 'policy - allow skipping policy entries for powerless compartments', + test, + fixture, + makeResultAssertions(powerlessCarolExpectations), + 1, // expected number of assertions + { + addGlobals: globals, + policy: skipCarol(policy), + }, +); + +scaffold( + 'policy - disallowed package with error hint', + test, + fixture, + assertTestAlwaysThrows, + 2, // expected number of assertions + { + shouldFailBeforeArchiveOperations: true, + onError: (t, { error }) => { + t.regex(error.message, /Importing.*carol.*in.*alice.*not allowed/i); + t.snapshot(sanitizePaths(error.message)); + }, + addGlobals: globals, + policy: disallowCarol(policy), + }, +); + scaffold( 'policy - globals attenuator', test, @@ -403,3 +414,18 @@ scaffold( }, }, ); + +scaffold( + 'policy - nested export in attenuator', + test, + fixture, + combineAssertions( + makeResultAssertions(defaultExpectations), + assertNoPolicyBypassImport, + ), + 2, // expected number of assertions + { + addGlobals: globals, + policy: nestedAttenuator(policy), + }, +);