Skip to content
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

feat(ses): Add minimal Compartment to SES-lite #443

Merged
merged 15 commits into from
Sep 7, 2020

Conversation

kriskowal
Copy link
Member

The ses/lockdown layer, and the Rollup bundles that we generate from it, will now contain a Compartment with evaluate, but without a module system. This is sufficient for containment, and doesn’t entrain a full JavaScript parser framework.

packages/ses/ses.js Show resolved Hide resolved
packages/ses/src/compartment-shim.js Show resolved Hide resolved
return performEval(source, globalObject, globalLexicals, {
let localObject = globalLexicals;
if (localLexicals !== undefined) {
localObject = create(null, getOwnPropertyDescriptors(globalLexicals));
Copy link
Contributor

Choose a reason for hiding this comment

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

Can global lexicals be mutable? Are mutable global lexicals represented as mutable data properties, or as accessor properties whose getter and setter access captured state? If the latter, this seems to be fine. However, if they are represented as data properties, this will cause data properties with independent mutability, causing updates to be lost to the compartment-wide shared global lexical contour.

Copy link
Member Author

Choose a reason for hiding this comment

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

globalLexicals must be mutable to effect live bindings, when used to carry setters into module scope.

packages/ses/src/compartment-shim.js Outdated Show resolved Hide resolved
packages/ses/src/lockdown-shim.js Show resolved Hide resolved
packages/ses/src/global-object.js Outdated Show resolved Hide resolved
packages/ses/src/module-shim.js Show resolved Hide resolved
packages/ses/src/module-shim.js Show resolved Hide resolved
packages/ses/src/inert.js Outdated Show resolved Hide resolved
Copy link
Contributor

@erights erights left a comment

Choose a reason for hiding this comment

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

Separately, I want to express a hip hip hoorah! for this reorganization. Each level is extraordinarily easier to understand, now that it has been disentangled from the other level. Even if we didn't need to do it for packaging reasons, it is something we should have done anyway for clarity.

Could we even split the levels into two packages, so that it is clear that there are no dependencies from the eval-only level to the module level?

IIUC our immediate plans for XS: Because they do not yet support dynamic module loading, we would use their Compartment system almost exactly as an implementation of our eval-only level of abstraction. We would then build a module-supporting Compartment on top of it exactly as the module level here builds on our own eval-only Compartment. Could the module layer code in fact be the same --- be independent of how the eval-only Compartment level is provided?

There's the gotcha with that we already know: The special evaluate option we're using is not supported by Moddable and should never be. We should never ask them for that or propose that anyone else implement it. That means the only ES module code we cannot run through our translator and then on the Moddable compartments is code that exports live bindings. What's the best way to feature detect for whether this evaluate option is supported? As long as we can detect and reliably signal an error, I don't think anyone running on XS will ever care about the absence of live bindings. And this restriction will disappear anyway once XS directly implements the full Compartment spec.

packages/ses/src/module-shim.js Outdated Show resolved Hide resolved
packages/ses/src/module-shim.js Outdated Show resolved Hide resolved
packages/ses/src/compartment-shim.js Show resolved Hide resolved
Copy link
Contributor

@erights erights left a comment

Choose a reason for hiding this comment

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

An interesting suggestion, and a correction to a previous review comment.

packages/ses/src/module-shim.js Outdated Show resolved Hide resolved
@erights
Copy link
Contributor

erights commented Aug 30, 2020

NOT URGENT: There is a further separation that this PR sets up, that will eventually be relevant to us, that I would like to understand. Most of the module layer code here is not concerned with translating module source text to evaluable strings. As long as these end up as static module records that do the right thing, most of the module layer code is happy. So if we were going to do offline untrusted translation, we'd still unburden ourselves from the parser, but we could use the rest of this module layer to do least authority linkage as driven by endo/lavamoat/tofu declarative policy config files.

Building on the separation done by this PR, what would need to change to do that further separation? It would seem only another module kind handler that knows how to turn allegedly-pre-translated modules into static module records. Aside from live bindings, this would seem a smaller step than adding CJS modules. Anything else?

@kriskowal
Copy link
Member Author

Building on the separation done by this PR, what would need to change to do that further separation? It would seem only another module kind handler that knows how to turn allegedly-pre-translated modules into static module records. Aside from live bindings, this would seem a smaller step than adding CJS modules. Anything else?

Live bindings would be the only hard thing. CommonJS module support using the third-party static module record interface should continue to work fine.

@kriskowal kriskowal linked an issue Sep 3, 2020 that may be closed by this pull request
@kriskowal kriskowal force-pushed the kris/ses-lite-compartment branch 2 times, most recently from 0fa6a63 to cbcd102 Compare September 3, 2020 21:13
@kriskowal kriskowal changed the base branch from kris/quick-fix to master September 3, 2020 21:14
Copy link
Contributor

@erights erights left a comment

Choose a reason for hiding this comment

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

LGTM.

Looking forward to seeing this land!

packages/ses/src/module-shim.js Outdated Show resolved Hide resolved
Comment on lines +32 to +33
"qt": "tap --no-esm --no-coverage --reporter spec 'test/**/*.test.js'",
"test": "yarn build && yarn qt",
Copy link
Contributor

Choose a reason for hiding this comment

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

This is nice. I've already found it useful. We should propagate this pattern everywhere. Though not in this PR ;)

@kriskowal
Copy link
Member Author

NOT URGENT: There is a further separation that this PR sets up, that will eventually be relevant to us, that I would like to understand. Most of the module layer code here is not concerned with translating module source text to evaluable strings. As long as these end up as static module records that do the right thing, most of the module layer code is happy. So if we were going to do offline untrusted translation, we'd still unburden ourselves from the parser, but we could use the rest of this module layer to do least authority linkage as driven by endo/lavamoat/tofu declarative policy config files.

Building on the separation done by this PR, what would need to change to do that further separation? It would seem only another module kind handler that knows how to turn allegedly-pre-translated modules into static module records. Aside from live bindings, this would seem a smaller step than adding CJS modules. Anything else?

It might be sufficient to separate the StaticModuleRecord into a subsequent layer. That’s the bit of the module system that entrains the parser. There is a coupling there because the module system treats these ESM records as special. We would need to make the relationship non-special, perhaps providing an execute method akin to third-party modules, which should be sufficient given our willingness to drop live-binding support for our own purposes.

How to make that coupling optional is a hard problem. It would be easier to provide a public-but-nonstandard static-modul-record interface that supports live-bindings.

@kriskowal kriskowal merged commit 3d1dfd2 into master Sep 7, 2020
@kriskowal kriskowal deleted the kris/ses-lite-compartment branch September 7, 2020 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Shipping SES without Babel
2 participants