-
Notifications
You must be signed in to change notification settings - Fork 72
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
Using XS native Compartments for Agoric Vat Workers #400
Comments
I wonder if that's quite true. I'm not sure what "Node.js-style packaging" means exactly. XS can import modules by reading .js from the filesystem at runtime. (I was in the past under the impression that it cannot, and I spread this misinformation around a bit, but I was wrong. IOU pointers to details) I have incomplete understanding of |
Thanks @dckc. Importing off the filesystem might be useful in some special cases. It would be useful to see an example of, say, writing a file to disk then importing it. |
here's hoping I find time to cook up such an example. (I'm pretty sure I've done it before... maybe I still have it around...) Meanwhile, for reference: fxLoadScript and |
found it: https://gist.github.com/dckc/cbbd3e8469723b342cc90799ace7a287 |
The stopgap I described here has been working for some time now. Moddable has also recently made incredible strides toward making the longshot work too. I’m revising the title and description so that this issue continues to track native compartment support. #848 is related. |
Refs: #400 and #2294 ## Description In this change, we carve and export `-lite.js` and `-parsers.js` out of `import.js`, `archive.js`, and `import-archive.js`, as well revealing `mapNodeModules` through `@endo/compartment-mapper/node-modules.js` revealing hidden flexibility already present in the Compartment Mapper. This allows the Compartment Mapper to mix and match “language behaviors” with different workflows (e.g., using `import-parsers.js` with `archive-lite.js` instead of `archive-parsers.js` generates archives with original sources instead of precompiled sources.) We also decouple the process of discovering the physical compartments such that `node-modules.js` can be substituted for alternate compartment exploration algorithms, e.g., combining a custom lockfile and package cache from a specific package management solution. ### Security Considerations Does not cross security considerations. ### Scaling Considerations Exporting more narrowly scoped modules allows consumers to be avoid entraining Babel in a greater variety of scenarios. ### Documentation Considerations Evolution of the reference documentation should suffice, though another pass at README.md to dig into these more surgical and composable APIs may be worthwhile. ### Testing Considerations The existing scenarios are extensive and fully cover the behaviors that we’ve factored out. I expect #2294 tests to cover the new scenarios. ### Compatibility Considerations This change takes great care to preserve the existing behavior of the composite `import.js`, `archive.js`, and `import-archive.js` interfaces, only revealing existing behaviors that were previously internal, allowing more expressible scenarios. ### Upgrade Considerations This change will not affect upgrade and paves a migration path forward for preserving backward-compatibility for `bundleSource` and `importBundle` as we draw closer to supporting XS native compartments.
Closes: #2295 Refs: #400, #2252 ## Description This change adds a mode to the `bundle-source` command with the initial flag `--no-transforms` that generates “endo zip base64” style bundles without applying the module-to-program transform and SES shim censorship evasion transforms, such that the original files on disk appear in the zip file. This is a preparatory step, necessary for building test artifacts, in advance of full support for this bundle style. ### Security Considerations `bundle-source` is part of the Endo and Agoric toolkit and it, or its surrogate, participate in the toolchain for generating content that can be confined by Hardened JavaScript, but is not trusted by Hardened JavaScript at runtime. It does however _currently_ run with all the authority of the developer in their development environment and its integrity must be carefully guarded. ### Scaling Considerations No improvements expected at this time, but in pursuit of #400, it may be possible to move the heavy and performance sensitive JavaScript transform components from `bundle-source` to `import-bundle` and only suffer the performance cost of these transforms on Node.js, where those costs are more readily born by some runtimes. Precompiled bundles may continue to be the preferred medium for deployment to the web, for example. ### Documentation Considerations We will need to advertise the `--no-transforms` flag eventually, since there will be a period where it is advisable if not necessary to generate contracts and caplets targeting the XS runtime. ### Testing Considerations I have included a test that verifies the API behavior and manually run the following to verify behavior for the CLI: ```sh rm -rf bundles yarn bundle-source --no-transforms --cache-json bundles demo/circular/a.js circular-a rm -rf circular-a mkdir -p circular-a jq -r .endoZipBase64 bundles/bundle-circular-a.json | base64 -d > circular-a/circular-a.zip (cd circular-a; unzip circular-a.zip) jq . circular-a/compartment-map.json # verifying the final module entires have parser: 'mjs' ``` ### Compatibility Considerations This flag is opt-in and breaks no prior behaviors. This introduces a new entry to the build cache meta-data and may cause some bundles to be regenerated one extra time after upgrading. ### Upgrade Considerations This should not impact upgrade, though it participates in the greater #400 story which will require xsnap upgrades to come to bear.
Refs: #400 #2251 ## Description Pursuant to arriving at parity with XS, this change internally reörients the SES module loader around the concept of a “module descriptor”. This creates some clarity and removes some existing duplication of work for “alias” module descriptors, and prepares the material for a richer module descriptor schema to match those implemented by XS. ### Security Considerations No changes. ### Scaling Considerations No changes. ### Documentation Considerations No changes. ### Testing Considerations No changes. ### Compatibility Considerations No changes. ### Upgrade Considerations No changes.
Refs: #400 #2251 ## Description This change introduces support for XS-compatible module descriptors with the discriminating properties `source` and `namespace`, including support for loading a module from the parent compartment. ### Security Considerations None. ### Scaling Considerations None. ### Documentation Considerations This change is additive. ### Testing Considerations Covered. ### Compatibility Considerations Some usage patterns are now deprecated but continue to be supported without complaint. ### Upgrade Considerations None.
Refs: #400 ## Description XS does not support `compartment.module`. Rather than emulate it, I chose bring SES into closer alignment with XS module descriptors and use those instead. The Compartment Mapper is the only place we use this feature at the moment. ### Security Considerations None. ### Scaling Considerations None. ### Documentation Considerations None. ### Testing Considerations The existing Compartment Mapper tests exercise this path rigorously. ### Compatibility Considerations The new version of Compartment Mapper will not work with an older version of SES. Lerna will make sure the constraint gets updated when we release. ### Upgrade Considerations None.
Refs: #400, Agoric/agoric-sdk#9686 ## Description Endo’s zip bundle format and Rollup both support importing JSON modules. This change adds JSON module support to Endo’s script bundle format. We need this to have Rollup parity for Agoric Core Eval scripts and also to unblock test262 for XS native compartment parity tests. ### Security Considerations Obviates Rollup, increases legibility of script bundles. ### Scaling Considerations None. ### Documentation Considerations None. JSON module support is assumed. No one will notice unless it doesn’t work. ### Testing Considerations This change adds a JSON module to the existing bundle test fixture. This also verifies parity with the Zip bundle format. ### Compatibility Considerations This make Endo more compatible with Rollup, but Endo continues to not support `import / with { type: "json" }`, which would be necessary for parity with Node.js proper and newer bundlers. ### Upgrade Considerations None.
Refs: #400 ## Description We’ve discovered that, to create an Endo script bundle that captures our `ModuleSource` constructor shim, it will need to entrain Babel. With the default build conditions, Babel entrains a `debug` package, which entrains `node:tty`. So, it is necessary to add the `"browser"` condition, which instead entrains a package with a JSON module (#2352). This change threads arbitrary conditions (build tags) through `bundle-source` to conveniently generate Endo script bundles with different tags like `browser` or `xs`. ### Security Considerations None. ### Scaling Considerations None. ### Documentation Considerations The new flags are advertised in the command’s usage display. ### Testing Considerations - [ ] test scaffold and manual testing instructions ### Compatibility Considerations None. ### Upgrade Considerations None.
Refs: #400 ## Description To reduce mismatched behavior between SES and XS, this change adds an option (to be removed at the next major version) that changes the compartment import method such that it returns a promise for an exports namespace instead of a promise for a box containing the imports namespace. This opts-in to the same thenable behavior as dynamic import in the language. ### Security Considerations With this option, we must be weary of thenable modules, as we must be for thenable modules across the rest of the JavaScript ecosystem. ### Scaling Considerations None. ### Documentation Considerations This option will necessarily appear in all portable code examples on hardenedjs.org once it is available. ### Testing Considerations Tests have been adjusted to take advantage of the new option, except legacy tests which remain to test the behavior without the option enabled. ### Compatibility Considerations This is a backward compatible change. Namespace boxes are hereafter deprecated and we hope to remove this option on the next major release, making the new behavior mandatory or at least opt-out. ### Upgrade Considerations None.
Refs: #400 ## Description To converge with XS in the patterns accepted by SES for Compartment construction, this change introduces a `__options__` property to the first argument of the Compartment constructor that indicates that the constructor accepts a single options bag argument and does not receive separate endowments and module map arguments. ### Security Considerations None. ### Scaling Considerations None. ### Documentation Considerations This change includes updates for NEWS (with migration instructions and a notice of intent to break deprecated usage patterns) and README (to encourage recommended usage). We intend to follow up with an update to hardenedjs.org upon release. ### Testing Considerations All tests have been updated to use the new constructor pattern except those already marked as legacy, which remain to exercise support for the deprecated usage patterns. ### Compatibility Considerations There is a remote possibility that existing code uses `__options__` as the name of an endowment and will now be misinterpreted. We do not imagine any guest programs are in a position to influence their host compartment’s construction. ### Upgrade Considerations None.
[update 2024-04-29]
Agoric currently bundles contracts in a pre-compiled JSON envelope to avoid the runtime cost of loading and using Babel to transform ESM to a form that SES can digest. We could instead rely on the native XS
ModuleSource
behavior on XS if the nativeCompartment
were sufficiently similar to the SES emulation ofCompartment
.Compartment
andModuleSource
instead of Babel. In the current world,bundleSource
applies the module-to-program transform unconditionally. In the new world,bundleSource
would capture original sources, butimportBundle
will use the Babel transform on Node.js and nativeModuleSource
on XS."imports"
directive in@endo/import-bundle
such that it only entrains@endo/evasive-transforms
on Node.js and not with the"xs"
tag.Enables #2116, #2117
It follows that we will be able to close when we have adequate parity with native XS for virtual module source on XS #1066
[update 2023-12-19]
Agoric currently bundles contracts in a pre-compiled JSON envelope to avoid the runtime cost of loading and using Babel to transform ESM to a form that SES can digest. We could instead rely on the native XS
ModuleSource
behavior on XS if the nativeCompartment
were sufficiently similar to the SES emulation ofCompartment
.@endo/static-module-record
on Node.js but rely on the nativeModuleSource
constructor when running on XS. Differentiate these cases with a tag likeendo
in thepackage.json
"exports"
or"imports"
property so that the SwingSet worker bootstrap for XS doesn’t entrain Babel when we generate that bundle.[update 2020-01-21]
Agoric currently runs contracts in an XSnap worker using the SES shim for dynamic module-loading Compartment support. This works for now, and Moddable has made considerable progress toward making their native Compartment implementation a better alternative. To run a contract in a native Compartment, we would not need to use the bundleSource “censorship evasive transforms” that mitigate the weaknesses in the
ses
(hardened JavaScript shim) emulation of ESM (ECMAScript modules).This issue stands open to track native compartment support. At time of writing, the ball is in our court. We need:
In the original description below, we are running the stopgap in production, and the longshot is not such a long shot anymore.
There are two avenues to running contract archives on Moddable’s XS. Both involve creating an XS binary for hosting dynamically-loaded modules from an archive (presumed Zip), including both CommonJS and ECMAScript modules. In both scenarios, this binary would implement Endo, ideally reüsing as much of its internals without modification as possible, so we have parity between running on Node.js with SES-Shim and running on XS without.
The Longshot is the most desirable long-term outcome. XS should in principle not need any part of the SES shim, since it’s a SES-only runtime. Also, our friends at Moddable are committed to implementing the Compartment specification, though the specification remains negotiable. To pursue this option, we may need to engage more closely with the XS project.
The Stopgap is possible (modulo risks) without major changes to XS, and largely reusing work we have already done on SES-Shim. We would need to implement the dynamic module loading feature as an
xs-compartment-shim
. This would reüse thetransform-module
Babel shim. We would need to factor some code out of the SES compartment-shim, presumably into themake-importer
project Michael sketched.The work break-down for the Longshot includes:
StaticModuleRecord
constructor, so ECMAScript modules can be parsed and analyzed.importHook
.importHook
would need to be able to return a static module record provided by the aboveStaticModuleRecord
and the Compartment and StaticModuleRecord can communicate behind the scenes with internal slots or weak maps to hide implementation details.importHook
ould also support CommonJS, JSON, and potentially other modules by permitting theimportHook
to return implementations of static module record with the currently unspecified{ imports, execute(exports, compartment, resolvedImports) }
interface. This is possible as of feat(endo): Add CommonJS and JSON module support #397 on Node.js and would be necessary for parity, though we could constrain the transitive dependencies of contracts to be limited to the currently rare ESM format.resolveHook
. There is some wiggle room here since we actually just need everyCompartment
to use our particularresolveHook
that works like Node.js's resolver, but where every full specifier is either package-local (starting with . or ..) or from another package. With this hook,resolve('./aux.js', './main.js')
is./aux.js
, whereasresolve('../foo.js', './main.js')
is an error since it escapes the package root. Folks who have implemented resolution for Node.js do not use this math since Node.js effectively executes within a single compartment where module specifiers are fully qualified and resolution may involve IO. This would be antithetical to compartmentalizing third-party packages like LavaMoat.import
(which returns a promise) but not theimportNow
. This is likely a case where the specification and the SES shim need to change, since distinguishingimportNow
will no longer beuseful when the Compartment specification meets the new top-level-await.The work break-down for Stopgap includes:
The text was updated successfully, but these errors were encountered: