-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(compartment-mapper/node): support anonymous entrypoints #2664
base: master
Are you sure you want to change the base?
Conversation
An "anonymous" entrypoint is one where the closest `package.json` does not contain a `name` field. It is not unusual for CJS packages to create a subdirectory containing `package.json` like this: ```json {"type": "module"} ``` The effect is that any `.js` file in this subdir will be treated as an ECMAScript module by Node.js. A problem arises when a module in this subdir is provided as an entrypoint to `mapNodeModules()`. In this case, the "root" package descriptor _has no name_. Ultimately, the resulting shape of the `CompartmentMapDescriptor` fails `assertCompartmentMap()`, presumably due to an `undefined` value (or `"undefined"` string!) where one was not expected. To avoid the failure, we can assign a string value to the root package descriptor's `name` field. This is very much a corner case and was discovered by running arbitrary packages through `mapNodeModules()` (specifically, `@babel/runtime`). - Also added a test for this - Also added a broad/shallow test case for `mapNodeModules()` since one did not exist * * * Questions at time of commit: - Does the name need to be more unique to avoid collisions with other packages in the dependency tree? - Severe enough to pull in `node:crypto`? - Can there ever be more than one "anonymous" package?
c38c16d
to
647c2f7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A negative side-effect of this change is that modules under the anonymous package.json would not be able to find any of their dependencies. In Node.js, this is not a problem because Node.js does not consult package.json, but for the Compartment Mapper, this would be fatal.
I would like to consider a similarly surgical change that would probably have the same intended effect: We can alter the search() function to skip any package.json
that lacks a name
property, such that it would fall through to the true package root. These {"type": "module"}
package.json
s just alter the interpretation of .js
extensions in a subtree of the containing package.
We might need to do further work to ensure that the .js
extension for the inner and outer “packages” get interpreted consistently for their respective subtrees. I think that would entail a moduleTypeHook for importHook that closes over the same package descriptor memo as mapNodeModules, allowing that memo to grow in response to importHook as needed.
I could also imagine solving this problem with an alternate implementation of |
If Node.js didn't consult |
But anyhow, the more correct solution is what you suggested: "inherit" from the parent
This is Lavamoat, so we wish to (reasonably) maximize out-of-box compat with Node.js. @naugtur This involves some of the stuff we were talking about today. I thought you might have opinions on the API. |
An "anonymous" entrypoint is one where the closest
package.json
does not contain aname
field. It is not unusual for CJS packages to create a subdirectory containingpackage.json
like this:The effect is that any
.js
file in this subdir will be treated as an ECMAScript module by Node.js.A problem arises when a module in this subdir is provided as an entrypoint to
mapNodeModules()
.Note
Why the hell would anyone do this? I just wanted to see if I could generate policy for all of
@babel/runtime
's exports.In this case, the "root" package descriptor has no name. Ultimately, the resulting shape of the
CompartmentMapDescriptor
failsassertCompartmentMap()
, presumably due to anundefined
value (or"undefined"
string!) where one was not expected.To avoid the failure, we can assign a string value to the root package descriptor's
name
field.This is very much a corner case and was discovered by running arbitrary packages through
mapNodeModules()
(specifically,@babel/runtime
).mapNodeModules()
since one did not existQuestions at time of commit:
node:crypto
?