Open boneskull opened 3 weeks ago
If anyone can point me in the direction of why the tests are failing, that'd be helpful; otherwise I'll just plug at it. Plugged.
Going to extract the changes to @endo/evasive-transform
into a separate PR.
Ref: https://github.com/endojs/endo/pull/2332
cc @kriskowal
Once #2332 is merged, I can rebase this onto master
, which should eliminate the commit from this PR's history. So let's sit on it until then.
Description
This PR adds support for dynamic requires via
loadFromMap()
andlink()
(inimport-lite.js
andlink.js
, respectively).importLocation()
's signature has also been modified for support.To use this feature in either function, the following must be true:
moduleTransforms
option (in the appropriateoptions
parameter) must not be present. These are asynchronous module transforms, which cannot be used by dynamic require.ReadPowers
param must be a properReadPowers
object (not just aReadFn
) and must contain both the newreadSync
, newisAbsolute
, andfilePathFromURL
functions. anything, and we must delegate loading to the sync exit module handler.PackagePolicy
of theCompartmentDescriptor
must have adynamic: true
flag (see below)If all of the above are true, then a compartment will be allowed to dynamically require something. If that thing still cannot be found in the compartment map, the sync "fallback" exit hook (see next item) will be executed.
importHookNow
property can be provided via options, which is a synchronous exit module import hook.ReadPowers.readSync()
is necessary to read files synchronously which is necessary to load them synchronously.ReadPowers.isAbsolute()
is necessary to determine if the module specifier of a dynamic require is absolute. If it is, it could be just about anything, and must be loaded via the user-providedimportNowHook
(the sync exit module import hook).Note: It's possible to do more work here to check if the module specifier belongs to any known compartment to avoid using the fallback--this would mean storing absolute paths somewhere when traversing node modules, then, at import time, determinng if the module specifier refers to a child path of some compartment's absolute path--but IMO this is a good first pass.
moduleTransforms
, synchronous module transforms may be provided via the newsyncModuleTransforms
object. In a non-dynamic-require use-case, if present,syncModuleTransforms
are combined with themoduleTransforms
option; all sync module transforms are module transforms, but not all module transforms are sync module transforms.@endo/evasive-transform
now exportsevadeCensorSync()
in addition toevadeCensor()
. This is possible because I've swapped the async-only source-map with source-map-js, which is a fork of the former before it went async-only.source-map-js
claims comparable performance.PackagePolicy
now allows adynamic
flag. Piggybacking onoptions
was considered, but the content ofoptions
is intended to be unknown to Endo. Thus, we needed a new property.Security Considerations
Dynamically requiring an exit module (e.g., a Node.js builtin) requires a user-defined hook, which has the same security considerations as a user-defined exit module hook.
Swapping out a dependency (
source-map-js
forsource-map
) incurs risk.Scaling Considerations
n/a
Documentation Considerations
Should be announced as a user-facing feature
Testing Considerations
I've added some fixtures and tested around the conditionals I've added, but am open to any suggestions for additional coverage.
Compatibility Considerations
This increases ecosystem compatibility considerably; use of dynamic require in the ecosystem is not rare.
For example, most packages which ship a native module will be using dynamic require, because the filepath of the build artifact is dependent upon the platform and architecture.
Upgrade Considerations
Dynamic imports cannot be used without providing a
readSync()
andisAbsolute()
in thereadPowers
parameter. BothreadSync()
andisAbsolute()
are now generated bymakeReadPowersSloppy()
, which means that any consumer using this method who previously expected a dynamic require to fail will now receive a different error (presumably due to the missing policy item).To avoid this, I could create a separate function to provide a
ReadPowers
includingreadSync()
andisAbsolute()
, instead of changingmakeReadPowersSloppy
; please advise.Otherwise, everything else should be backwards-compatible, as long as
source-map-js
does as it says on the tin.Users of
@endo/evasive-transform
may note that native modules are neither downloaded/compiled (due to the switch fromsource-map
tosource-map-js
).