@endo/compartment-mapper 1.6.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -16
- package/src/archive-lite.d.ts +7 -7
- package/src/archive-lite.d.ts.map +1 -1
- package/src/archive-lite.js +78 -27
- package/src/archive.d.ts.map +1 -1
- package/src/archive.js +7 -0
- package/src/bundle-lite.d.ts +3 -3
- package/src/bundle-lite.d.ts.map +1 -1
- package/src/bundle-lite.js +19 -24
- package/src/bundle.d.ts +3 -3
- package/src/bundle.d.ts.map +1 -1
- package/src/bundle.js +19 -24
- package/src/capture-lite.d.ts +2 -2
- package/src/capture-lite.d.ts.map +1 -1
- package/src/capture-lite.js +217 -25
- package/src/compartment-map.d.ts +9 -2
- package/src/compartment-map.d.ts.map +1 -1
- package/src/compartment-map.js +737 -254
- package/src/digest.d.ts +22 -2
- package/src/digest.d.ts.map +1 -1
- package/src/digest.js +179 -56
- package/src/generic-graph.d.ts +84 -0
- package/src/generic-graph.d.ts.map +1 -0
- package/src/generic-graph.js +356 -0
- package/src/guards.d.ts +18 -0
- package/src/guards.d.ts.map +1 -0
- package/src/guards.js +109 -0
- package/src/hooks.md +124 -0
- package/src/import-archive-lite.d.ts.map +1 -1
- package/src/import-archive-lite.js +15 -11
- package/src/import-archive.d.ts +5 -19
- package/src/import-archive.d.ts.map +1 -1
- package/src/import-archive.js +7 -27
- package/src/import-hook.d.ts +4 -3
- package/src/import-hook.d.ts.map +1 -1
- package/src/import-hook.js +156 -71
- package/src/import-lite.d.ts +6 -6
- package/src/import-lite.d.ts.map +1 -1
- package/src/import-lite.js +8 -5
- package/src/import.d.ts +3 -3
- package/src/import.d.ts.map +1 -1
- package/src/import.js +16 -6
- package/src/infer-exports.d.ts.map +1 -1
- package/src/infer-exports.js +16 -6
- package/src/json.d.ts +1 -1
- package/src/json.d.ts.map +1 -1
- package/src/json.js +10 -3
- package/src/link.d.ts +4 -3
- package/src/link.d.ts.map +1 -1
- package/src/link.js +70 -58
- package/src/node-modules.d.ts +5 -3
- package/src/node-modules.d.ts.map +1 -1
- package/src/node-modules.js +648 -245
- package/src/node-powers.d.ts +6 -5
- package/src/node-powers.d.ts.map +1 -1
- package/src/node-powers.js +11 -8
- package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
- package/src/parse-cjs-shared-export-wrapper.js +3 -1
- package/src/policy-format.d.ts +22 -5
- package/src/policy-format.d.ts.map +1 -1
- package/src/policy-format.js +342 -108
- package/src/policy.d.ts +13 -28
- package/src/policy.d.ts.map +1 -1
- package/src/policy.js +161 -106
- package/src/types/canonical-name.d.ts +97 -0
- package/src/types/canonical-name.d.ts.map +1 -0
- package/src/types/canonical-name.ts +151 -0
- package/src/types/compartment-map-schema.d.ts +114 -35
- package/src/types/compartment-map-schema.d.ts.map +1 -1
- package/src/types/compartment-map-schema.ts +202 -37
- package/src/types/external.d.ts +173 -29
- package/src/types/external.d.ts.map +1 -1
- package/src/types/external.ts +221 -27
- package/src/types/generic-graph.d.ts +17 -0
- package/src/types/generic-graph.d.ts.map +1 -0
- package/src/types/generic-graph.ts +17 -0
- package/src/types/internal.d.ts +24 -42
- package/src/types/internal.d.ts.map +1 -1
- package/src/types/internal.ts +52 -50
- package/src/types/node-modules.d.ts +101 -17
- package/src/types/node-modules.d.ts.map +1 -1
- package/src/types/node-modules.ts +142 -17
- package/src/types/policy-schema.d.ts +26 -11
- package/src/types/policy-schema.d.ts.map +1 -1
- package/src/types/policy-schema.ts +29 -16
- package/src/types/policy.d.ts +6 -2
- package/src/types/policy.d.ts.map +1 -1
- package/src/types/policy.ts +7 -2
- package/src/types/powers.d.ts +38 -11
- package/src/types/powers.d.ts.map +1 -1
- package/src/types/powers.ts +50 -17
- package/src/types/typescript.d.ts +28 -0
- package/src/types/typescript.d.ts.map +1 -1
- package/src/types/typescript.ts +37 -1
package/src/policy.js
CHANGED
|
@@ -4,39 +4,46 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
// @ts-check
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* @import {
|
|
11
9
|
* Policy,
|
|
12
10
|
* PackagePolicy,
|
|
13
11
|
* AttenuationDefinition,
|
|
14
|
-
* PackageNamingKit,
|
|
15
12
|
* DeferredAttenuatorsProvider,
|
|
16
13
|
* CompartmentDescriptor,
|
|
17
14
|
* Attenuator,
|
|
18
15
|
* SomePolicy,
|
|
16
|
+
* PolicyEnforcementField,
|
|
19
17
|
* SomePackagePolicy,
|
|
18
|
+
* CompartmentDescriptorWithPolicy,
|
|
19
|
+
* ModuleConfiguration,
|
|
20
|
+
* CanonicalName,
|
|
20
21
|
* } from './types.js'
|
|
22
|
+
* @import {ThirdPartyStaticModuleInterface} from 'ses'
|
|
21
23
|
*/
|
|
22
24
|
|
|
23
25
|
import {
|
|
26
|
+
ATTENUATORS_COMPARTMENT,
|
|
27
|
+
ENTRY_COMPARTMENT,
|
|
24
28
|
getAttenuatorFromDefinition,
|
|
25
29
|
isAllowingEverything,
|
|
26
30
|
isAttenuationDefinition,
|
|
27
31
|
policyLookupHelper,
|
|
32
|
+
WILDCARD_POLICY_VALUE,
|
|
28
33
|
} from './policy-format.js';
|
|
29
34
|
|
|
30
|
-
const {
|
|
31
|
-
|
|
35
|
+
const {
|
|
36
|
+
keys,
|
|
37
|
+
create,
|
|
38
|
+
entries,
|
|
39
|
+
values,
|
|
40
|
+
assign,
|
|
41
|
+
freeze,
|
|
42
|
+
getOwnPropertyDescriptors,
|
|
43
|
+
} = Object;
|
|
32
44
|
const { ownKeys } = Reflect;
|
|
33
45
|
const q = JSON.stringify;
|
|
34
46
|
|
|
35
|
-
/**
|
|
36
|
-
* Const string to identify the internal attenuators compartment
|
|
37
|
-
*/
|
|
38
|
-
export const ATTENUATORS_COMPARTMENT = '<ATTENUATORS>';
|
|
39
|
-
|
|
40
47
|
/**
|
|
41
48
|
* Copies properties (optionally limited to a specific list) from one object to another.
|
|
42
49
|
* @template {Record<PropertyKey, any>} T
|
|
@@ -107,80 +114,55 @@ export const detectAttenuators = policy => {
|
|
|
107
114
|
return attenuatorsCache.get(policy);
|
|
108
115
|
};
|
|
109
116
|
|
|
110
|
-
/**
|
|
111
|
-
* Generates a string identifying a package for policy lookup purposes.
|
|
112
|
-
*
|
|
113
|
-
* @param {PackageNamingKit} namingKit
|
|
114
|
-
* @returns {string}
|
|
115
|
-
*/
|
|
116
|
-
const generateCanonicalName = ({ isEntry = false, name, path }) => {
|
|
117
|
-
if (isEntry) {
|
|
118
|
-
throw Error('Entry module cannot be identified with a canonicalName');
|
|
119
|
-
}
|
|
120
|
-
if (name === ATTENUATORS_COMPARTMENT) {
|
|
121
|
-
return ATTENUATORS_COMPARTMENT;
|
|
122
|
-
}
|
|
123
|
-
return path.join('>');
|
|
124
|
-
};
|
|
125
|
-
|
|
126
117
|
/**
|
|
127
118
|
* Verifies if a module identified by `namingKit` can be a dependency of a package per `packagePolicy`.
|
|
128
119
|
* `packagePolicy` is required, when policy is not set, skipping needs to be handled by the caller.
|
|
129
120
|
*
|
|
130
|
-
* @param {
|
|
121
|
+
* @param {CanonicalName} canonicalName
|
|
131
122
|
* @param {PackagePolicy} packagePolicy
|
|
132
123
|
* @returns {boolean}
|
|
133
124
|
*/
|
|
134
|
-
export const dependencyAllowedByPolicy = (
|
|
135
|
-
if (namingKit.isEntry) {
|
|
136
|
-
// dependency on entry compartment should never be allowed
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
const canonicalName = generateCanonicalName(namingKit);
|
|
125
|
+
export const dependencyAllowedByPolicy = (canonicalName, packagePolicy) => {
|
|
140
126
|
return !!policyLookupHelper(packagePolicy, 'packages', canonicalName);
|
|
141
127
|
};
|
|
142
128
|
|
|
143
129
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* @overload
|
|
147
|
-
* @param {PackageNamingKit} namingKit - a key in the policy resources spec is derived from these
|
|
148
|
-
* @param {SomePolicy} policy - user supplied policy
|
|
149
|
-
* @returns {SomePackagePolicy} packagePolicy if policy was specified
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Returns `undefined`
|
|
154
|
-
*
|
|
155
|
-
* @overload
|
|
156
|
-
* @param {PackageNamingKit} namingKit - a key in the policy resources spec is derived from these
|
|
157
|
-
* @param {SomePolicy} [policy] - user supplied policy
|
|
158
|
-
* @returns {SomePackagePolicy|undefined} packagePolicy if policy was specified
|
|
159
|
-
*/
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Returns the policy applicable to the canonicalName of the package
|
|
130
|
+
* Generates the {@link SomePackagePolicy} value to be used in
|
|
131
|
+
* {@link CompartmentDescriptor.policy}
|
|
163
132
|
*
|
|
164
|
-
* @param {
|
|
165
|
-
* @param {
|
|
133
|
+
* @param {CanonicalName | typeof ATTENUATORS_COMPARTMENT | typeof ENTRY_COMPARTMENT} label
|
|
134
|
+
* @param {object} [options] Options
|
|
135
|
+
* @param {SomePolicy} [options.policy] User-supplied policy
|
|
136
|
+
* @returns {SomePackagePolicy|undefined} Package policy from `policy` or empty
|
|
137
|
+
* object; returns `params.packagePolicy` if provided. If entry compartment,
|
|
138
|
+
* returns the `entry` property of the policy verbatim.
|
|
166
139
|
*/
|
|
167
|
-
export const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const canonicalName = generateCanonicalName(namingKit);
|
|
175
|
-
if (canonicalName === ATTENUATORS_COMPARTMENT) {
|
|
176
|
-
return { defaultAttenuator: policy.defaultAttenuator, packages: 'any' };
|
|
140
|
+
export const makePackagePolicy = (label, { policy } = {}) => {
|
|
141
|
+
/** @type {SomePackagePolicy|undefined} */
|
|
142
|
+
let packagePolicy;
|
|
143
|
+
if (!label) {
|
|
144
|
+
throw new TypeError(
|
|
145
|
+
`Invalid arguments: label must be a non-empty string; got ${q(label)}`,
|
|
146
|
+
);
|
|
177
147
|
}
|
|
178
|
-
if (policy
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
148
|
+
if (policy) {
|
|
149
|
+
if (label === ATTENUATORS_COMPARTMENT) {
|
|
150
|
+
packagePolicy = {
|
|
151
|
+
defaultAttenuator: policy.defaultAttenuator,
|
|
152
|
+
packages: WILDCARD_POLICY_VALUE,
|
|
153
|
+
};
|
|
154
|
+
} else if (label === ENTRY_COMPARTMENT) {
|
|
155
|
+
packagePolicy = policy.entry;
|
|
156
|
+
// If policy.entry is `undefined`, we return `undefined` which is
|
|
157
|
+
// equivalent to "allow everything".
|
|
158
|
+
return packagePolicy;
|
|
159
|
+
} else if (label) {
|
|
160
|
+
packagePolicy = policy.resources?.[label];
|
|
161
|
+
}
|
|
162
|
+
// An empty object for a package policy is equivalent to "allow nothing"
|
|
163
|
+
return packagePolicy ?? create(null);
|
|
183
164
|
}
|
|
165
|
+
return undefined;
|
|
184
166
|
};
|
|
185
167
|
|
|
186
168
|
/**
|
|
@@ -249,6 +231,11 @@ export const makeDeferredAttenuatorsProvider = (
|
|
|
249
231
|
throw Error(`No attenuators specified in policy`);
|
|
250
232
|
};
|
|
251
233
|
} else {
|
|
234
|
+
if (!compartmentDescriptors[ATTENUATORS_COMPARTMENT].policy) {
|
|
235
|
+
throw Error(
|
|
236
|
+
`${q(ATTENUATORS_COMPARTMENT)} is missing the required policy; this is likely a bug`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
252
239
|
defaultAttenuator =
|
|
253
240
|
compartmentDescriptors[ATTENUATORS_COMPARTMENT].policy.defaultAttenuator;
|
|
254
241
|
|
|
@@ -321,7 +308,7 @@ async function attenuateGlobalThis({
|
|
|
321
308
|
*
|
|
322
309
|
* @param {object} globalThis
|
|
323
310
|
* @param {object} globals
|
|
324
|
-
* @param {PackagePolicy} packagePolicy
|
|
311
|
+
* @param {PackagePolicy|undefined} packagePolicy
|
|
325
312
|
* @param {DeferredAttenuatorsProvider} attenuators
|
|
326
313
|
* @param {Array<Promise>} pendingJobs
|
|
327
314
|
* @param {string} name
|
|
@@ -376,18 +363,46 @@ export const attenuateGlobals = (
|
|
|
376
363
|
};
|
|
377
364
|
|
|
378
365
|
/**
|
|
379
|
-
*
|
|
366
|
+
* Generates a helpful error message for a policy enforcement failure
|
|
367
|
+
*
|
|
368
|
+
* @param {string} specifier
|
|
369
|
+
* @param {CompartmentDescriptorWithPolicy} referrerCompartmentDescriptor
|
|
370
|
+
* @param {object} options
|
|
371
|
+
* @param {string} [options.resourceCanonicalName]
|
|
372
|
+
* @param {string} [options.errorHint]
|
|
373
|
+
* @param {PolicyEnforcementField} [options.policyField]
|
|
380
374
|
* @returns {string}
|
|
381
375
|
*/
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
376
|
+
const policyEnforcementFailureMessage = (
|
|
377
|
+
specifier,
|
|
378
|
+
{ label, policy },
|
|
379
|
+
{ resourceCanonicalName, errorHint, policyField = 'packages' } = {},
|
|
380
|
+
) => {
|
|
381
|
+
let message = `Importing ${q(specifier)}`;
|
|
382
|
+
if (resourceCanonicalName) {
|
|
383
|
+
message += ` in resource ${q(resourceCanonicalName)}`;
|
|
385
384
|
}
|
|
386
|
-
|
|
385
|
+
message += ` in ${q(label)} was not allowed by`;
|
|
386
|
+
if (keys(policy[policyField] ?? {}).length > 0) {
|
|
387
|
+
message += ` ${q(policyField)} policy: ${q(policy[policyField])}`;
|
|
388
|
+
} else {
|
|
389
|
+
message += ` empty ${q(policyField)} policy`;
|
|
390
|
+
}
|
|
391
|
+
if (errorHint) {
|
|
392
|
+
message += ` (info: ${errorHint})`;
|
|
393
|
+
}
|
|
394
|
+
return message;
|
|
387
395
|
};
|
|
388
396
|
|
|
389
397
|
/**
|
|
390
|
-
*
|
|
398
|
+
* @template {ModuleConfiguration} T
|
|
399
|
+
* @param {CompartmentDescriptor<T>} compartmentDescriptor
|
|
400
|
+
* @returns {compartmentDescriptor is CompartmentDescriptorWithPolicy<T>}
|
|
401
|
+
*/
|
|
402
|
+
const hasPolicy = compartmentDescriptor => !!compartmentDescriptor.policy;
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Options for {@link enforcePolicyByModule}
|
|
391
406
|
* @typedef EnforceModulePolicyOptions
|
|
392
407
|
* @property {boolean} [exit] - Whether it is an exit module
|
|
393
408
|
* @property {string} [errorHint] - Error hint message
|
|
@@ -400,34 +415,69 @@ const diagnoseModulePolicy = errorHint => {
|
|
|
400
415
|
* @param {CompartmentDescriptor} compartmentDescriptor
|
|
401
416
|
* @param {EnforceModulePolicyOptions} [options]
|
|
402
417
|
*/
|
|
403
|
-
export const
|
|
418
|
+
export const enforcePolicyByModule = (
|
|
404
419
|
specifier,
|
|
405
420
|
compartmentDescriptor,
|
|
406
421
|
{ exit, errorHint } = {},
|
|
407
422
|
) => {
|
|
408
|
-
|
|
409
|
-
|
|
423
|
+
if (!hasPolicy(compartmentDescriptor)) {
|
|
424
|
+
// No policy, no enforcement
|
|
410
425
|
return;
|
|
411
426
|
}
|
|
427
|
+
const { policy, modules } = compartmentDescriptor;
|
|
412
428
|
|
|
413
429
|
if (!exit) {
|
|
414
430
|
if (!modules[specifier]) {
|
|
415
431
|
throw Error(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
)
|
|
419
|
-
policy.packages,
|
|
420
|
-
)}${diagnoseModulePolicy(errorHint)}`,
|
|
432
|
+
policyEnforcementFailureMessage(specifier, compartmentDescriptor, {
|
|
433
|
+
errorHint,
|
|
434
|
+
}),
|
|
421
435
|
);
|
|
422
436
|
}
|
|
437
|
+
|
|
423
438
|
return;
|
|
424
439
|
}
|
|
425
440
|
|
|
426
441
|
if (!policyLookupHelper(policy, 'builtins', specifier)) {
|
|
427
442
|
throw Error(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
443
|
+
policyEnforcementFailureMessage(specifier, compartmentDescriptor, {
|
|
444
|
+
errorHint,
|
|
445
|
+
policyField: 'builtins',
|
|
446
|
+
}),
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Throws if importing `compartmentDescriptor` from `referrerCompartmentDescriptor` is not allowed per package policy
|
|
453
|
+
*
|
|
454
|
+
* @param {CompartmentDescriptor} compartmentDescriptor
|
|
455
|
+
* @param {CompartmentDescriptor} referrerCompartmentDescriptor
|
|
456
|
+
* @param {EnforceModulePolicyOptions} [options]
|
|
457
|
+
*/
|
|
458
|
+
export const enforcePackagePolicyByCanonicalName = (
|
|
459
|
+
compartmentDescriptor,
|
|
460
|
+
referrerCompartmentDescriptor,
|
|
461
|
+
{ errorHint } = {},
|
|
462
|
+
) => {
|
|
463
|
+
if (!hasPolicy(referrerCompartmentDescriptor)) {
|
|
464
|
+
throw new Error(
|
|
465
|
+
`Cannot enforce policy via ${q(referrerCompartmentDescriptor.label)}: no package policy defined`,
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
const { policy: referrerPolicy } = referrerCompartmentDescriptor;
|
|
469
|
+
const { label: resourceCanonicalName } = compartmentDescriptor;
|
|
470
|
+
|
|
471
|
+
if (!policyLookupHelper(referrerPolicy, 'packages', resourceCanonicalName)) {
|
|
472
|
+
throw new Error(
|
|
473
|
+
policyEnforcementFailureMessage(
|
|
474
|
+
resourceCanonicalName,
|
|
475
|
+
referrerCompartmentDescriptor,
|
|
476
|
+
{
|
|
477
|
+
errorHint,
|
|
478
|
+
resourceCanonicalName,
|
|
479
|
+
},
|
|
480
|
+
),
|
|
431
481
|
);
|
|
432
482
|
}
|
|
433
483
|
};
|
|
@@ -437,8 +487,8 @@ export const enforceModulePolicy = (
|
|
|
437
487
|
* @param {object} options
|
|
438
488
|
* @param {DeferredAttenuatorsProvider} options.attenuators
|
|
439
489
|
* @param {AttenuationDefinition} options.attenuationDefinition
|
|
440
|
-
* @param {
|
|
441
|
-
* @returns {Promise<
|
|
490
|
+
* @param {ThirdPartyStaticModuleInterface} options.originalModuleRecord
|
|
491
|
+
* @returns {Promise<ThirdPartyStaticModuleInterface>}
|
|
442
492
|
*/
|
|
443
493
|
async function attenuateModule({
|
|
444
494
|
attenuators,
|
|
@@ -454,29 +504,31 @@ async function attenuateModule({
|
|
|
454
504
|
// An async attenuator maker could be introduced here to return a synchronous attenuator.
|
|
455
505
|
// For async attenuators see PR https://github.com/endojs/endo/pull/1535
|
|
456
506
|
|
|
457
|
-
return freeze(
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
507
|
+
return freeze(
|
|
508
|
+
/** @type {ThirdPartyStaticModuleInterface} */ ({
|
|
509
|
+
imports: originalModuleRecord.imports,
|
|
510
|
+
// It seems ok to declare the exports but then let the attenuator trim the values.
|
|
511
|
+
// Seems ok for attenuation to leave them undefined - accessing them is malicious behavior.
|
|
512
|
+
exports: originalModuleRecord.exports,
|
|
513
|
+
execute: (moduleExports, compartment, resolvedImports) => {
|
|
514
|
+
const ns = {};
|
|
515
|
+
originalModuleRecord.execute(ns, compartment, resolvedImports);
|
|
516
|
+
const attenuated = attenuate(ns);
|
|
517
|
+
moduleExports.default = attenuated;
|
|
518
|
+
assign(moduleExports, attenuated);
|
|
519
|
+
},
|
|
520
|
+
}),
|
|
521
|
+
);
|
|
470
522
|
}
|
|
471
523
|
|
|
472
524
|
/**
|
|
473
525
|
* Throws if importing of the specifier is not allowed by the policy
|
|
474
526
|
*
|
|
475
527
|
* @param {string} specifier - exit module name
|
|
476
|
-
* @param {
|
|
477
|
-
* @param {PackagePolicy} policy - local compartment policy
|
|
528
|
+
* @param {ThirdPartyStaticModuleInterface} originalModuleRecord - reference to the exit module
|
|
529
|
+
* @param {PackagePolicy|undefined} policy - local compartment policy
|
|
478
530
|
* @param {DeferredAttenuatorsProvider} attenuators - a key-value where attenuations can be found
|
|
479
|
-
* @returns {Promise<
|
|
531
|
+
* @returns {Promise<ThirdPartyStaticModuleInterface>} - the attenuated module
|
|
480
532
|
*/
|
|
481
533
|
export const attenuateModuleHook = async (
|
|
482
534
|
specifier,
|
|
@@ -484,8 +536,11 @@ export const attenuateModuleHook = async (
|
|
|
484
536
|
policy,
|
|
485
537
|
attenuators,
|
|
486
538
|
) => {
|
|
539
|
+
if (!policy) {
|
|
540
|
+
return originalModuleRecord;
|
|
541
|
+
}
|
|
487
542
|
const policyValue = policyLookupHelper(policy, 'builtins', specifier);
|
|
488
|
-
if (
|
|
543
|
+
if (policyValue === true) {
|
|
489
544
|
return originalModuleRecord;
|
|
490
545
|
}
|
|
491
546
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fairly exhaustive, excruciatingly pedantic _type-level_ helpers for
|
|
3
|
+
* representing and validating **Canonical Names** and npm package names.
|
|
4
|
+
*
|
|
5
|
+
* A {@link CanonicalName | Canonical Name} is a string containing one or more
|
|
6
|
+
* npm package names (scoped or unscoped) delimited by a `>` character.
|
|
7
|
+
*
|
|
8
|
+
* The following rules about npm package names are enforced:
|
|
9
|
+
*
|
|
10
|
+
* - ✅ Length > 0
|
|
11
|
+
* - ✅ Can contain hyphens
|
|
12
|
+
* - ✅ No leading `.` or `_`
|
|
13
|
+
* - ✅ No spaces
|
|
14
|
+
* - ✅ No `~)('!*` characters
|
|
15
|
+
*
|
|
16
|
+
* The following rules are not enforced:
|
|
17
|
+
*
|
|
18
|
+
* - ❌ All lowercase - Not feasible due to recursion limits & legacy package
|
|
19
|
+
* names
|
|
20
|
+
* - ❌ Not a reserved name - unmaintainable list of node builtin module names
|
|
21
|
+
* - ❌ Length ≤ 214 - Not feasible due to recursion limits & legacy package
|
|
22
|
+
* names
|
|
23
|
+
*
|
|
24
|
+
* "Legacy" package names may contain uppercase letters and be longer than 214
|
|
25
|
+
* characters.
|
|
26
|
+
*
|
|
27
|
+
* @module
|
|
28
|
+
* @see {@link https://www.npmjs.com/package/validate-npm-package-name}
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Characters that are explicitly forbidden in npm package names. These include:
|
|
32
|
+
* ` `, `~`, `)`, `(`, `'`, `!`, `*`
|
|
33
|
+
*
|
|
34
|
+
* We check each one individually because TypeScript's template literal types
|
|
35
|
+
* can detect if a string contains a specific substring.
|
|
36
|
+
*
|
|
37
|
+
* Returns `true` if the string contains a forbidden character, `false`
|
|
38
|
+
* otherwise.
|
|
39
|
+
*/
|
|
40
|
+
type ContainsForbiddenChar<S extends string> = S extends `${string} ${string}` | `${string}~${string}` | `${string})${string}` | `${string}(${string}` | `${string}'${string}` | `${string}!${string}` | `${string}*${string}` ? true : false;
|
|
41
|
+
/**
|
|
42
|
+
* Validates that a string doesn't start with `.` or `_`.
|
|
43
|
+
*
|
|
44
|
+
* Returns `true` if the string doesn't start with `.` or `_`, `false`
|
|
45
|
+
* otherwise.
|
|
46
|
+
*/
|
|
47
|
+
type HasValidStart<S extends string> = S extends `.${string}` | `_${string}` ? false : true;
|
|
48
|
+
/**
|
|
49
|
+
* Validates that a string is non-empty.
|
|
50
|
+
*
|
|
51
|
+
* Returns `true` if the string is non-empty, `false` otherwise.
|
|
52
|
+
*/
|
|
53
|
+
type IsNonEmpty<S extends string> = S extends '' ? false : true;
|
|
54
|
+
/**
|
|
55
|
+
* Combines all validation checks for a package name segment.
|
|
56
|
+
*
|
|
57
|
+
* Returns `true` if the string passes all checks, `false` otherwise.
|
|
58
|
+
*/
|
|
59
|
+
type IsValidPackageNameSegment<S extends string> = IsNonEmpty<S> extends false ? false : HasValidStart<S> extends false ? false : ContainsForbiddenChar<S> extends true ? false : true;
|
|
60
|
+
/** A scoped npm package name, like "@scope/pkg" */
|
|
61
|
+
export type ScopedPackageName<S extends string = string> = S extends `@${infer Scope}/${infer Name}` ? IsValidPackageNameSegment<Scope> extends true ? IsValidPackageNameSegment<Name> extends true ? S : never : never : never;
|
|
62
|
+
/**
|
|
63
|
+
* An unscoped npm package name.
|
|
64
|
+
*
|
|
65
|
+
* Must pass all validation checks and must not contain a `/` (which would
|
|
66
|
+
* indicate a scoped package or a subpath).
|
|
67
|
+
*
|
|
68
|
+
* Note: Package names containing uppercase letters are technically invalid per
|
|
69
|
+
* npm rules, but they exist in the wild. TypeScript cannot reliably validate
|
|
70
|
+
* case at the type level, so we don't enforce this.
|
|
71
|
+
*/
|
|
72
|
+
export type UnscopedPackageName<S extends string = string> = S extends `${string}/${string}` ? never : IsValidPackageNameSegment<S> extends true ? S : never;
|
|
73
|
+
/**
|
|
74
|
+
* A scoped or unscoped npm package name.
|
|
75
|
+
*/
|
|
76
|
+
export type NpmPackageName<S extends string = string> = S extends `@${string}/${string}` ? ScopedPackageName<S> : UnscopedPackageName<S>;
|
|
77
|
+
/**
|
|
78
|
+
* Split a string on `>`—the canonical name delimiter—into a tuple of segments.
|
|
79
|
+
*/
|
|
80
|
+
export type SplitOnDelimiter<S extends string> = S extends `${infer Head}>${infer Tail}` ? [Head, ...SplitOnDelimiter<Tail>] : [S];
|
|
81
|
+
/**
|
|
82
|
+
* Validate that every element in a tuple of strings is a valid npm package
|
|
83
|
+
* name.
|
|
84
|
+
*/
|
|
85
|
+
export type AllValidPackageNames<Parts extends readonly string[]> = Parts extends [
|
|
86
|
+
infer Head extends string,
|
|
87
|
+
...infer Tail extends readonly string[]
|
|
88
|
+
] ? NpmPackageName<Head> extends never ? never : AllValidPackageNames<Tail> : Parts;
|
|
89
|
+
/**
|
|
90
|
+
* A Canonical Name string comprised of one or more npm package names separated
|
|
91
|
+
* by `>` (e.g., `foo`, `@scope/foo>bar`, `foo>@scope/bar>baz`).
|
|
92
|
+
*
|
|
93
|
+
* When given a string literal type, invalid shapes narrow to `never`.
|
|
94
|
+
*/
|
|
95
|
+
export type CanonicalName<S extends string = string> = AllValidPackageNames<SplitOnDelimiter<S>> extends never ? never : S;
|
|
96
|
+
export {};
|
|
97
|
+
//# sourceMappingURL=canonical-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-name.d.ts","sourceRoot":"","sources":["canonical-name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;;;;GASG;AACH,KAAK,qBAAqB,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAC5C,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,GAAG,MAAM,IAAI,MAAM,EAAE,GACrB,IAAI,GACJ,KAAK,CAAC;AAEV;;;;;GAKG;AACH,KAAK,aAAa,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,GACxE,KAAK,GACL,IAAI,CAAC;AAET;;;;GAIG;AACH,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,GAAG,IAAI,CAAC;AAEhE;;;;GAIG;AACH,KAAK,yBAAyB,CAAC,CAAC,SAAS,MAAM,IAC7C,UAAU,CAAC,CAAC,CAAC,SAAS,KAAK,GACvB,KAAK,GACL,aAAa,CAAC,CAAC,CAAC,SAAS,KAAK,GAC5B,KAAK,GACL,qBAAqB,CAAC,CAAC,CAAC,SAAS,IAAI,GACnC,KAAK,GACL,IAAI,CAAC;AAMf,mDAAmD;AACnD,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IACrD,CAAC,SAAS,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,EAAE,GACrC,yBAAyB,CAAC,KAAK,CAAC,SAAS,IAAI,GAC3C,yBAAyB,CAAC,IAAI,CAAC,SAAS,IAAI,GAC1C,CAAC,GACD,KAAK,GACP,KAAK,GACP,KAAK,CAAC;AAEZ;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IACvD,CAAC,SAAS,GAAG,MAAM,IAAI,MAAM,EAAE,GAC3B,KAAK,GACL,yBAAyB,CAAC,CAAC,CAAC,SAAS,IAAI,GACvC,CAAC,GACD,KAAK,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAClD,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,EAAE,GAC5B,iBAAiB,CAAC,CAAC,CAAC,GACpB,mBAAmB,CAAC,CAAC,CAAC,CAAC;AAE7B;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,IAC3C,CAAC,SAAS,GAAG,MAAM,IAAI,IAAI,MAAM,IAAI,EAAE,GACnC,CAAC,IAAI,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,GACjC,CAAC,CAAC,CAAC,CAAC;AAEV;;;GAGG;AACH,MAAM,MAAM,oBAAoB,CAAC,KAAK,SAAS,SAAS,MAAM,EAAE,IAC9D,KAAK,SAAS;IACZ,MAAM,IAAI,SAAS,MAAM;IACzB,GAAG,MAAM,IAAI,SAAS,SAAS,MAAM,EAAE;CACxC,GACG,cAAc,CAAC,IAAI,CAAC,SAAS,KAAK,GAChC,KAAK,GACL,oBAAoB,CAAC,IAAI,CAAC,GAC5B,KAAK,CAAC;AAEZ;;;;;GAKG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IACjD,oBAAoB,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fairly exhaustive, excruciatingly pedantic _type-level_ helpers for
|
|
3
|
+
* representing and validating **Canonical Names** and npm package names.
|
|
4
|
+
*
|
|
5
|
+
* A {@link CanonicalName | Canonical Name} is a string containing one or more
|
|
6
|
+
* npm package names (scoped or unscoped) delimited by a `>` character.
|
|
7
|
+
*
|
|
8
|
+
* The following rules about npm package names are enforced:
|
|
9
|
+
*
|
|
10
|
+
* - ✅ Length > 0
|
|
11
|
+
* - ✅ Can contain hyphens
|
|
12
|
+
* - ✅ No leading `.` or `_`
|
|
13
|
+
* - ✅ No spaces
|
|
14
|
+
* - ✅ No `~)('!*` characters
|
|
15
|
+
*
|
|
16
|
+
* The following rules are not enforced:
|
|
17
|
+
*
|
|
18
|
+
* - ❌ All lowercase - Not feasible due to recursion limits & legacy package
|
|
19
|
+
* names
|
|
20
|
+
* - ❌ Not a reserved name - unmaintainable list of node builtin module names
|
|
21
|
+
* - ❌ Length ≤ 214 - Not feasible due to recursion limits & legacy package
|
|
22
|
+
* names
|
|
23
|
+
*
|
|
24
|
+
* "Legacy" package names may contain uppercase letters and be longer than 214
|
|
25
|
+
* characters.
|
|
26
|
+
*
|
|
27
|
+
* @module
|
|
28
|
+
* @see {@link https://www.npmjs.com/package/validate-npm-package-name}
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Characters that are explicitly forbidden in npm package names. These include:
|
|
33
|
+
* ` `, `~`, `)`, `(`, `'`, `!`, `*`
|
|
34
|
+
*
|
|
35
|
+
* We check each one individually because TypeScript's template literal types
|
|
36
|
+
* can detect if a string contains a specific substring.
|
|
37
|
+
*
|
|
38
|
+
* Returns `true` if the string contains a forbidden character, `false`
|
|
39
|
+
* otherwise.
|
|
40
|
+
*/
|
|
41
|
+
type ContainsForbiddenChar<S extends string> = S extends
|
|
42
|
+
| `${string} ${string}`
|
|
43
|
+
| `${string}~${string}`
|
|
44
|
+
| `${string})${string}`
|
|
45
|
+
| `${string}(${string}`
|
|
46
|
+
| `${string}'${string}`
|
|
47
|
+
| `${string}!${string}`
|
|
48
|
+
| `${string}*${string}`
|
|
49
|
+
? true
|
|
50
|
+
: false;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Validates that a string doesn't start with `.` or `_`.
|
|
54
|
+
*
|
|
55
|
+
* Returns `true` if the string doesn't start with `.` or `_`, `false`
|
|
56
|
+
* otherwise.
|
|
57
|
+
*/
|
|
58
|
+
type HasValidStart<S extends string> = S extends `.${string}` | `_${string}`
|
|
59
|
+
? false
|
|
60
|
+
: true;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Validates that a string is non-empty.
|
|
64
|
+
*
|
|
65
|
+
* Returns `true` if the string is non-empty, `false` otherwise.
|
|
66
|
+
*/
|
|
67
|
+
type IsNonEmpty<S extends string> = S extends '' ? false : true;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Combines all validation checks for a package name segment.
|
|
71
|
+
*
|
|
72
|
+
* Returns `true` if the string passes all checks, `false` otherwise.
|
|
73
|
+
*/
|
|
74
|
+
type IsValidPackageNameSegment<S extends string> =
|
|
75
|
+
IsNonEmpty<S> extends false
|
|
76
|
+
? false
|
|
77
|
+
: HasValidStart<S> extends false
|
|
78
|
+
? false
|
|
79
|
+
: ContainsForbiddenChar<S> extends true
|
|
80
|
+
? false
|
|
81
|
+
: true;
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Scoped and Unscoped Package Names
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
/** A scoped npm package name, like "@scope/pkg" */
|
|
88
|
+
export type ScopedPackageName<S extends string = string> =
|
|
89
|
+
S extends `@${infer Scope}/${infer Name}`
|
|
90
|
+
? IsValidPackageNameSegment<Scope> extends true
|
|
91
|
+
? IsValidPackageNameSegment<Name> extends true
|
|
92
|
+
? S
|
|
93
|
+
: never
|
|
94
|
+
: never
|
|
95
|
+
: never;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* An unscoped npm package name.
|
|
99
|
+
*
|
|
100
|
+
* Must pass all validation checks and must not contain a `/` (which would
|
|
101
|
+
* indicate a scoped package or a subpath).
|
|
102
|
+
*
|
|
103
|
+
* Note: Package names containing uppercase letters are technically invalid per
|
|
104
|
+
* npm rules, but they exist in the wild. TypeScript cannot reliably validate
|
|
105
|
+
* case at the type level, so we don't enforce this.
|
|
106
|
+
*/
|
|
107
|
+
export type UnscopedPackageName<S extends string = string> =
|
|
108
|
+
S extends `${string}/${string}`
|
|
109
|
+
? never
|
|
110
|
+
: IsValidPackageNameSegment<S> extends true
|
|
111
|
+
? S
|
|
112
|
+
: never;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A scoped or unscoped npm package name.
|
|
116
|
+
*/
|
|
117
|
+
export type NpmPackageName<S extends string = string> =
|
|
118
|
+
S extends `@${string}/${string}`
|
|
119
|
+
? ScopedPackageName<S>
|
|
120
|
+
: UnscopedPackageName<S>;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Split a string on `>`—the canonical name delimiter—into a tuple of segments.
|
|
124
|
+
*/
|
|
125
|
+
export type SplitOnDelimiter<S extends string> =
|
|
126
|
+
S extends `${infer Head}>${infer Tail}`
|
|
127
|
+
? [Head, ...SplitOnDelimiter<Tail>]
|
|
128
|
+
: [S];
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Validate that every element in a tuple of strings is a valid npm package
|
|
132
|
+
* name.
|
|
133
|
+
*/
|
|
134
|
+
export type AllValidPackageNames<Parts extends readonly string[]> =
|
|
135
|
+
Parts extends [
|
|
136
|
+
infer Head extends string,
|
|
137
|
+
...infer Tail extends readonly string[],
|
|
138
|
+
]
|
|
139
|
+
? NpmPackageName<Head> extends never
|
|
140
|
+
? never
|
|
141
|
+
: AllValidPackageNames<Tail>
|
|
142
|
+
: Parts;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* A Canonical Name string comprised of one or more npm package names separated
|
|
146
|
+
* by `>` (e.g., `foo`, `@scope/foo>bar`, `foo>@scope/bar>baz`).
|
|
147
|
+
*
|
|
148
|
+
* When given a string literal type, invalid shapes narrow to `never`.
|
|
149
|
+
*/
|
|
150
|
+
export type CanonicalName<S extends string = string> =
|
|
151
|
+
AllValidPackageNames<SplitOnDelimiter<S>> extends never ? never : S;
|