Skip to content

Commit

Permalink
chore: add WASM plugin proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
rholshausen committed Dec 6, 2024
1 parent ef3d3a2 commit b0c9044
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 46 deletions.
2 changes: 1 addition & 1 deletion docs/proposals/002_Support_script_language_plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ These can map quite easily to the gRPC calls make to the exiting plugins.

## Technical details

For a POC of a JWT plugin written in Lua, see the feat/lua-plugins branch is this repository:
For a POC of a JWT plugin written in Lua, see the feat/lua-plugins branch in this repository:
* Consumer test https://github.com/pact-foundation/pact-plugins/blob/feat/lua-plugins/examples/jwt/consumer/src/lib.rs
* Lua Plugin https://github.com/pact-foundation/pact-plugins/tree/feat/lua-plugins/plugins/jwt

Expand Down
158 changes: 114 additions & 44 deletions docs/proposals/003_Support_WASM_plugins.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,121 @@
## Support WASM plugins (Draft)
# Support WASM plugins (Draft)

A one-paragraph explanation of the feature.
Discussion for this proposal: https://github.com/pact-foundation/pact-plugins/discussions/85

## Motivation

Why are we doing this? What use cases does it support? What is the expected outcome?

## Guide-level explanation

Explain the proposal as if it were already a part of Pact. That generally means:

- Explaining the feature largely in terms of examples.
- Explaining how Pact users should *think* about the feature, and how it should impact the way they use Pact. It should explain the impact as concretely as possible.
- If applicable, provide sample error messages, deprecation warnings, or migration guidance.
- If applicable, describe the differences between teaching this to existing Pact users and new Pact users.
- Discuss how this impacts existing Pacts, and the Pact ecosystem in general.

## Reference-level explanation

This is the technical portion of the RFC. Explain the design in sufficient detail that:

- Its interaction with other features is clear.
- It is reasonably clear how the feature would be implemented.
- Corner cases are dissected by example.
## Summary

The section should return to the examples given in the previous section, and explain more fully how the detailed proposal makes those examples work.
Allow plugins to be written in a language that can compile to WASM + WASI using WIT and the Web Assembly Component model.

## Drawbacks
## Definitions

Why should we *not* do this?
* WASM is the Web Assembly format
* WASI is the Web Assembly System Interface.
* Web Assembly Component model is a model where WASM files are distributed a components with a well defined interface.
* WIT is the Web Assembly interface definition language (IDL). It forms the interface part of the Web Assembly Component model.

## Rationale and alternatives

- Why is this design the best in the space of possible designs?
- What other designs have been considered and what is the rationale for not choosing them?
- What is the impact of not doing this?

## Unresolved questions

- What parts of the design do you expect to resolve through the RFC process before this gets merged?
- What parts of the design do you expect to resolve through the implementation of this feature before stabilization?
- What related issues do you consider out of scope for this RFC but could be addressed independently in future solutions?

## Future possibilities

Think about what the natural extension and evolution of your proposal would be and how it would affect the Pact specification, Pact users, and the ecosystem in a holistic way. This is also a good place to "dump ideas", if they are out of scope for the RFC you are writing but otherwise related.

If you have tried and cannot think of any future possibilities, you may simply state that you cannot think of anything.
## Motivation

Note that having something written down in the future-possibilities section is not a reason to accept the current or a future RFC; such notes should be in the section on motivation or rationale in this or subsequent RFCs. The section merely provides additional information.
Web Assembly is designed as a general purpose virtual machine that can execute WASM files (basically a more general
VM than the JVM). With WASI, it can run server side (WASI brings to Web Assembly what Node brought to the JavaScript world).
This means that plugins compiled to WASM + WASI are executables that are not dependent on system architectures. Like
with the JVM, it allows the "write once, run anywhere" paradigm (or the more flippant "Write once, debug everyone" one).
This is very appealing for plugins.

The Web Assembly Component model allows WASM components to be made up of a number components that have a well defined
interface defined by the WIT format (which is very similar to the Protobuf definition). The components can be loaded,
and their interfaces queried and invoked. This is even more appealing for plugins.

## Details

The WASM based plugins are executed by an embedded interpreter. This means they are run in the same address space as the
testing framework (unlike the gRPC based plugins). Wasmtime was used for the prototype, as it is very standard compliant
and is actively developed. It supports JIT compilation of the executed WASM.

Instead of making RPC calls to the plugin process, the plugin just exposes functions defined by an interface definition
that the plugin driver can call. These can map quite easily to the gRPC calls make to the exiting plugins (in fact the
WIT format is very similar to the Protobuf one).

For example, with the Init call to the plugin, the plugin returns with the catalogue entries that it supports. With gRPC,
this was defined as

```protobuf
// Entry to be added to the core catalogue. Each entry describes one of the features the plugin provides.
// Entries will be stored in the catalogue under the key "plugin/$name/$type/$key".
message CatalogueEntry {
enum EntryType {
// Matcher for contents of messages, requests or response bodies
CONTENT_MATCHER = 0;
// Generator for contents of messages, requests or response bodies
CONTENT_GENERATOR = 1;
// Transport for a network protocol
TRANSPORT = 2;
// Matching rule for content field/values
MATCHER = 3;
// Type of interaction
INTERACTION = 4;
}
// Entry type
EntryType type = 1;
// Entry key
string key = 2;
// Associated data required for the entry. For CONTENT_MATCHER and CONTENT_GENERATOR types, a "content-types"
// value (separated by semi-colons) is required for all the content types the plugin supports.
map<string, string> values = 3;
}
```

This can be represented easily with WIT:
```wit
enum entry-type {
// Matcher for contents of messages, requests or response bodies
CONTENT-MATCHER,
// Generator for contents of messages, requests or response bodies
CONTENT-GENERATOR,
// Transport for a network protocol
TRANSPORT,
// Matching rule for content field/values
MATCHER,
// Type of interaction
INTERACTION
}
// Entry to be added to the core catalogue. Each entry describes one of the features the plugin provides.
// Entries will be stored in the catalogue under the key "plugin/$name/$type/$key".
record catalogue-entry {
// Entry type
entry-type: entry-type,
// Entry key
key: string,
// Associated data required for the entry. For CONTENT_MATCHER and CONTENT_GENERATOR types, a "content-types"
// value (separated by semi-colons) is required for all the content types the plugin supports.
values: list<tuple<string, string>>
}
```

## Technical details

For a POC of a JWT plugin written in Rust and compiled to WASM, see the feat/wasm-plugins branch in this repository:
* Consumer test https://github.com/pact-foundation/pact-plugins/blob/feat/wasm-plugins/examples/jwt/consumer/src/lib.rs
* JWT Plugin https://github.com/pact-foundation/pact-plugins/tree/feat/wasm-plugins/plugins/jwt/wasm-plugin

All the [gRPC calls and messages](https://github.com/pact-foundation/pact-plugins/blob/feat/wasm-plugins/proto/plugin.proto)
are defined using [WIT instead](https://github.com/pact-foundation/pact-plugins/blob/feat/wasm-plugins/plugins/jwt/wasm-plugin/wit/plugin.wit).

## Benefits

* The plugins are independent of system architecture. They only need to produce a single WASM file.
* Call back functionality (see the [V2 Plugin Interface proposal](https://github.com/pact-foundation/pact-plugins/blob/main/docs/proposals/001_V2_Plugin_Interface.md#capability-for-plugins-to-use-the-functionality-from-the-calling-framework))
can be easily implemented as functions that are exposed by the driver to the plugin. With the WASM plugin, [the log](https://github.com/pact-foundation/pact-plugins/blob/feat/wasm-plugins/plugins/jwt/wasm-plugin/wit/plugin.wit#L4)
function is an example. Exporting functions for a WASM file is part of the design of Web Assembly.
* Plugins can be written in any language that compiles to WASM + WASI and supports WIT (there are quite a lot).
* Plugins can have a well defined interface that is part of the plugin binary (WASM file).

## Issues with this approach

* Web Assembly specifications are still in development. Some, like thread support, have only recently gotten to a usable state.
* WASI is missing lots of functionality. While development for it is moving quite fast, there are still gaps. For instance,
there is no cryptography support. This made writing a JWT plugin challenging, as part of what it needs to do is validate the signature of the token.
* There is no JVM support. There are frameworks like [Extism](https://extism.org/) that support the JVM, they do this by embedding
the interpreter shared library. This makes the implementation system architecture dependent. It also feels wrong to have
a stack-based virtual machine embed another stack-based virtual machine.
* There are multiple implementations. Two main ones are Wasmtime and Wasmer. We would need to pick one to use.
2 changes: 1 addition & 1 deletion docs/proposals/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Here is the current list of proposed changes to the Pact Plugin architecture.
|-----------------------------------------------------------------------------|-------|----------------------------------------------------------------|
| [V2 Plugin Interface](./001_V2_Plugin_Interface.md) | Draft | https://github.com/pact-foundation/pact-plugins/discussions/83 |
| [Support script language plugins](./002_Support_script_language_plugins.md) | Draft | https://github.com/pact-foundation/pact-plugins/discussions/84 |
| [Support WASM plugins](./003_Support_WASM_plugins.md) | Draft | |
| [Support WASM plugins](./003_Support_WASM_plugins.md) | Draft | https://github.com/pact-foundation/pact-plugins/discussions/85 |

0 comments on commit b0c9044

Please sign in to comment.