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
harden
enables 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 GitHub Comments
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.