Skip to content

Commit

Permalink
Minimum viable module source (#36)
Browse files Browse the repository at this point in the history
Co-authored-by: Jordan Harband <ljharb@gmail.com>
Co-authored-by: guybedford <guybedford@users.noreply.github.com>
Co-authored-by: Nicolò Ribaudo <nribaudo@igalia.com>
Co-authored-by: Luca Casonato <hello@lcas.dev>
Co-authored-by: Kris Kowal <kris@cixar.com>
Co-authored-by: lucacasonato <hello@lcas.dev>
  • Loading branch information
6 people authored May 9, 2023
1 parent 4adc143 commit 4defdd7
Show file tree
Hide file tree
Showing 3 changed files with 972 additions and 500 deletions.
75 changes: 32 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Module Source Imports
# Import Source Reflection

## Status

Expand Down Expand Up @@ -49,9 +49,7 @@ not supported.
const x = await import("<specifier>", { phase: "source" });
```

For dynamic imports, import phase is specified in the same second
attribute options bag that [import assertions][] are specified in, using the
`phase` key.
For dynamic imports, import phase is specified as a separate `phase` key in the options object to dyamic import, similar to how [import attributes][] use the `with` key.

### Loading Phase

Expand All @@ -69,29 +67,31 @@ Only the `source` import source phase is specified by this proposal.

### Defining Module Source

Module source is defined through the [ECMA-262 ES modules HostLoadImportedModule refactoring][],
which moves the construction of module records to the host, and on which we can define a
`[[ModuleSourceObject]]` custom object to be returned by module source phase that is compatible
with module expressions.
The object provided by the module source phase must be an object with
`AbtractModuleSource.prototype` in its prototype chain, defined by this specification
to be a minimal shared base prototype for a compiled modular resource.

In addition it defines the `@@toStringTag` getter returning the constructor name string
corresponding to the name of the specific module source subclass, with a strong
internal slot check.

### JS Module Source

The type of the module source object for a JavaScript module is would depend
on the [module source][] specification.
For JavaScript modules, the module source phase is then specified to return
a `ModuleSource` object, representing an ECMAScript Module Source, where
`ModuleSource.prototype.[[Proto]]` is `%AbstractModuleSource%.prototype`.

In the current specification, the JS module source case just throws an error
to support this as a future addition.
Future proposals may then add support for [bindings lookup methods][],
the [ModuleSource constructor][module soruce] and [instantiation][] support.

### Wasm Module Source
New properties may be added to the base `%AbstractModuleSource%.prototype`, or shared
with ECMAScript module sources via `ModuleSource.prototype` additions.

The type of the module source object for WebAssembly would be a
`WebAssembly.Module`, as defined in the [WebAssembly JS integration
API][wasm-js-api].
### Wasm Module Source

The module source would represent an unlinked and uninstantiated module, while
still being able to support the same CSP policy as the native [ESM
integration][wasm-esm], avoiding the need for `unsafe-wasm-eval` for custom Wasm
execution.
For WebAssembly modules, the existing `WebAssembly.Module.prototype` object is to be
updated to have a `[[Proto]]` of `%AbstractModuleSource%.prototype` in the
[WebAssembly JS integration API][wasm-js-api].

This allows workflows, as explained in the motivation, like the following:

Expand Down Expand Up @@ -119,29 +119,16 @@ In turn this enables [Wasm components to be able to import][]

### Other Module Types

Other module types may define their own host module sources. If no module phase import
is defined, it will fail during the loading phase.
Any other host-defined module types may define their own host module sources. If a given module does not define a source representation for it's source, importing it with a "source" phase target fails with a `ReferenceError` at link time.

## Security Benefits

Tracking the origins of scripts or modules is important for protecting programs
from cross-site scripting attacks, for example using [Content Security
Policies][CSP]. Extending this behaviour to dynamic module sources enables
custom loaders while retaining these security benefits.
Host-defined module sources must include `%AbstractModuleSource%.prototype` in their prototype chain and support the `[[ModuleSourceRecord]]` internal slot containing the `@@toStringTag` brand check and underlying source host data.

Wasm compilation is unfortunately completely dynamic right now (manual network
fetch & compile), so Wasm unconditionally requires a
`script-src: unsafe-wasm-eval` CSP attribute.
## Security Benefits

With this proposal, the JS and Wasm module sources would be known statically,
so would not have to be considered as dynamic code generation. This would allow
the web platform to enabling dynamic instantiation for these modules while
lifting the restriction of an arbitrary evaluation CSP policy and instead just
require `script-src: self` (or `wasm-src: self`). Also see
https://github.com/WebAssembly/esm-integration/issues/56.
The native ES module loader is able to implement security policies, including
support for [Content Security Policies][CSP] in browsers. This property does not just impact platforms using CSP, but also other platforms with systems to restrict permissions, such as Deno. These policies are based on protecting which URLs are supported for the compilation and execution of scripts or modules.

This property does not just impact platforms using CSP, but also other platforms
with systems to restrict permissions, such as Deno.
Extending the static security benefits of the host module system to custom loaders is a security benefit of this proposal. For Wasm, it would enable source-specific CSP policies for dynamic Wasm instantiation.

## Cache Key Semantics

Expand All @@ -150,11 +137,11 @@ be unique to the module being imported from.

## Q&A

**Q**: How does this relate to import assertions / evaluator attributes?
**Q**: How does this relate to import attributes?

**A**: Import assertions are properties of the module request, while source imports
**A**: Import attributes are properties of the module request, while source imports
represent phases of that specific request / key in the module map, without affecting
the idempotency of the module load.
the idempotency of the module load. Both can be used together for a resource to indicate alternative phasing for the given module resource and attributes.

**Q**: How does this relate to module expressions and compartments?

Expand All @@ -179,8 +166,10 @@ needed. See the security improvements section for more details.
[Wasm module object]:
https://webassembly.github.io/spec/js-api/index.html#modules
[asset references proposal]: https://github.com/tc39/proposal-asset-references
[bindings lookup methods]: https://github.com/tc39/proposal-compartments/blob/master/1-static-analysis.md
[compartments]: https://github.com/tc39/proposal-compartments
[import assertions]: https://github.com/tc39/proposal-import-assertions/
[import attributes]: https://github.com/tc39/proposal-import-attributes/
[instantiation]: https://github.com/tc39/proposal-compartments/blob/master/0-module-and-module-source.md#module-instances
[module-linking]:
https://github.com/WebAssembly/module-linking/blob/main/proposals/module-linking/Binary.md#import-section-updates
[module expressions]: https://github.com/tc39/proposal-module-expressions
Expand Down
Loading

0 comments on commit 4defdd7

Please sign in to comment.