Skip to content

Conversation

@boneskull
Copy link
Member

Description

This changes the logic in mapNodeModules() so that when it reads the package.json of the entrypoint, it checks for type === 'module'. If this is set, then import is added to the conditions. If it is not set, then require is added to the conditions. The conditions always contain default; this has not changed.

This prevents CJS modules from referencing modules in the CompartmentMapDescriptor which they would not otherwise load (and in fact cannot load for some value of "cannot").

Security Considerations

n/a

Scaling Considerations

n/a

Documentation Considerations

This may impact users, but it is a bug fix.

Testing Considerations

The tests verify this is working for both module systems.

Compatibility Considerations

n/a

Upgrade Considerations

Updated NEWS.md.

@boneskull boneskull requested a review from naugtur November 3, 2025 21:31
@boneskull boneskull added the bug Something isn't working label Nov 3, 2025
@boneskull boneskull self-assigned this Nov 3, 2025
…from CJS entrypoints

This changes the logic in mapNodeModules() so that when it reads the `package.json` of the entrypoint, it checks for `type === 'module'`. If this is set, then `import` is added to the `conditions`. If it is not set, then `require` is added to the conditions. The conditions always contain `default`; this has not changed.

This prevents CJS modules from referencing modules in the `CompartmentMapDescriptor` which they would not otherwise load (and in fact _cannot_ load for some value of "_cannot_").
@boneskull boneskull force-pushed the boneskull/conditional-conditions branch from c972ee6 to d99f0a4 Compare November 3, 2025 21:34
@@ -0,0 +1,2 @@
module.exports = { value: 'dual-esm' };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you mean dual-cjs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk, doesn't really matter

Copy link
Member

@naugtur naugtur Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created an exploratory e2e test to see how the nested trees of cjs vs esm would work

#3006

there's a few more permutations to try.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comparing against node.js is one thgin, but do we also want to compare against some bundlers and tsc?

@kriskowal
Copy link
Member

For the sake of capturing notes,

I think this is interesting. Node.js, unlike Endo-as-writ, supports two concurrent module systems. The legacy, bottom tier module system is always synchronous and only hosts CJS. The top tier, like Endo, hosts both CJS and ESM. The ramp up is dynamic import, with a fully qualified module specifier (module- and package-relative imports won’t work). The ramp down is modules.createRequire, which contextualizes module- and package relative imports to a fully qualified module specifier (import.meta.url). Endo isn’t in a great position for implementing either of these ramps because portability demands neutrality about fully qualified URLs, but we’ve discussed ways to bolt these features on the side for LavaMoat.

I believe the top tier always has import and the bottom tier always has require conditions. We could conceivably create parallel compartments for the tiers, but I don’t like what that implies about eval twin hazards. I’d much go where the puck is headed: ESM and CJS coëxisting on the top tier. I could also see tacking on a legacy mode where there’s only the bottom tier (require and CJS only), and that could be another mapNodeModules variant, or we could use an 'auto-entry' mode to sense which tier to use based on the module type of the entry, like Node.js.

@boneskull
Copy link
Member Author

Yeah, based on talking it over with @kriskowal and his comments here, I am not really convinced this is "correct", nor am I convinced it actually "fixes" anything. The current behavior seems kind of weird to me, so I think Something should be done. This is likely not the Something that should be done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lavamoat

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants