add "SES-adapter" package?
See original GitHub issue@michaelfig and I spent the morning talking about how libraries and applications could/should get access to SES features like harden, Compartment, and the closely-coupled HandledPromise in diverse SES/non-SES environments. We have a proposal for a new package, provisionally named ses-adapter, and plans for how it should be used.
The only API of this package is:
import { harden, Compartment, HandledPromise } from 'ses-adapter';
Internally, this would use a global of the same name if one already exists, else it would use a shimmed version. It would also have a way to coordinate with separately-bundled copies of the package, to avoid identity discontinuities.
The goal is to support library and application authors who want to use these features (hardening, Compartment isolation/evaluation, and handled promises), independently of the final application’s runtime environment. The operational library code that these authors write should be able to say import { harden } from 'ses-adapter' and then use harden(obj) in all the appropriate places. They should not have to load/install SES to acquire harden, nor should their desire to use harden impose a burden on downstream libraries or applications which import their harden-using code.
The decision about using SES is up to the final application. We imagine three environments in which this might run:
- non-SES: not ocap-secure, but
hardenenables good programming discipline, and the others are probably helpful too - yes-SES: configured by the application startup code, ocap secure
- SwingSet
Applications that wish to run under SES should create a local module named install-SES or similar. This module should import and execute any vetted shims (which need to modify globals), after which it should import { lockdown } from 'SES' and call lockdown():
// install-SES.js
import { installShim1 } from 'shim1';
import { installShim2 } from 'shim2';
import { lockdown } from 'SES';
installShim1();
installShim2();
lockdown();
The application’s main.js should then import from './install-SES' on its very first line. install-SES is imported solely for its side effects, which are to modify the globals and then freeze/tame them. All subsequent imports will see the SES “Start Compartment” which still has the usual platform authorities (fs, document, etc) as well as a mutable global object. As long as those modules don’t attempt to modify the primordials in-place, they should not be significantly impacted by running under SES.
The idea of importing install-SES before anything else is to avoid relying upon the behavior of everything else: those second-run modules cannot modify the primordials. However, since the start compartment’s global is still mutable, they could still replace the primordials with something surprising. Proper isolation between dependent libraries is a job for the upcoming module loader framework. But, we might consider recommending install-SES.js also do a harden(global)… I’m not sure. Proper isolation is easier to think about when you create a new Compartment for the untrusted code (and requires running under SES in any case).
When a library using harden/etc wishes to test outside of SES, they don’t have to do anything special: ses-adapter will load a shimmed/insecure version of the functions they want to use. If they wish to test inside SES as well, the library should declare a devDependency upon SES, and the individual test-foo.js files that want to use SES (which are like mini-applications) should import a similar ../install-SES module before doing anything else. In particular, they must import from '../install-SES' before they import the code under test, so that it gets the real SES exports rather than the insecure shimmed versions.
The agoric-sdk bundle-source tool will declare SES-adapter as an “external” (an exit from the module graph), and thus will not incorporate SES-adapter or its dependencies into the bundled source object. The SwingSet require endowment will honor a require('SES-adapter') by providing a stub that reflects the SwingSet’s host’s SES properties. This provides a secure implementation of harden/etc for code loaded into a SwingSet environment (specifically code that gets used in a Vat, or in a contract).
harden, Compartment, and HandledPromise are all on the standards track. As JS engines start implementing them natively, libraries that use SES-adapter (in applications which did not somehow install-SES) will automatically switch over to the native+secure versions.
Applications which call lockdown will probably get native versions too, since I think our plan is for lockdown() to look for existing globals and use them if available.
When running under XS, SES-adapter will prefer the native versions. We might avoid importing SES and calling lockdown() there, or we might continue to import it and rely upon lockdown() noticing the existing Compartment/etc and doing nothing.
At some point in the future, both lockdown and SES-adapter will effectively be no-ops, since all runtime environments will have these features and/or be SES environments. At that point, library code might choose to delete the import { harden } from 'SES-adapter' lines from their files, but they will not have to change anything else.
I don’t yet know what application code will do in this future utopia: their continued use of install-SES depends upon what the least-authority module loader looks like. We’ve talked about running programs under a SES-aware loader (perhaps ses main.js or ses app-manifest.json instead of node main.js). In that case, the construction/configuration of the SES environment would be the responsibility of the loader/app-launcher, rather than the first few lines of the application being loaded.
Issue Analytics
- State:
- Created 4 years ago
- Comments:12 (12 by maintainers)

Top Related StackOverflow Question
published as https://www.npmjs.com/package/ses-adapter/v/0.0.1
This looks very comfortable to me. I think both the Shim and the longer term target would be quite useable, and it sounds like a fine transition plan. I like having a single evaluation pattern that works for multiple contexts.