This is a rough POC for allowing people to whitelist a dir as readonly.
When the source path is prefixed with `ro:`, the dir is considered as
readonly. This preserved backward compatibility. This suggestion came up
in https://github.com/extism/go-sdk/pull/1#discussion_r1276700587
Readonly:
```rs
let manifest = Manifest::new([url])
.with_allowed_path("ro:D:/x/rust/fs/data".to_string(), "/data")
.with_config_key("path", "/data/data.txt");
```
```
trying to read file:
"Hello World at 1719851282.5109031sHello World at 1719851299.0819795sHello World at 1719851317.8934608s\n"
-----------------------------------------------------
trying to write file:
thread '<unnamed>' panicked at src\lib.rs:24:34:
called `Result::unwrap()` on an `Err` value: Os { code: 58, kind: Unsupported, message: "Not supported" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'main' panicked at runtime\examples\fs.rs:27:6:
called `Result::unwrap()` on an `Err` value: error while executing at wasm backtrace:
0: 0x234d2 - fs.wasm!__rust_start_panic
1: 0x232a1 - fs.wasm!rust_panic
2: 0x231da - fs.wasm!std::panicking::rust_panic_with_hook::hd3fb69bc0aea298a
3: 0x22467 - fs.wasm!std::panicking::begin_panic_handler::{{closure}}::h4d99b90b43f79472
4: 0x223ca - fs.wasm!std::sys_common::backtrace::__rust_end_short_backtrace::h5691573a73161cb1
5: 0x22bca - fs.wasm!rust_begin_unwind
6: 0x303e9 - fs.wasm!core::panicking::panic_fmt::hdb62f5cdb45533e4
7: 0x3234d - fs.wasm!core::result::unwrap_failed::h30d23efcc9e41efc
8: 0x36c2 - fs.wasm!fs::try_write::inner::h0b3b0df8e129f5cc
9: 0x29cd - fs.wasm!try_write
10: 0x35e4a - fs.wasm!try_write.command_export
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
Caused by:
wasm trap: wasm `unreachable` instruction executed
Stack backtrace:
0: std::backtrace_rs::backtrace::dbghelp64::trace
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\..\..\backtrace\src\backtrace\dbghelp64.rs:99
1: std::backtrace_rs::backtrace::trace_unsynchronized
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
2: std::backtrace::Backtrace::create
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\backtrace.rs:331
3: std::backtrace::Backtrace::capture
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\backtrace.rs:296
4: anyhow::error::impl$1::from<wasmtime_environ::trap_encoding::Trap>
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\anyhow-1.0.86\src\error.rs:565
5: core::convert::impl$3::into<wasmtime_environ::trap_encoding::Trap,anyhow::Error>
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\convert\mod.rs:759
6: wasmtime_environ::impl$1::into_anyhow<wasmtime_environ::trap_encoding::Trap>
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-environ-22.0.0\src\lib.rs:90
7: wasmtime::runtime::trap::from_runtime_box
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\trap.rs:118
8: wasmtime::runtime::func::invoke_wasm_and_catch_traps::closure$0<extism::current_plugin::CurrentPlugin,wasmtime::runtime::func::impl$1::call_unchecked_raw::closure_env$0<extism::current_plugin::CurrentPlugin> >
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1597
9: enum2$<core::result::Result<tuple$<>,alloc::boxed::Box<wasmtime::runtime::vm::traphandlers::Trap,alloc::alloc::Global> > >::map_err<tuple$<>,alloc::boxed::Box<wasmtime::runtime::vm::traphandlers::Trap,alloc::alloc::Global>,anyhow::Error,wasmtime::runtime:
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\result.rs:829
10: wasmtime::runtime::func::invoke_wasm_and_catch_traps<extism::current_plugin::CurrentPlugin,wasmtime::runtime::func::impl$1::call_unchecked_raw::closure_env$0<extism::current_plugin::CurrentPlugin> >
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1597
11: wasmtime::runtime::func::Func::call_unchecked_raw<extism::current_plugin::CurrentPlugin>
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1063
12: wasmtime::runtime::func::Func::call_unchecked<ref_mut$<wasmtime::runtime::store::context::StoreContextMut<extism::current_plugin::CurrentPlugin> > >
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1049
13: wasmtime::runtime::func::Func::call_impl_do_call<extism::current_plugin::CurrentPlugin>
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1243
14: wasmtime::runtime::func::Func::call<ref_mut$<wasmtime::runtime::store::Store<extism::current_plugin::CurrentPlugin> > >
at C:\Users\muham\.cargo\registry\src\index.crates.io-6f17d22bba15001f\wasmtime-22.0.0\src\runtime\func.rs:1002
15: extism::plugin::Plugin::raw_call<ref$<str$>,ref$<str$> >
at .\src\plugin.rs:753
16: extism::plugin::Plugin::call<ref$<str$>,ref$<str$>,ref$<str$> >
at .\src\plugin.rs:900
17: fs::main
at .\examples\fs.rs:25
18: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\ops\function.rs:250
19: core::hint::black_box
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\hint.rs:337
20: std::sys_common::backtrace::__rust_begin_short_backtrace<void (*)(),tuple$<> >
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\sys_common\backtrace.rs:155
21: std::rt::lang_start::closure$0<tuple$<> >
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\rt.rs:166
22: std::rt::lang_start_internal
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\rt.rs:148
23: std::rt::lang_start<tuple$<> >
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\rt.rs:165
24: main
25: invoke_main
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
26: __scrt_common_main_seh
at D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
27: BaseThreadInitThunk
28: RtlUserThreadStart
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\std\src\panicking.rs:645
1: core::panicking::panic_fmt
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\core\src\panicking.rs:72
2: core::result::unwrap_failed
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library\core\src\result.rs:1654
3: enum2$<core::result::Result<ref$<str$>,anyhow::Error> >::unwrap
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\result.rs:1077
4: fs::main
at .\examples\fs.rs:25
5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\ops\function.rs:250
6: core::hint::black_box
at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\hint.rs:337
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `D:\dylibso\extism\target\debug\examples\fs.exe` (exit code: 101)
```
Writable:
```rs
let manifest = Manifest::new([url])
.with_allowed_path("D:/x/rust/fs/data".to_string(), "/data")
.with_config_key("path", "/data/data.txt");
```
```
trying to read file:
"Hello World at 1719851282.5109031sHello World at 1719851299.0819795sHello World at 1719851317.8934608s\n"
-----------------------------------------------------
trying to write file:
"Hello World at 1719851282.5109031sHello World at 1719851299.0819795sHello World at 1719851317.8934608s\nHello World at 1719851500.7803263s\n"
done!
```
https://github.com/extism/dotnet-pdk/pull/84 brought to my attention
that the Rust SDK supports both `headers` and `header` while the go sdk
only supports `headers`. After talking to Zach, we decided to remove the
`header` alias from the Rust SDK too, since it's obsolete and we want
people to use `headers`
- Adds `memory.max_var_bytes` to the manifest to limit the number of
bytes allowed to be stored in Extism vars - if `max_var_bytes` is set to
0 then vars are disabled.
- Adds some builder functions to `MemoryOptions` struct
- Sets the default var store size to 1mb
- Includes a test to make sure `var_set` returns an error when the limit
is reached
Updates the requirements on
[base64](https://github.com/marshallpierce/rust-base64) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md">base64's
changelog</a>.</em></p>
<blockquote>
<h1>0.22.0</h1>
<ul>
<li><code>DecodeSliceError::OutputSliceTooSmall</code> is now
conservative rather than precise. That is, the error will only occur if
the decoded output <em>cannot</em> fit, meaning that
<code>Engine::decode_slice</code> can now be used with exactly-sized
output slices. As part of this, <code>Engine::internal_decode</code> now
returns <code>DecodeSliceError</code> instead of
<code>DecodeError</code>, but that is not expected to affect any
external callers.</li>
<li><code>DecodeError::InvalidLength</code> now refers specifically to
the <em>number of valid symbols</em> being invalid (i.e. <code>len % 4
== 1</code>), rather than just the number of input bytes. This avoids
confusing scenarios when based on interpretation you could make a case
for either <code>InvalidLength</code> or <code>InvalidByte</code> being
appropriate.</li>
<li>Decoding is somewhat faster (5-10%)</li>
</ul>
<h1>0.21.7</h1>
<ul>
<li>Support getting an alphabet's contents as a str via
<code>Alphabet::as_str()</code></li>
</ul>
<h1>0.21.6</h1>
<ul>
<li>Improved introductory documentation and example</li>
</ul>
<h1>0.21.5</h1>
<ul>
<li>Add <code>Debug</code> and <code>Clone</code> impls for the general
purpose Engine</li>
</ul>
<h1>0.21.4</h1>
<ul>
<li>Make <code>encoded_len</code> <code>const</code>, allowing the
creation of arrays sized to encode compile-time-known data lengths</li>
</ul>
<h1>0.21.3</h1>
<ul>
<li>Implement <code>source</code> instead of <code>cause</code> on Error
types</li>
<li>Roll back MSRV to 1.48.0 so Debian can continue to live in a time
warp</li>
<li>Slightly faster chunked encoding for short inputs</li>
<li>Decrease binary size</li>
</ul>
<h1>0.21.2</h1>
<ul>
<li>Rollback MSRV to 1.57.0 -- only dev dependencies need 1.60, not the
main code</li>
</ul>
<h1>0.21.1</h1>
<ul>
<li>Remove the possibility of panicking during decoded length
calculations</li>
<li><code>DecoderReader</code> no longer sometimes erroneously ignores
padding <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/226">#226</a></li>
</ul>
<h2>Breaking changes</h2>
<ul>
<li><code>Engine.internal_decode</code> return type changed</li>
<li>Update MSRV to 1.60.0</li>
</ul>
<h1>0.21.0</h1>
<h2>Migration</h2>
<h3>Functions</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5d70ba7576"><code>5d70ba7</code></a>
Merge pull request <a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/269">#269</a>
from marshallpierce/mp/decode-precisely</li>
<li><a
href="efb6c006c7"><code>efb6c00</code></a>
Release notes</li>
<li><a
href="2b91084a31"><code>2b91084</code></a>
Add some tests to boost coverage</li>
<li><a
href="9e9c7abe65"><code>9e9c7ab</code></a>
Engine::internal_decode now returns DecodeSliceError</li>
<li><a
href="a8a60f43c5"><code>a8a60f4</code></a>
Decode main loop improvements</li>
<li><a
href="a25be0667c"><code>a25be06</code></a>
Simplify leftover output writes</li>
<li><a
href="9979cc33bb"><code>9979cc3</code></a>
Keep morsels as separate bytes</li>
<li><a
href="37670c5ec2"><code>37670c5</code></a>
Bump dev toolchain version (<a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/268">#268</a>)</li>
<li><a
href="9652c78773"><code>9652c78</code></a>
v0.21.7</li>
<li><a
href="08deccf703"><code>08deccf</code></a>
provide as_str() method to return the alphabet characters (<a
href="https://redirect.github.com/marshallpierce/rust-base64/issues/264">#264</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/marshallpierce/rust-base64/compare/v0.21.0...v0.22.0">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
base64 support is retained. Now `data` can instead be `{"ptr":
ptr_value, "len": len_value}` where `ptr_value` points to a wasm module
and `len_value` is the size of bytes of it.
The default for `timeout_ms` is currently 30s which was an arbitrary
decision but it forces a user to set `timeout_ms` to null to avoid
having plugins cancelled which is a little strange.
Alternate to: #596 without support for manually compiling/loading native
code
- Enables wasmtime caching: https://docs.wasmtime.dev/cli-cache.html
- Adds `EXTISM_CACHE_CONFIG` and `PluginBuilder::with_cache_config` to
determine where to load a custom cache configuration from
- Adds `PluginBuilder::with_cache_disabled` to disable the cache when
initializing a plugin
- Setting `EXTISM_CACHE_CONFIG=""` will also disable caching
## Performance
With caching:
```
create/create_plugin time: [2.9079 ms 2.9139 ms 2.9200 ms]
change: [+3.2677% +3.6399% +3.9766%] (p = 0.00 < 0.20)
Change within noise threshold.
```
Compared to `main`:
```
create/create_plugin time: [26.089 ms 26.498 ms 26.923 ms]
change: [+0.1729% +2.0868% +4.1337%] (p = 0.04 < 0.20)
Change within noise threshold.
```
Attempts to address an error seen when upgrading both Rust PDK & SDK to
latest:
```
Updating git repository `https://github.com/extism/extism.git`
Updating git repository `https://github.com/extism/rust-pdk.git`
Updating crates.io index
error: failed to select a version for `base64`.
... required by package `extism-convert v0.2.0 (https://github.com/extism/extism.git?branch=main#7636c873)`
... which satisfies git dependency `extism-convert` of package `extism v1.0.0-alpha.0 (https://github.com/extism/extism.git?branch=main#7636c873)`
... which satisfies git dependency `extism` of package `proto_core v0.22.4 (/Users/miles/Projects/proto/crates/core)`
... which satisfies path dependency `proto_core` (locked to 0.22.4) of package `proto_cli v0.22.0 (/Users/miles/Projects/proto/crates/cli)`
versions that meet the requirements `^0.21.3` are: 0.21.5, 0.21.4, 0.21.3
all possible versions conflict with previously selected packages.
previously selected package `base64 v0.21.0`
... which satisfies dependency `base64 = "^0.21.0"` (locked to 0.21.0) of package `extism-manifest v0.5.0`
... which satisfies dependency `extism-manifest = "^0.5.0"` (locked to 0.5.0) of package `extism-pdk v1.0.0-beta.0 (https://github.com/extism/rust-pdk.git?branch=main#009bf808)`
... which satisfies git dependency `extism-pdk` of package `proto_pdk v0.10.2 (/Users/miles/Projects/proto/crates/pdk)`
failed to select a version for `base64` which could resolve this conflict
```
- Removes `Plugin::new_with_manifest` and updates `Plugin::new` to take
wasm bytes or `Manifest` using the new `WasmInput` trait
- Removes `PluginBuilder::new_with_module` in favor of a
`PluginBuilder::new` with a `WasmInput` argument
See #504
Removes CI for the in-repo SDKs, we can remove the actual code closer to
the 1.0 release.
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: zshipko <zshipko@users.noreply.github.com>
- Removes restrictions around when `memory.max_pages` setting can be
used. Before we used `wasmtime::MemoryLimiter` it was hard to determine
how much was being allocated at runtime, so we used to calculate the
totals statically, which required every module to have a maximum memory
set at compile time. This PR allows `memory.max` to be used on any
module!
- Fixes a crash when the `memory.max_pages` field is set
- Adds a test that checks for failure when allocating more than
configured
- Adds `extism-convert` crate with `ToBytes`, `FromBytes` and
`FromBytesOwned` traits
- This serves as a single interface for reading/writing rich types from
WebAssembly linear memory.
- Supports `Json` and `Msgpack` and `Protobuf` encodings out-of-the-box
- Updates `Plugin::call` to take `ToBytes` as the input argument and
return a `FromBytes` value
- Adds `host_fn!` macro to simplify host function creation
- Cleans up generated documentation a little
- PR for the Rust PDK: https://github.com/extism/rust-pdk/pull/31
- Adds a `typed_plugin!` macro to implement type-safe wrappers around
`Plugin`
- After this we should focus on adding similar type-conversion helpers
to the SDKs and other PDKs to make it easier to use across languages.
For example, a Python host running a Rust plugin using Msgpack encoded
types.
## Examples
### Calling a function
Instead of the untyped, bytes-only `call` function:
```rust
let output = plugin.call("func_name", "my data").unwrap();
let output: MyType = serde_json::from_slice(&output).unwrap();
```
We can now use richer types to encode/decode our values directly when
using `call`:
```rust
let Json(output) = plugin.call::<_, Json<MyType>>("func_name", "my data").unwrap();
```
### Allocating inside of a host function
The same interface works for host functions, so instead of:
```rust
fn hello_world(
plugin: &mut CurrentPlugin,
inputs: &[Val],
outputs: &mut [Val],
_user_data: UserData,
) -> Result<(), Error> {
let handle = plugin.memory_handle_val(&inputs[0])?;
let input = plugin.memory_read_str(handle)?;
let output = plugin.memory_alloc_bytes(&input).unwrap();
outputs[0] = output.into();
Ok(())
}
```
Becomes:
```rust
fn hello_world(
plugin: &mut CurrentPlugin,
inputs: &[Val],
outputs: &mut [Val],
_user_data: UserData,
) -> Result<(), Error> {
let my_value: String = plugin.memory_get_val(&inputs[0])?;
let output = plugin.memory_new(&my_value)?;
outputs[0] = plugin.memory_to_val(output);
Ok(())
}
```
Although this isn't much of an improvement, using the `host_fn` macro,
we can really begin to see how the above function is really just an
identity function:
```rust
host_fn!(hello_world(a: String) -> String {
a
});
```
### typed_plugin!
`typed_plugin!` is used to make a typed wrapper around a Plugin:
```rust
/// Create the typed plugin
typed_plugin!(Testing {
count_vowels(&str) -> Json<Count>
});
/// Create the `Plugin` and convert it to `Testing` wrapper
let mut plugin: Testing = Plugin::new(WASM, [f], true).unwrap().into();
/// Call the `count_vowels` function:
let Json(output0): Json<Count> = plugin.count_vowels("abc123")?;
```
It could make sense to convert `host_fn` and/or `typed_plugin` to
proc-macros at some point, but for now they work and provide some
flexibility in experimenting with the interfaces. Another future update
could be to figure out a nice way to make it so input can be written in
multiple chunks, so the entire input doesn't have to get copied into
memory at once.
- Removes the `ExtismContext` type from runtime and all SDKs
- Removed SDK functions: `extism_context_new`, `extism_context_reset`,
`extism_context_free`
- All SDKs have been updated, but there are still some TODOs below
- Removes `extism_plugin_update`
- Plugins can no longer be updated - a new plugin should be created
instead
- Adds `extism_plugin_id` to uniquely identify plugins
- Merges the `extism-runtime` and `extism` crates (there is no longer an
`extism-runtime` crate)
- Makes `extism::Manifest` an alias for `extism_manifest::Manifest`
instead of a distinct type
- Adds `MemoryHandle` type to SDKs to refer to blocks of Extism memory
that can be accessed in host functions
- Improves thread-safety of Plugins, adds C++ test to call a single
plugin from multiple threads.
- Expands wasmtime bounds to include 12.0
This PR adds the `kernel` directory which contains a port of the Extism
memory allocator compiled to WebAssembly and removes
`runtime/src/memory.rs` completely.
Being able to re-use memory functions as a WASM module allows us to
begin to experiment with porting Extism to new runtimes!
This is in a draft state while I'm verifying some of these changes.
Unsure if now is the best time to do the `extism` crate version bumps,
but I figured they'd need to happen at some point in the near future
anyways. Happy to revert if there is any opposition. Also, I added back
the local `path` property to the Elixir NIF crate manifest. I want to
see if this breaks again in CI, or if we can leave it.
---------
Co-authored-by: zach <zach@dylib.so>
Let's get the last changes in this week for a release. Will hold this PR
until all changes we want are in.
Release checklist:
- [x] test: updates across CI to test for Host Function output /
integration (#219)
- this should probably look something like a grep for some kind of
output proving guest/host interop?
- [x] Fix for userData pointer issue in Go host functions (#220)
- [x] docs: Host Functions in SDKs
- [ ] sdk: C
- [ ] sdk: C++
- [ ] sdk: Python
- [ ] sdk: Node
- [ ] sdk: Go
- [ ] sdk: Rust
- [x] docs: Manifest property names (http `headers` & memory
`max_pages`)
- [ ] blog: announcing v0.2.0, including host functions, Zig SDK/PDK,
Java SDK, .NET SDK, + ...
Updates the requirements on
[base64](https://github.com/marshallpierce/rust-base64) to permit the
latest version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md">base64's
changelog</a>.</em></p>
<blockquote>
<h1>0.21.0</h1>
<p>(not yet released)</p>
<h2>Migration</h2>
<h3>Functions</h3>
<table>
<thead>
<tr>
<th>< 0.20 function</th>
<th>0.21 equivalent</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>encode()</code></td>
<td><code>engine::general_purpose::STANDARD.encode()</code> or
<code>prelude::BASE64_STANDARD.encode()</code></td>
</tr>
<tr>
<td><code>encode_config()</code></td>
<td><code>engine.encode()</code></td>
</tr>
<tr>
<td><code>encode_config_buf()</code></td>
<td><code>engine.encode_string()</code></td>
</tr>
<tr>
<td><code>encode_config_slice()</code></td>
<td><code>engine.encode_slice()</code></td>
</tr>
<tr>
<td><code>decode()</code></td>
<td><code>engine::general_purpose::STANDARD.decode()</code> or
<code>prelude::BASE64_STANDARD.decode()</code></td>
</tr>
<tr>
<td><code>decode_config()</code></td>
<td><code>engine.decode()</code></td>
</tr>
<tr>
<td><code>decode_config_buf()</code></td>
<td><code>engine.decode_vec()</code></td>
</tr>
<tr>
<td><code>decode_config_slice()</code></td>
<td><code>engine.decode_slice()</code></td>
</tr>
</tbody>
</table>
<p>The short-lived 0.20 functions were the 0.13 functions with
<code>config</code> replaced with <code>engine</code>.</p>
<h3>Padding</h3>
<p>If applicable, use the preset engines <code>engine::STANDARD</code>,
<code>engine::STANDARD_NO_PAD</code>, <code>engine::URL_SAFE</code>,
or <code>engine::URL_SAFE_NO_PAD</code>.
The <code>NO_PAD</code> ones require that padding is absent when
decoding, and the others require that
canonical padding is present .</p>
<p>If you need the < 0.20 behavior that did not care about padding,
or want to recreate < 0.20.0's predefined <code>Config</code>s
precisely, see the following table.</p>
<table>
<thead>
<tr>
<th>0.13.1 Config</th>
<th>0.20.0+ alphabet</th>
<th><code>encode_padding</code></th>
<th><code>decode_padding_mode</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>STANDARD</td>
<td>STANDARD</td>
<td>true</td>
<td>Indifferent</td>
</tr>
<tr>
<td>STANDARD_NO_PAD</td>
<td>STANDARD</td>
<td>false</td>
<td>Indifferent</td>
</tr>
<tr>
<td>URL_SAFE</td>
<td>URL_SAFE</td>
<td>true</td>
<td>Indifferent</td>
</tr>
<tr>
<td>URL_SAFE_NO_PAD</td>
<td>URL_SAFE</td>
<td>false</td>
<td>Indifferent</td>
</tr>
</tbody>
</table>
<h1>0.21.0-rc.1</h1>
<ul>
<li>Restore the ability to decode into a slice of precisely the correct
length with <code>Engine.decode_slice_unchecked</code>.</li>
<li>Add <code>Engine</code> as a <code>pub use</code> in
<code>prelude</code>.</li>
</ul>
<h1>0.21.0-beta.2</h1>
<h2>Breaking changes</h2>
<ul>
<li>Re-exports of preconfigured engines in <code>engine</code> are
removed in favor of <code>base64::prelude::...</code> that are better
suited to those who wish to <code>use</code> the entire path to a
name.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d7fb31c4ad"><code>d7fb31c</code></a>
v0.21.0</li>
<li><a
href="83503761e9"><code>8350376</code></a>
Merge pull request <a
href="https://github-redirect.dependabot.com/marshallpierce/rust-base64/issues/207">#207</a>
from marshallpierce/mp/api-rework</li>
<li><a
href="726f7841b7"><code>726f784</code></a>
v0.21.0-rc.1</li>
<li><a
href="b29ab0196d"><code>b29ab01</code></a>
Add <code>Engine</code> in <code>prelude</code></li>
<li><a
href="64bbcc02df"><code>64bbcc0</code></a>
Remove no longer needed test helpers</li>
<li><a
href="0f981bd04f"><code>0f981bd</code></a>
Add decode_slice_unchecked to restore ability to decode into a precisely
size...</li>
<li><a
href="a51e822ae9"><code>a51e822</code></a>
v0.21.0-beta.2</li>
<li><a
href="936569a658"><code>936569a</code></a>
Move re-exports from <code>engine</code> to <code>prelude</code></li>
<li><a
href="53e1091e1b"><code>53e1091</code></a>
Fix release notes typo</li>
<li><a
href="b03eb5a84d"><code>b03eb5a</code></a>
v0.21.0-beta.1</li>
<li>Additional commits viewable in <a
href="https://github.com/marshallpierce/rust-base64/compare/v0.20.0-alpha.1...v0.21.0">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
- Adds `Manifest::timeout_ms` field to specify the plugin timeout in
milliseconds
- Sets a 30 second default timeout
Co-authored-by: Steve Manuel <steve@dylib.so>
- Adds the ability to initialize plugins with additional functions
created by the host (only supported by the Rust SDK right now)
- Adds `PluginBuilder` to the Rust SDK to make it easier to configure all the options
## Hello, world
The following example uses `println` from the host to print to stdout
from inside the plugin.
Host:
```rust
use extism::*;
fn main() -> Result<(), Error> {
let context = Context::new();
let manifest = Manifest::new([std::path::PathBuf::from("code.wasm")]);
let say_hello = Function::new("say_hello", [ValType::I64], [], |caller, input, _out| {
let internal = caller.data();
let r = internal.memory().get_str(input[0].unwrap_i64() as usize)?;
println!("Hello, {r}!");
Ok(())
});
let mut plugin = PluginBuilder::new(manifest)
.with_function(say_hello)
.with_wasi(true)
.build(&context)?;
plugin.call("test", b"world").unwrap();
Ok(())
}
```
Plugin:
```rust
use extism_pdk::*;
extern "C" {
fn say_hello(offs: u64);
}
#[plugin_fn]
pub fn test(input: String) -> FnResult<()> {
let memory = Memory::from_bytes(&input);
unsafe {
say_hello(memory.offset);
}
Ok(())
}
```
Adds ability to make local files available to plugins. Using the Rust
SDK:
```rust
let wasm = include_bytes!("code.wasm");
let mut context = Context::new();
let manifest = Manifest::new(vec![Wasm::data(wasm)]).with_allowed_path("/path/on/disk", "/plugin/path");
let plugin = Plugin::new_with_manifest(&mut context, &manifest, false)?;
...
```
- Adds some helper functions for creating a manifest, mostly helpful for
the Rust SDK
- Renames `ManifestWasm` to `Wasm`
- Renames `ManifestMemory` to `MemoryOptions`
- `ManifestWasm` and `ManifestMemory` have been marked as deprecated
- Adds an alias from `MemoryOptions::max_pages` to `MemoryOptions::max`
in serde specification
Co-authored-by: Steve Manuel <steve@dylib.so>
- Adds `allowed_hosts` to the manifest
- If there are any `allowed_hosts` then `extism_http_request` checks to
make sure a URL's host is listed before performing the reques
- Adds `ExtismContext` instead of global `PLUGINS` registry
- Adds `extism_context_new`, `extism_context_free` and
`extism_context_reset`
- Requires updating nearly every SDK function to add context parameter
- Renames some SDK functions to follow better naming conventions
- `extism_plugin_register` -> `extism_plugin_new`
- `extism_output_get` -> `extism_plugin_output_data`
- `extism_output_length` -> `extism_plugin_output_length`
- `extism_call` -> `extism_plugin_call`
- Updates `extism_error` to return the context error when -1 issued for
the plug-in ID
- Adds `extism_plugin_free` to remove an existing plugin
- Updates SDKs to include these functions
- Updates SDK examples and comments
Co-authored-by: Steve Manuel <steve@dylib.so>