From 4153f14b8e53ac6434913ab98da7b59e853046c1 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 11:03:40 +0100 Subject: [PATCH 01/11] chore: remove hyperlight-nanvix backend Wipes the nanvix backend and every reference to it so the repo reads as if it never existed. - delete src/nanvix_sandbox/ crate (manifest, lib, examples, Justfile, lockfile) - drop the nanvix exclude entry and explanatory comment from root Cargo.toml - drop `mod nanvix` and the `nanvix::build` dependency from the root Justfile - remove the `nanvix-sandbox` job from .github/workflows/ci.yml - strip the Nanvix Sandbox section + TOC entry from README.md - drop the manual-version-bump bullet from RELEASE.md - rename the slide heading and remove the Nanvix guests section in docs/end-user-overview-slides.md - scrub the nanvix entries from the justfile-ci copilot skill notes Signed-off-by: Simon Davies --- .copilot/skills/justfile-ci/SKILL.md | 1 - .../justfile-ci/references/architecture.md | 9 +- .github/workflows/ci.yml | 23 - Cargo.toml | 4 - Justfile | 3 +- README.md | 30 - RELEASE.md | 1 - docs/end-user-overview-slides.md | 14 +- src/nanvix_sandbox/Cargo.lock | 4454 ----------------- src/nanvix_sandbox/Cargo.toml | 13 - src/nanvix_sandbox/Justfile | 16 - src/nanvix_sandbox/examples/hello.rs | 91 - src/nanvix_sandbox/src/lib.rs | 154 - 13 files changed, 4 insertions(+), 4809 deletions(-) delete mode 100644 src/nanvix_sandbox/Cargo.lock delete mode 100644 src/nanvix_sandbox/Cargo.toml delete mode 100644 src/nanvix_sandbox/Justfile delete mode 100644 src/nanvix_sandbox/examples/hello.rs delete mode 100644 src/nanvix_sandbox/src/lib.rs diff --git a/.copilot/skills/justfile-ci/SKILL.md b/.copilot/skills/justfile-ci/SKILL.md index 38f6b28..d71069e 100644 --- a/.copilot/skills/justfile-ci/SKILL.md +++ b/.copilot/skills/justfile-ci/SKILL.md @@ -20,7 +20,6 @@ This repo uses a **hierarchical Justfile** structure with a matching **GitHub Ac Justfile (root) ← orchestrates everything ├── mod wasm 'src/wasm_sandbox/Justfile' ├── mod js 'src/javascript_sandbox/Justfile' -├── mod nanvix 'src/nanvix_sandbox/Justfile' ├── mod python 'src/sdk/python/Justfile' └── mod examples_mod 'examples/Justfile' ``` diff --git a/.copilot/skills/justfile-ci/references/architecture.md b/.copilot/skills/justfile-ci/references/architecture.md index 2f60e6e..e686e7b 100644 --- a/.copilot/skills/justfile-ci/references/architecture.md +++ b/.copilot/skills/justfile-ci/references/architecture.md @@ -4,7 +4,7 @@ | Recipe | Delegates to | Purpose | |--------|-------------|---------| -| `build` | `wasm::build`, `jss::build`, `nanvix::build`, `python::build` | Build everything | +| `build` | `wasm::build`, `jss::build`, `python::build` | Build everything | | `test` | `test-rust`, `wasm::test`, `python::python-test` | All tests | | `test-rust` | (direct cargo) | Core crate unit + integration tests | | `lint` | `lint-rust`, `wasm::lint`, `js::lint`, `python::lint` | All linters | @@ -21,8 +21,7 @@ ci.yml ├── rust — fmt-check-rust, lint-rust, test-rust ├── wasm-sandbox — wasm build, lint, test, examples + python fmt-check/lint/build/examples/python-test/fuzz/benchmark/integration-examples -├── javascript-sandbox — js build, lint, test, examples -└── nanvix-sandbox — nanvix build (examples skipped pending upstream) +└── javascript-sandbox — js build, lint, test, examples ``` ## Subproject Justfile Responsibilities @@ -39,10 +38,6 @@ ci.yml - Recipes: `build`, `test`, `examples`, `lint` - `examples` is a flat recipe listing all `cargo run` commands -### nanvix (`src/nanvix_sandbox/Justfile`) -- Standalone build, excluded from workspace -- Recipes: `build`, `examples` (currently skipped) - ### python (`src/sdk/python/Justfile`) - Manages `uv`, `maturin`, `ruff` tooling - Recipes: `build`, `fmt`, `fmt-check`, `lint`, `examples`, `python-test`, `python-fuzz`, `python-sandbox-benchmark`, `python-publish` diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5666acb..a33bbb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -411,26 +411,3 @@ jobs: - name: Run examples run: just js examples - - nanvix-sandbox: - name: Nanvix Sandbox · build - runs-on: ubuntu-latest #current linux only - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1.16.0 - with: - toolchain: nightly - rustflags: "" - - - name: Install just - run: cargo install --locked just - - - name: Build - run: just nanvix build - - # NOTE: nanvix examples are skipped until hyperlight-nanvix updates to - # the new nanvix registry API (qjs/python3 are now separate packages). - # See: https://github.com/hyperlight-dev/hyperlight-nanvix - # - name: Run examples - # run: just nanvix examples diff --git a/Cargo.toml b/Cargo.toml index e1d715b..3c2c827 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,6 @@ members = [ "src/sdk/python/hyperlight_js_backend", "src/sdk/dotnet/ffi", ] -# nanvix_sandbox requires nightly Rust (nanvix uses #![feature(never_type)]) -exclude = [ - "src/nanvix_sandbox", -] resolver = "2" [workspace.package] diff --git a/Justfile b/Justfile index b6294b3..bdad65f 100644 --- a/Justfile +++ b/Justfile @@ -2,7 +2,6 @@ set unstable := true mod wasm 'src/wasm_sandbox/Justfile' mod js 'src/javascript_sandbox/Justfile' -mod nanvix 'src/nanvix_sandbox/Justfile' mod python 'src/sdk/python/Justfile' mod dotnet 'src/sdk/dotnet/Justfile' mod examples_mod 'examples/Justfile' @@ -14,7 +13,7 @@ clean: wasm::clean python::clean dotnet::clean #### BUILD TARGETS #### -build target=default-target: (wasm::build target) (js::build target) nanvix::build python::build (dotnet::build target) +build target=default-target: (wasm::build target) (js::build target) python::build (dotnet::build target) lint: lint-rust wasm::lint js::lint python::lint diff --git a/README.md b/README.md index 6086d95..4e9e953 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ Supported backends: - [Wasm Component Sandbox](#wasm-component-sandbox) (Python/Javascript or provide your own) - [HyperlightJS Sandbox](#hyperlightjs-sandbox) -- [Nanvix Sandbox](#nanvix-sandbox) ## Overview @@ -195,35 +194,6 @@ console.log('10 + 20 = ' + sum); See [examples](./src/javascript_sandbox/examples/) for file I/O and network demos. -### Nanvix Sandbox - -A microkernel-based backend built on [hyperlight-nanvix](https://github.com/hyperlight-dev/hyperlight-nanvix) that runs JavaScript or Python inside a Nanvix VM. Currently limited to basic code execution with stdout capture -- no host tools, file I/O, networking, or snapshot support yet. - -```rust -use hyperlight_nanvix_sandbox::{NanvixJavaScript, NanvixPython}; -use hyperlight_sandbox::Sandbox; - -fn main() { - // JavaScript - let mut js = Sandbox::builder() - .guest(NanvixJavaScript) - .build() - .expect("failed to create JS sandbox"); - - let result = js.run(r#"console.log("Hello from Nanvix JS!");"#).unwrap(); - print!("{}", result.stdout); - - // Python - let mut py = Sandbox::builder() - .guest(NanvixPython) - .build() - .expect("failed to create Python sandbox"); - - let result = py.run(r#"print("Hello from Nanvix Python!")"#).unwrap(); - print!("{}", result.stdout); -} -``` - ## Building Tool requirements: diff --git a/RELEASE.md b/RELEASE.md index 42f7d96..9baa245 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -7,7 +7,6 @@ Bump the version in **all** manifest files. For example, to go from `0.1.0` → ### Rust (Cargo) - `Cargo.toml` — `[workspace.package] version` -- `src/nanvix_sandbox/Cargo.toml` — `[package] version` (excluded from workspace, must be updated manually) All other workspace member crates inherit the version automatically. diff --git a/docs/end-user-overview-slides.md b/docs/end-user-overview-slides.md index bcff6a5..eb48c8b 100644 --- a/docs/end-user-overview-slides.md +++ b/docs/end-user-overview-slides.md @@ -111,19 +111,7 @@ result = sandbox.run('console.log(2 + 3)') --- -# Guest Support: Nanvix & Extensibility - -## Nanvix guests (Rust API) - -```rust -// JavaScript via QuickJS in a Nanvix microkernel -let mut sandbox = SandboxBuilder::new().guest(NanvixJavaScript).build()?; -let result = sandbox.run(r#"console.log("Hello from Nanvix!")"#)?; - -// Python via Python in a Nanvix microkernel -let mut sandbox = SandboxBuilder::new().guest(NanvixPython).build()?; -let result = sandbox.run(r#"print("Hello from Nanvix!")"#)?; -``` +# Guest Support & Extensibility ## Broader Wasm/WASI guest model diff --git a/src/nanvix_sandbox/Cargo.lock b/src/nanvix_sandbox/Cargo.lock deleted file mode 100644 index e098017..0000000 --- a/src/nanvix_sandbox/Cargo.lock +++ /dev/null @@ -1,4454 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59317f77929f0e679d39364702289274de2f0f0b22cbf50b2b8cff2169a0b27a" -dependencies = [ - "gimli", -] - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "ambient-authority" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.61.2", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" - -[[package]] -name = "arch" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "cfg-if", - "config", - "error", - "static_assert", - "sys", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "aws-lc-rs" -version = "1.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa7e52a4c5c547c741610a2c6f123f3881e409b714cd27e6798ef020c514f0a" -dependencies = [ - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - -[[package]] -name = "blake3" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "cpufeatures", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" -dependencies = [ - "allocator-api2", -] - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "cap-fs-ext" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" -dependencies = [ - "cap-primitives 3.4.5", - "cap-std 3.4.5", - "io-lifetimes 2.0.4", - "windows-sys 0.52.0", -] - -[[package]] -name = "cap-net-ext" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" -dependencies = [ - "cap-primitives 3.4.5", - "cap-std 3.4.5", - "rustix 1.1.4", - "smallvec", -] - -[[package]] -name = "cap-primitives" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" -dependencies = [ - "ambient-authority", - "fs-set-times", - "io-extras 0.18.4", - "io-lifetimes 2.0.4", - "ipnet", - "maybe-owned", - "rustix 1.1.4", - "rustix-linux-procfs", - "windows-sys 0.52.0", - "winx", -] - -[[package]] -name = "cap-primitives" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdadbd7c002d3a484b35243669abdae85a0ebaded5a61117169dc3400f9a7ff0" -dependencies = [ - "ambient-authority", - "fs-set-times", - "io-extras 0.19.0", - "io-lifetimes 3.0.1", - "ipnet", - "maybe-owned", - "rustix 1.1.4", - "rustix-linux-procfs", - "windows-sys 0.61.2", - "winx", -] - -[[package]] -name = "cap-rand" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8144c22e24bbcf26ade86cb6501a0916c46b7e4787abdb0045a467eb1645a1d" -dependencies = [ - "ambient-authority", - "rand 0.8.6", -] - -[[package]] -name = "cap-std" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6dc3090992a735d23219de5c204927163d922f42f575a0189b005c62d37549a" -dependencies = [ - "cap-primitives 3.4.5", - "io-extras 0.18.4", - "io-lifetimes 2.0.4", - "rustix 1.1.4", -] - -[[package]] -name = "cap-std" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7281235d6e96d3544ca18bba9049be92f4190f8d923e3caef1b5f66cfa752608" -dependencies = [ - "cap-primitives 4.0.2", - "io-extras 0.19.0", - "io-lifetimes 3.0.1", - "rustix 1.1.4", -] - -[[package]] -name = "cap-time-ext" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def102506ce40c11710a9b16e614af0cde8e76ae51b1f48c04b8d79f4b671a80" -dependencies = [ - "ambient-authority", - "cap-primitives 3.4.5", - "iana-time-zone", - "once_cell", - "rustix 1.1.4", - "winx", -] - -[[package]] -name = "cc" -version = "1.2.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" -dependencies = [ - "find-msvc-tools", - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" -dependencies = [ - "iana-time-zone", - "num-traits", - "windows-link", -] - -[[package]] -name = "clap" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" - -[[package]] -name = "cmake" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" -dependencies = [ - "cc", -] - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror 2.0.18", -] - -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "config" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "constant_time_eq" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" - -[[package]] -name = "control-plane-api" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "config", - "num_enum", - "syslog", - "tokio", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpp_demangle" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "cranelift-assembler-x64" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb5bdd1af46714e3224a017fabbbd57f70df4e840eb5ad6a7429dc456119d6" -dependencies = [ - "cranelift-assembler-x64-meta", -] - -[[package]] -name = "cranelift-assembler-x64-meta" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a819599186e1b1a1f88d464e06045696afc7aa3e0cc018aa0b2999cb63d1d088" -dependencies = [ - "cranelift-srcgen", -] - -[[package]] -name = "cranelift-bforest" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e2c152d488e03c87b913bc2ed3414416eb1e0d66d61b49af60bf456a9665c7" -dependencies = [ - "cranelift-entity", - "wasmtime-internal-core", -] - -[[package]] -name = "cranelift-bitset" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6559d4fbc253d1396e1f6beeae57fa88a244f02aaf0cde2a735afd3492d9b2e" -dependencies = [ - "serde", - "serde_derive", - "wasmtime-internal-core", -] - -[[package]] -name = "cranelift-codegen" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d9315d98d6e0a64454d4c83be2ee0e8055c3f80c3b2d7bcad7079f281a06ff" -dependencies = [ - "bumpalo", - "cranelift-assembler-x64", - "cranelift-bforest", - "cranelift-bitset", - "cranelift-codegen-meta", - "cranelift-codegen-shared", - "cranelift-control", - "cranelift-entity", - "cranelift-isle", - "gimli", - "hashbrown 0.16.1", - "libm", - "log", - "pulley-interpreter", - "regalloc2", - "rustc-hash", - "serde", - "smallvec", - "target-lexicon", - "wasmtime-internal-core", -] - -[[package]] -name = "cranelift-codegen-meta" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89c00a88081c55e3087c45bebc77e0cc973de2d7b44ef6a943c7122647b89f5" -dependencies = [ - "cranelift-assembler-x64-meta", - "cranelift-codegen-shared", - "cranelift-srcgen", - "heck", - "pulley-interpreter", -] - -[[package]] -name = "cranelift-codegen-shared" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f77c497a1eb6273482aa1ac3b23cb8563ff04edb39ed5dfcfd28c8deff8f5" - -[[package]] -name = "cranelift-control" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "498dc1f17a6910c88316d49c7176d8fa97cf10c30859c32a266040449317f963" -dependencies = [ - "arbitrary", -] - -[[package]] -name = "cranelift-entity" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2acba797f6a46042ce82aaf7680d0c3567fe2001e238db9df649fd104a2727f" -dependencies = [ - "cranelift-bitset", - "serde", - "serde_derive", - "wasmtime-internal-core", -] - -[[package]] -name = "cranelift-frontend" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dca3df1d107d98d88f159ad1d5eaa2d5cdb678b3d5bcfadc6fc83d8ebb448ea" -dependencies = [ - "cranelift-codegen", - "log", - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cranelift-isle" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f62dd18116d88bed649871feceda79dad7b59cc685ea8998c2b3e64d0e689602" - -[[package]] -name = "cranelift-native" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f843b80360d7fdf61a6124642af7597f6d55724cf521210c34af8a1c66daca6e" -dependencies = [ - "cranelift-codegen", - "libc", - "target-lexicon", -] - -[[package]] -name = "cranelift-srcgen" -version = "0.131.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090ee5de58c6f17eb5e3a5ae8cf1695c7efea04ec4dd0ecba6a5b996c9bad7dc" - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.2", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "elfcore" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdaa3d1c27119b3394513f4596894a40cd53cb4acec7fce636a9ca0c4abb171" -dependencies = [ - "libc", - "nix", - "smallvec", - "thiserror 2.0.18", - "tracing", - "zerocopy", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "error" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "sysapi", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fd-lock" -version = "4.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" -dependencies = [ - "cfg-if", - "rustix 1.1.4", - "windows-sys 0.52.0", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flatbuffers" -version = "25.12.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" -dependencies = [ - "bitflags 2.11.0", - "rustc_version", -] - -[[package]] -name = "flexi_logger" -version = "0.31.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aea7feddba9b4e83022270d49a58d4a1b3fdad04b34f78cf1ce471f698e42672" -dependencies = [ - "chrono", - "log", - "nu-ansi-term", - "regex", - "thiserror 2.0.18", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foldhash" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs-set-times" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" -dependencies = [ - "io-lifetimes 2.0.4", - "rustix 1.1.4", - "windows-sys 0.52.0", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" - -[[package]] -name = "futures-io" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" - -[[package]] -name = "futures-sink" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" - -[[package]] -name = "futures-task" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" - -[[package]] -name = "futures-util" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" -dependencies = [ - "futures-core", - "futures-sink", - "futures-task", - "pin-project-lite", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi 5.3.0", - "wasip2", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", -] - -[[package]] -name = "gimli" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e16c5073773ccf057c282be832a59ee53ef5ff98db3aeff7f8314f52ffc196" -dependencies = [ - "fnv", - "hashbrown 0.16.1", - "indexmap", - "stable_deref_trait", -] - -[[package]] -name = "globset" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "goblin" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983a6aafb3b12d4c41ea78d39e189af4298ce747353945ff5105b54a056e5cd9" -dependencies = [ - "log", - "plain", - "scroll", -] - -[[package]] -name = "h2" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "half" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -dependencies = [ - "foldhash 0.2.0", - "serde", - "serde_core", -] - -[[package]] -name = "hashbrown" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" -dependencies = [ - "foldhash 0.2.0", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "http" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" -dependencies = [ - "bytes", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hwloc" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "libc", - "serde", - "syslog", -] - -[[package]] -name = "hyper" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-layer", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "hyperlight-common" -version = "0.12.0" -source = "git+https://github.com/nanvix/hyperlight?branch=nanvix%2Fv0.12.0#fd41035ec5218fe13a0feeb5e1649ec112b810c9" -dependencies = [ - "anyhow", - "flatbuffers", - "log", - "spin 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "hyperlight-host" -version = "0.12.0" -source = "git+https://github.com/nanvix/hyperlight?branch=nanvix%2Fv0.12.0#fd41035ec5218fe13a0feeb5e1649ec112b810c9" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "blake3", - "cfg-if", - "cfg_aliases", - "crossbeam-channel", - "elfcore", - "flatbuffers", - "goblin", - "hyperlight-common", - "kvm-bindings", - "kvm-ioctls", - "lazy_static", - "libc", - "log", - "metrics", - "mshv-bindings", - "mshv-ioctls", - "page_size", - "rand 0.9.2", - "rust-embed", - "serde_json", - "sha256", - "termcolor", - "thiserror 2.0.18", - "tracing", - "tracing-core", - "tracing-log", - "uuid", - "vmm-sys-util", - "windows", - "windows-result", - "windows-sys 0.61.2", - "windows-version", -] - -[[package]] -name = "hyperlight-nanvix" -version = "0.1.0" -source = "git+https://github.com/hyperlight-dev/hyperlight-nanvix?rev=f4bc205a40ed072cbb5f26b141498477985782f7#f4bc205a40ed072cbb5f26b141498477985782f7" -dependencies = [ - "anyhow", - "clap", - "dirs", - "libc", - "nanvix", - "tokio", -] - -[[package]] -name = "hyperlight-nanvix-sandbox" -version = "0.3.0" -dependencies = [ - "anyhow", - "hyperlight-nanvix", - "hyperlight-sandbox", - "tempfile", - "tokio", -] - -[[package]] -name = "hyperlight-sandbox" -version = "0.3.0" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "bytes", - "cap-std 4.0.2", - "http", - "http-body-util", - "hyper", - "hyper-util", - "log", - "serde", - "serde_json", - "tempfile", - "tokio", - "url", - "wasmtime-wasi-http", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" -dependencies = [ - "equivalent", - "hashbrown 0.17.0", - "serde", - "serde_core", -] - -[[package]] -name = "io-extras" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" -dependencies = [ - "io-lifetimes 2.0.4", - "windows-sys 0.52.0", -] - -[[package]] -name = "io-extras" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f" -dependencies = [ - "io-lifetimes 3.0.1", - "windows-sys 0.60.2", -] - -[[package]] -name = "io-lifetimes" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" - -[[package]] -name = "io-lifetimes" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96" - -[[package]] -name = "ipnet" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" -dependencies = [ - "getrandom 0.3.4", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "kvm-bindings" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3c06ff73c7ce03e780887ec2389d62d2a2a9ddf471ab05c2ff69207cd3f3b4" -dependencies = [ - "serde", - "vmm-sys-util", - "zerocopy", -] - -[[package]] -name = "kvm-ioctls" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333f77a20344a448f3f70664918135fddeb804e938f28a99d685bd92926e0b19" -dependencies = [ - "bitflags 2.11.0", - "kvm-bindings", - "libc", - "vmm-sys-util", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.183" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - -[[package]] -name = "libredox" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" -dependencies = [ - "libc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "linuxd" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "config", - "control-plane-api", - "libc", - "profiler", - "rand 0.9.2", - "signal-hook", - "static_assert", - "sys", - "sysapi", - "syscall", - "syscomm", - "syslog", - "tokio", - "user-vm-api", -] - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "mach2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" -dependencies = [ - "libc", -] - -[[package]] -name = "maybe-owned" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "memfd" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" -dependencies = [ - "rustix 1.1.4", -] - -[[package]] -name = "metrics" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5312e9ba3771cfa961b585728215e3d972c950a3eed9252aa093d6301277e8" -dependencies = [ - "ahash", - "portable-atomic", -] - -[[package]] -name = "mio" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.61.2", -] - -[[package]] -name = "mshv-bindings" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbfd4f32d185152003679339751839da77c17e18fa8882a11051a236f841426" -dependencies = [ - "libc", - "num_enum", - "vmm-sys-util", - "zerocopy", -] - -[[package]] -name = "mshv-ioctls" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f035616abe1e4cbc026a1a8094ff8d3900f5063fe6608309098bc745926fdfd8" -dependencies = [ - "libc", - "mshv-bindings", - "thiserror 2.0.18", - "vmm-sys-util", -] - -[[package]] -name = "nanvix" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "config", - "hwloc", - "linuxd", - "nanvix-http", - "nanvix-registry", - "nanvix-sandbox", - "nanvix-sandbox-cache", - "nanvix-terminal", - "syscomm", - "syslog", - "uservm", -] - -[[package]] -name = "nanvix-http" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "config", - "http", - "http-body-util", - "hyper", - "hyper-util", - "linuxd", - "nanvix-registry", - "nanvix-sandbox-cache", - "nanvix-terminal", - "serde", - "serde_json", - "syscomm", - "syslog", - "tokio", - "user-vm-api", - "uservm", -] - -[[package]] -name = "nanvix-registry" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "bytes", - "dirs", - "reqwest", - "serde", - "serde_json", - "sha2", - "syslog", - "tokio", - "uuid", -] - -[[package]] -name = "nanvix-sandbox" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "cfg-if", - "config", - "control-plane-api", - "hwloc", - "libc", - "linuxd", - "rand 0.9.2", - "sys", - "syscomm", - "syslog", - "tokio", - "user-vm-api", - "uservm", -] - -[[package]] -name = "nanvix-sandbox-cache" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "config", - "nanvix-sandbox", - "rand 0.9.2", - "syslog", - "tokio", -] - -[[package]] -name = "nanvix-terminal" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "libc", - "nanvix-sandbox-cache", - "syslog", - "tokio", - "user-vm-api", -] - -[[package]] -name = "nix" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" -dependencies = [ - "bitflags 2.11.0", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "object" -version = "0.39.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" -dependencies = [ - "crc32fast", - "hashbrown 0.17.0", - "indexmap", - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "page_size" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - -[[package]] -name = "portable-atomic" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "profiler" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "cfg-if", - "syslog", -] - -[[package]] -name = "pulley-interpreter" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df866b7fd522992ccc6682e58b2741cc7972b163b661db24c4328f4c914cb09d" -dependencies = [ - "cranelift-bitset", - "log", - "pulley-macros", - "wasmtime-internal-core", -] - -[[package]] -name = "pulley-macros" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7dfa8354acc622b3857e1bb1a4e4315d3bc1a44ad31d5653c3e87c0da9306d7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.60.2", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "rand" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.11.0", -] - -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror 2.0.18", -] - -[[package]] -name = "regalloc2" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952ddbfc6f9f64d006c3efd8c9851a6ba2f2b944ba94730db255d55006e0ffda" -dependencies = [ - "allocator-api2", - "bumpalo", - "hashbrown 0.15.5", - "log", - "rustc-hash", - "smallvec", -] - -[[package]] -name = "regex" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" - -[[package]] -name = "reqwest" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" -dependencies = [ - "base64", - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "rustls-platform-verifier", - "serde", - "serde_json", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rust-embed" -version = "8.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27" -dependencies = [ - "rust-embed-impl", - "rust-embed-utils", - "walkdir", -] - -[[package]] -name = "rust-embed-impl" -version = "8.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa" -dependencies = [ - "proc-macro2", - "quote", - "rust-embed-utils", - "shellexpand", - "syn", - "walkdir", -] - -[[package]] -name = "rust-embed-utils" -version = "8.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1" -dependencies = [ - "globset", - "sha2", - "walkdir", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.11.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags 2.11.0", - "errno", - "libc", - "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustix-linux-procfs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" -dependencies = [ - "once_cell", - "rustix 1.1.4", -] - -[[package]] -name = "rustls" -version = "0.23.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" -dependencies = [ - "aws-lc-rs", - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-platform-verifier" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scroll" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.10.1", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha256" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6" -dependencies = [ - "async-trait", - "bytes", - "hex", - "sha2", - "tokio", -] - -[[package]] -name = "shellexpand" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" -dependencies = [ - "dirs", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b57709da74f9ff9f4a27dce9526eec25ca8407c45a7887243b031a58935fb8e" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "slab" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -dependencies = [ - "serde", -] - -[[package]] -name = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "spin" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spin" -version = "0.10.0" -source = "git+https://github.com/nanvix/spin-rs?branch=nanvix%2Fv0.10.0#ec00ed314406d2cc8313ef72c06178619ee0b48c" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assert" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sys" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "config", - "error", - "static_assert", -] - -[[package]] -name = "sysapi" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "config", - "static_assert", -] - -[[package]] -name = "syscall" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "arch", - "cfg-if", - "config", - "spin 0.10.0 (git+https://github.com/nanvix/spin-rs?branch=nanvix%2Fv0.10.0)", - "static_assert", - "sys", - "sysapi", - "type-safe", -] - -[[package]] -name = "syscomm" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "config", - "libc", - "num_enum", - "syslog", - "tokio", -] - -[[package]] -name = "syslog" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "flexi_logger", - "log", - "syslog-macros", -] - -[[package]] -name = "syslog-macros" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "system-configuration" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" -dependencies = [ - "bitflags 2.11.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "system-interface" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" -dependencies = [ - "bitflags 2.11.0", - "cap-fs-ext", - "cap-std 3.4.5", - "fd-lock", - "io-lifetimes 2.0.4", - "rustix 0.38.44", - "windows-sys 0.52.0", - "winx", -] - -[[package]] -name = "target-lexicon" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix 1.1.4", - "windows-sys 0.61.2", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl 2.0.18", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" -dependencies = [ - "bitflags 2.11.0", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "type-safe" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "user-vm-api" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "config", - "serde", - "syscomm", - "syslog", - "tokio", -] - -[[package]] -name = "uservm" -version = "0.11.133" -source = "git+https://github.com/nanvix/nanvix?rev=cc9c508918bd17678e9d790f10a6a7c20b7902da#cc9c508918bd17678e9d790f10a6a7c20b7902da" -dependencies = [ - "anyhow", - "arch", - "cfg-if", - "config", - "control-plane-api", - "hyperlight-host", - "kvm-bindings", - "kvm-ioctls", - "libc", - "profiler", - "serde", - "serde_cbor", - "static_assert", - "sys", - "syscall", - "syscomm", - "syslog", - "tokio", - "user-vm-api", - "vmm-sys-util", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" -dependencies = [ - "getrandom 0.4.2", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "vmm-sys-util" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "506c62fdf617a5176827c2f9afbcf1be155b03a9b4bf9617a60dbc07e3a1642f" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" -dependencies = [ - "cfg-if", - "futures-util", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser 0.244.0", -] - -[[package]] -name = "wasm-encoder" -version = "0.246.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fb705ce81adde29d2a8e99d87995e39a6e927358c91398f374474746070ef7" -dependencies = [ - "leb128fmt", - "wasmparser 0.246.2", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder 0.244.0", - "wasmparser 0.244.0", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - -[[package]] -name = "wasmparser" -version = "0.246.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71cde4757396defafd25417cfb36aa3161027d06d865b0c24baaae229aac005d" -dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.16.1", - "indexmap", - "semver", - "serde", -] - -[[package]] -name = "wasmprinter" -version = "0.246.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e41f7493ba994b8a779430a4c25ff550fd5a40d291693af43a6ef48688f00e3" -dependencies = [ - "anyhow", - "termcolor", - "wasmparser 0.246.2", -] - -[[package]] -name = "wasmtime" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca3f777dfb4db45915f95eeb25cac7f2eeb268797a27e5eb78b072618135c7f" -dependencies = [ - "addr2line", - "async-trait", - "bitflags 2.11.0", - "bumpalo", - "cc", - "cfg-if", - "encoding_rs", - "libc", - "log", - "mach2", - "memfd", - "object", - "once_cell", - "postcard", - "pulley-interpreter", - "rustix 1.1.4", - "semver", - "serde", - "serde_derive", - "smallvec", - "target-lexicon", - "wasmparser 0.246.2", - "wasmtime-environ", - "wasmtime-internal-component-macro", - "wasmtime-internal-component-util", - "wasmtime-internal-core", - "wasmtime-internal-cranelift", - "wasmtime-internal-fiber", - "wasmtime-internal-jit-debug", - "wasmtime-internal-jit-icache-coherence", - "wasmtime-internal-unwinder", - "wasmtime-internal-versioned-export-macros", - "wasmtime-internal-winch", - "windows-sys 0.61.2", -] - -[[package]] -name = "wasmtime-environ" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5ca1af838cec374931242d07af5d354aedf63f297f95b3625ac863e516ef67" -dependencies = [ - "anyhow", - "cpp_demangle", - "cranelift-bforest", - "cranelift-bitset", - "cranelift-entity", - "gimli", - "hashbrown 0.16.1", - "indexmap", - "log", - "object", - "postcard", - "rustc-demangle", - "semver", - "serde", - "serde_derive", - "sha2", - "smallvec", - "target-lexicon", - "wasm-encoder 0.246.2", - "wasmparser 0.246.2", - "wasmprinter", - "wasmtime-internal-component-util", - "wasmtime-internal-core", -] - -[[package]] -name = "wasmtime-internal-component-macro" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58b31927f7b613d8fe019609744e226f6458d8aa5e6289e92fbbc60e521cd026" -dependencies = [ - "anyhow", - "proc-macro2", - "quote", - "syn", - "wasmtime-internal-component-util", - "wasmtime-internal-wit-bindgen", - "wit-parser 0.246.2", -] - -[[package]] -name = "wasmtime-internal-component-util" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc29e3478928b93979831ba02a997ce7f707c673ce47180d643091cf4fa4f561" - -[[package]] -name = "wasmtime-internal-core" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816a61a75275c6be435131fc625a4f5956daf24d9f9f59443e81cbef228929b3" -dependencies = [ - "hashbrown 0.16.1", - "libm", - "serde", -] - -[[package]] -name = "wasmtime-internal-cranelift" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ceb5e079877e7e4565c1e2d86d9db889175d55f7ca0001315576d08c71e634" -dependencies = [ - "cfg-if", - "cranelift-codegen", - "cranelift-control", - "cranelift-entity", - "cranelift-frontend", - "cranelift-native", - "gimli", - "itertools", - "log", - "object", - "pulley-interpreter", - "smallvec", - "target-lexicon", - "thiserror 2.0.18", - "wasmparser 0.246.2", - "wasmtime-environ", - "wasmtime-internal-core", - "wasmtime-internal-unwinder", - "wasmtime-internal-versioned-export-macros", -] - -[[package]] -name = "wasmtime-internal-fiber" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e18f8bb05d25e0d4cca7278147c9f9e2f26f66886ef754b562bf729128f1e537" -dependencies = [ - "cc", - "cfg-if", - "libc", - "rustix 1.1.4", - "wasmtime-environ", - "wasmtime-internal-versioned-export-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "wasmtime-internal-jit-debug" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357f1070b31154ee463937b477ca0b2962bf450b40fc59799bef2f656b15da73" -dependencies = [ - "cc", - "wasmtime-internal-versioned-export-macros", -] - -[[package]] -name = "wasmtime-internal-jit-icache-coherence" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd683a94490bf755d016a09697b0955602c50106b1ded97d16983ab2ded9fed" -dependencies = [ - "cfg-if", - "libc", - "wasmtime-internal-core", - "windows-sys 0.61.2", -] - -[[package]] -name = "wasmtime-internal-unwinder" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4471746ce113c3c1862ce2c0674acb35399a4b3ed3ef4531dc087f333c74f064" -dependencies = [ - "cfg-if", - "cranelift-codegen", - "log", - "object", - "wasmtime-environ", -] - -[[package]] -name = "wasmtime-internal-versioned-export-macros" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6af582ec18b674bf7a17775d6fbfbddfcc143f0edbd89c9c1778239c8aa92ed" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "wasmtime-internal-winch" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31be8916bb60ea756d2f0ae1f634d9258442aa71e773c893e2f4cead30501b5" -dependencies = [ - "cranelift-codegen", - "gimli", - "log", - "object", - "target-lexicon", - "wasmparser 0.246.2", - "wasmtime-environ", - "wasmtime-internal-cranelift", - "winch-codegen", -] - -[[package]] -name = "wasmtime-internal-wit-bindgen" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2150e63d502ab2d64754e5abe8eb737ae674b7dd4ad53144fd16bbeceaf4a19" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "heck", - "indexmap", - "wit-parser 0.246.2", -] - -[[package]] -name = "wasmtime-wasi" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f5109b4fd619b9796b9c9901de59d83e3575cd1226c1a36d1901371f43db28" -dependencies = [ - "async-trait", - "bitflags 2.11.0", - "bytes", - "cap-fs-ext", - "cap-net-ext", - "cap-rand", - "cap-std 3.4.5", - "cap-time-ext", - "fs-set-times", - "futures", - "io-extras 0.18.4", - "io-lifetimes 2.0.4", - "rustix 1.1.4", - "system-interface", - "thiserror 2.0.18", - "tokio", - "tracing", - "url", - "wasmtime", - "wasmtime-wasi-io", - "windows-sys 0.61.2", -] - -[[package]] -name = "wasmtime-wasi-http" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5798e6e48005406983ba6a7b27f3832f1571e53f1401ef2d60111c96eab534b4" -dependencies = [ - "async-trait", - "bytes", - "futures", - "http", - "http-body", - "http-body-util", - "hyper", - "rustls", - "tokio", - "tokio-rustls", - "tracing", - "wasmtime", - "wasmtime-wasi", - "wasmtime-wasi-io", - "webpki-roots 0.26.11", -] - -[[package]] -name = "wasmtime-wasi-io" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ebe14c586e98d2fdc32c76ca0005ef28348e98ed737e776d378b3b0cc2afd0" -dependencies = [ - "async-trait", - "bytes", - "futures", - "tracing", - "wasmtime", -] - -[[package]] -name = "web-sys" -version = "0.3.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-root-certs" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.6", -] - -[[package]] -name = "webpki-roots" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "winch-codegen" -version = "44.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9339858ad222412200fd8b1af9e270712201aaec440c7618991443af3446481f" -dependencies = [ - "cranelift-assembler-x64", - "cranelift-codegen", - "gimli", - "regalloc2", - "smallvec", - "target-lexicon", - "thiserror 2.0.18", - "wasmparser 0.246.2", - "wasmtime-environ", - "wasmtime-internal-core", - "wasmtime-internal-cranelift", -] - -[[package]] -name = "windows" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" -dependencies = [ - "windows-core", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" -dependencies = [ - "windows-core", - "windows-link", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" -dependencies = [ - "windows-core", - "windows-link", -] - -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows-threading" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-version" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "winx" -version = "0.36.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" -dependencies = [ - "bitflags 2.11.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser 0.244.0", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.0", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder 0.244.0", - "wasm-metadata", - "wasmparser 0.244.0", - "wit-parser 0.244.0", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser 0.244.0", -] - -[[package]] -name = "wit-parser" -version = "0.246.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd979042b5ff288607ccf3b314145435453f20fc67173195f91062d2289b204d" -dependencies = [ - "anyhow", - "hashbrown 0.16.1", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser 0.246.2", -] - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/src/nanvix_sandbox/Cargo.toml b/src/nanvix_sandbox/Cargo.toml deleted file mode 100644 index 0d01b50..0000000 --- a/src/nanvix_sandbox/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "hyperlight-nanvix-sandbox" -version = "0.4.0" -edition = "2021" -license = "Apache-2.0" -description = "Nanvix microkernel sandbox backend for hyperlight-sandbox" - -[dependencies] -hyperlight-sandbox = { path = "../hyperlight_sandbox" } -hyperlight-nanvix = { git = "https://github.com/hyperlight-dev/hyperlight-nanvix", rev = "f4bc205a40ed072cbb5f26b141498477985782f7" } -anyhow = "1" -tokio = { version = "1", features = ["rt-multi-thread"] } -tempfile = "3" diff --git a/src/nanvix_sandbox/Justfile b/src/nanvix_sandbox/Justfile deleted file mode 100644 index a2d0d37..0000000 --- a/src/nanvix_sandbox/Justfile +++ /dev/null @@ -1,16 +0,0 @@ -repo-root := invocation_directory_native() -nanvix-rev := "f4bc205a40ed072cbb5f26b141498477985782f7" -skip-msg := "echo 'Skipping nanvix (not supported on Windows)'" - -build: - {{ if os() == "windows" { skip-msg } else { "cd " + repo-root + "/src/nanvix_sandbox && cargo +nightly build" } }} - -setup-registry: - {{ if os() == "windows" { skip-msg } else { "@command -v hyperlight-nanvix >/dev/null 2>&1 || cargo +nightly install --git https://github.com/hyperlight-dev/hyperlight-nanvix --rev " + nanvix-rev + "\n hyperlight-nanvix setup-registry" } }} - -#### EXAMPLES #### - -nanvix-sandbox-example: setup-registry - {{ if os() == "windows" { skip-msg } else { "cd " + repo-root + "/src/nanvix_sandbox && cargo +nightly run --example hello" } }} - -examples: nanvix-sandbox-example diff --git a/src/nanvix_sandbox/examples/hello.rs b/src/nanvix_sandbox/examples/hello.rs deleted file mode 100644 index 5fb3e87..0000000 --- a/src/nanvix_sandbox/examples/hello.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! Example: run JavaScript and Python code in a Nanvix microkernel sandbox. - -use hyperlight_nanvix_sandbox::{NanvixJavaScript, NanvixPython}; -use hyperlight_sandbox::{Sandbox, SandboxBuilder}; - -fn main() { - // --- JavaScript --- - println!("=== Nanvix JavaScript Sandbox ===\n"); - let mut js_sandbox = match SandboxBuilder::new() - .guest(NanvixJavaScript) - .build() - { - Ok(s) => s, - Err(e) => { - eprintln!("Failed to create JS sandbox: {e:#}"); - std::process::exit(1); - } - }; - - println!("--- Test 1: Basic JS execution ---"); - match js_sandbox.run( - r#" -console.log("Hello from JavaScript in Nanvix!"); -console.log("2 + 3 =", 2 + 3); -"#, - ) { - Ok(result) => { - assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); - assert!( - result.stdout.contains("Hello from JavaScript in Nanvix!"), - "stdout was {:?}", - result.stdout - ); - assert!( - result.stdout.contains("2 + 3 = 5"), - "stdout was {:?}", - result.stdout - ); - println!("stdout: {:?}", result.stdout); - println!("exit_code: {}", result.exit_code); - } - Err(e) => panic!("Test 1 failed: {e}"), - } - - // --- Python --- - println!("\n=== Nanvix Python Sandbox ===\n"); - let mut py_sandbox = match SandboxBuilder::new() - .guest(NanvixPython) - .build() - { - Ok(s) => s, - Err(e) => { - eprintln!("Failed to create Python sandbox: {e:#}"); - std::process::exit(1); - } - }; - - println!("--- Test 2: Basic Python execution ---"); - match py_sandbox.run( - r#" -print("Hello from Python in Nanvix!") -print(f"2 + 3 = {2 + 3}") -"#, - ) { - Ok(result) => { - assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); - assert!( - result.stdout.contains("Hello from Python in Nanvix!"), - "stdout was {:?}", - result.stdout - ); - assert!( - result.stdout.contains("2 + 3 = 5"), - "stdout was {:?}", - result.stdout - ); - println!("stdout: {:?}", result.stdout); - println!("exit_code: {}", result.exit_code); - } - Err(e) => panic!("Test 2 failed: {e}"), - } - - // --- Snapshot (unsupported) --- - println!("\n--- Test 3: Snapshot (expected to fail) ---"); - match js_sandbox.snapshot() { - Ok(_) => panic!("Snapshot should not succeed on Nanvix!"), - Err(e) => println!("Snapshot correctly unsupported: {e}"), - } - - println!("\n\u{2705} All tests passed!"); -} diff --git a/src/nanvix_sandbox/src/lib.rs b/src/nanvix_sandbox/src/lib.rs deleted file mode 100644 index abe4626..0000000 --- a/src/nanvix_sandbox/src/lib.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! Nanvix microkernel sandbox backend for hyperlight-sandbox. -//! -//! Runs JavaScript or Python workloads inside a Nanvix microkernel VM. -//! -//! **Limitations** compared to the Wasm/JS sandbox backends: -//! - No host function / tool dispatch (guest code cannot call `call_tool`) -//! - No snapshot/restore -//! - File I/O and network are not available through the sandbox API -//! - Output is captured from a guest console log file, not from WASI streams -//! -//! Supported: -//! - Basic code execution (JS via QuickJS, Python via CPython) -//! - stdout capture from the guest console log - -use std::io::Write; - -use anyhow::{Context, Result}; -use hyperlight_nanvix::{RuntimeConfig, Sandbox as NanvixSandboxInner, WorkloadType}; -use hyperlight_sandbox::{ - ExecutionResult, Guest, GuestSandbox, SandboxConfig, Snapshot, ToolRegistry, -}; - -// --------------------------------------------------------------------------- -// Guest types -// --------------------------------------------------------------------------- - -/// Guest type for running JavaScript via QuickJS in a Nanvix microkernel. -#[derive(Debug, Clone, Copy, Default)] -pub struct NanvixJavaScript; - -impl Guest for NanvixJavaScript { - type Sandbox = NanvixSandbox; - fn build( - self, - _config: SandboxConfig, - _tools: ToolRegistry, - _network: std::sync::Arc>, - _fs: std::sync::Arc>, - ) -> Result { - NanvixSandbox::new(WorkloadType::JavaScript) - } -} - -/// Guest type for running Python via CPython in a Nanvix microkernel. -#[derive(Debug, Clone, Copy, Default)] -pub struct NanvixPython; - -impl Guest for NanvixPython { - type Sandbox = NanvixSandbox; - fn build( - self, - _config: SandboxConfig, - _tools: ToolRegistry, - _network: std::sync::Arc>, - _fs: std::sync::Arc>, - ) -> Result { - NanvixSandbox::new(WorkloadType::Python) - } -} - -// --------------------------------------------------------------------------- -// Sandbox implementation -// --------------------------------------------------------------------------- - -pub struct NanvixSandbox { - workload_type: WorkloadType, - runtime_config: RuntimeConfig, - /// Tokio runtime for async nanvix API - rt: tokio::runtime::Runtime, -} - -impl NanvixSandbox { - fn new(workload_type: WorkloadType) -> Result { - let rt = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .context("failed to create tokio runtime")?; - - Ok(Self { - workload_type, - runtime_config: RuntimeConfig::default(), - rt, - }) - } - - fn file_extension(&self) -> &'static str { - match self.workload_type { - WorkloadType::JavaScript => "js", - WorkloadType::Python => "py", - WorkloadType::Binary => "elf", - } - } -} - -/// Unit type used as snapshot data for backends that don't support snapshotting. -pub struct NoSnapshot; - -impl GuestSandbox for NanvixSandbox { - type SnapshotData = NoSnapshot; - - fn run(&mut self, code: &str) -> Result { - // Write code to a temporary file - let mut tmp = tempfile::Builder::new() - .suffix(&format!(".{}", self.file_extension())) - .tempfile() - .context("failed to create temp file for guest code")?; - tmp.write_all(code.as_bytes()) - .context("failed to write guest code")?; - tmp.flush()?; - - let tmp_path = tmp.path().to_path_buf(); - let config = self.runtime_config.clone(); - let console_log_path = format!("{}/guest-console.log", &config.log_directory); - - // Run the workload - let run_result = self.rt.block_on(async { - let mut sandbox = NanvixSandboxInner::new(config)?; - sandbox.run(&tmp_path).await - }); - - // Read captured console output - let stdout = std::fs::read_to_string(&console_log_path).unwrap_or_default(); - - // Clean up log directory - let _ = std::fs::remove_dir_all(&self.runtime_config.log_directory); - // Rotate to a fresh config for the next run - self.runtime_config = RuntimeConfig::default(); - - match run_result { - Ok(()) => Ok(ExecutionResult { - stdout, - stderr: String::new(), - exit_code: 0, - }), - Err(e) => Ok(ExecutionResult { - stdout, - stderr: format!("{e:#}"), - exit_code: 1, - }), - } - } - - fn snapshot(&mut self) -> Result> { - Err(anyhow::anyhow!( - "snapshot is not supported by the Nanvix sandbox" - )) - } - - fn restore(&mut self, _snapshot: &Snapshot) -> Result<()> { - Err(anyhow::anyhow!( - "restore is not supported by the Nanvix sandbox" - )) - } -} From eeda74d7032b4d07902048963d8baa66962fe8f9 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Wed, 13 May 2026 16:02:21 +0100 Subject: [PATCH 02/11] Add scoped credentials WIT interface Adds hyperlight:sandbox/credentials, a new interface for scoped credential injection in outgoing HTTP requests. Hosts register named credentials with a target URL scope, header name, value prefix and a resolver callback. Guests attach a credential by name to an outgoing-request before dispatch; the host injects the header at handle() time after verifying scope. Secret values never cross the WIT boundary. The new interface is imported by both the root world (componentize-py Python guests) and the inner sandbox world (own-shim guests). Signed-off-by: Simon Davies --- src/wasm_sandbox/wit/hyperlight-sandbox.wit | 46 +++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/wasm_sandbox/wit/hyperlight-sandbox.wit b/src/wasm_sandbox/wit/hyperlight-sandbox.wit index 5adc2cf..345b4e7 100644 --- a/src/wasm_sandbox/wit/hyperlight-sandbox.wit +++ b/src/wasm_sandbox/wit/hyperlight-sandbox.wit @@ -35,6 +35,7 @@ world root { import wasi:http/types@0.2.0; import wasi:http/outgoing-handler@0.2.0; import hyperlight:sandbox/tools; + import hyperlight:sandbox/credentials; export hyperlight:sandbox/executor; } @@ -54,9 +55,54 @@ package hyperlight:sandbox { dispatch: func(name: string, args-json: string) -> result; } + /// Scoped credential injection for outgoing HTTP requests. + /// + /// A credential is registered host-side with: + /// * a name (opaque string the guest uses to reference it), + /// * a target scope (URL prefix the credential is bound to), + /// * a header name + value prefix, + /// * a resolver callback that produces the secret value. + /// + /// The guest never sees the secret. It attaches a credential by name to an + /// `outgoing-request` before dispatching it through + /// `wasi:http/outgoing-handler`. At dispatch time the host: + /// 1. resolves the credential value (resolver callback), + /// 2. verifies the request URL is within the credential's target scope, + /// 3. injects `
: ` into the request, + /// 4. then proceeds with the normal `allow_domain` network gate. + /// + /// Both the credential scope check AND the allow_domain check must pass. + /// Credential lookup, scope match, resolver errors and unknown credentials + /// all surface as the `credential-error` variant. Secret values are never + /// included in error messages. + interface credentials { + use wasi:http/types@0.2.0.{outgoing-request}; + + variant credential-error { + /// No credential is registered under this name. + unknown, + /// The request URL does not fall within the credential's target scope. + scope-mismatch, + /// The host resolver callback failed. The inner string is a + /// host-redacted message safe for logging. + resolver-failed(string), + /// A credential is already attached to this request. + already-attached, + } + + /// Attach a registered credential to an outgoing-request. + /// The host will inject the credential's header at dispatch time. + /// Returns ok on success, credential-error on failure. + attach: func( + request: borrow, + credential: string, + ) -> result<_, credential-error>; + } + /// Minimal world for guests that bring their own WASI shim (e.g. ComponentizeJS). world sandbox { import tools; + import credentials; import wasi:filesystem/types@0.2.0; import wasi:filesystem/preopens@0.2.0; import wasi:http/types@0.2.0; From 1d806cb3085e3f0b70f98342e5873951fbfa655d Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Wed, 13 May 2026 20:53:35 +0100 Subject: [PATCH 03/11] feat(host): stub Credentials trait impl to keep build green Satisfies the new RootImports trait shape produced by adding `import hyperlight:sandbox/credentials` to the root world. - Add `type Credentials = HostState; fn credentials(...)` to the `RootImports for HostState` impl, mirroring the pattern used for every other imported interface. - Add a stub `impl Credentials> for HostState` whose `attach()` rejects every call with `CredentialError::Unknown`. The stub deliberately makes the API behave as if no credentials are registered yet. This keeps the host-side trait surface satisfied so `just wasm::lint` (cargo clippy) passes after the WIT addition, without silently pretending credential injection works. Guests calling `attach` will get a loud `Unknown` error until the registry, scope match and header-injection paths land in follow-up commits. No registry, no resolver, no outgoing-handler hook in this commit. Signed-off-by: Simon Davies --- src/wasm_sandbox/src/lib.rs | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/wasm_sandbox/src/lib.rs b/src/wasm_sandbox/src/lib.rs index 4d5b681..987e0a7 100644 --- a/src/wasm_sandbox/src/lib.rs +++ b/src/wasm_sandbox/src/lib.rs @@ -50,6 +50,11 @@ impl bindings::root::component::RootImports for HostState { self } + type Credentials = HostState; + fn credentials(&mut self) -> &mut Self { + self + } + type Environment = HostState; fn environment(&mut self) -> &mut Self { self @@ -216,6 +221,49 @@ impl bindings::hyperlight::sandbox::Tools for HostState { } } +// --------------------------------------------------------------------------- +// Scoped credentials — skeleton stub (commit B). +// +// The full design lands in follow-up commits: +// * Credential registry on `HostState` (host-side `register_credential`). +// * `attach` records a request -> credential binding in per-Sandbox state. +// * The outgoing-handler dispatch path consults that binding, calls the +// resolver, enforces the credential's target scope, and injects the +// `
: ` pair before the existing `allow_domain` +// gate runs. +// +// Until then, every `attach` call is rejected with `Unknown` so guests +// fail loudly if they try to use the API before the registry exists. +// This keeps the host-side trait surface satisfied so `cargo check` +// passes after the WIT addition, without silently pretending credentials +// work. +// --------------------------------------------------------------------------- +impl + bindings::hyperlight::sandbox::Credentials< + crate::wasi_impl::resource::Resource< + crate::wasi_impl::types::http_outgoing_request::OutgoingRequest, + >, + > for HostState +{ + fn attach( + &mut self, + _request: hyperlight_common::resource::BorrowedResourceGuard< + '_, + crate::wasi_impl::resource::Resource< + crate::wasi_impl::types::http_outgoing_request::OutgoingRequest, + >, + >, + _credential: String, + ) -> Result< + Result<(), bindings::hyperlight::sandbox::credentials::CredentialError>, + hyperlight_host::HyperlightError, + > { + Ok(Err( + bindings::hyperlight::sandbox::credentials::CredentialError::Unknown, + )) + } +} + pub struct WasmComponentSandbox { sandbox: bindings::RootSandbox, fs: Arc>, From 9553d21ac01525f5645c78faa0aa496bf412e065 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Wed, 13 May 2026 21:53:58 +0100 Subject: [PATCH 04/11] feat(credentials): add registry, attach binding, and host API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the credential registry and functional attach() implementation: - New credentials module with CredentialEntry struct holding target (URL-prefix scope), header name, value prefix, and resolver. - CredentialRegistry type alias (Arc>>) with mpty_registry() constructor. - HostState::register_credential() — host-side-only API for populating the registry before the guest runs. Not exposed via WIT. - Real ttach() impl: validates credential exists in registry, checks for double-attach, writes binding into OutgoingRequest. - \ttached_credential: Option\ field on OutgoingRequest, initialised to None, set by attach(), ready for the outgoing-handler dispatch path to consume in follow-up commits. Error semantics: - Unknown: credential id not found in registry - AlreadyAttached: request already has a credential bound Token resolution and header injection land in commit D/E. Signed-off-by: Simon Davies --- src/wasm_sandbox/src/credentials.rs | 49 ++++++++++++ src/wasm_sandbox/src/lib.rs | 80 ++++++++++++++----- .../wasi_impl/types/http_outgoing_request.rs | 4 + 3 files changed, 115 insertions(+), 18 deletions(-) create mode 100644 src/wasm_sandbox/src/credentials.rs diff --git a/src/wasm_sandbox/src/credentials.rs b/src/wasm_sandbox/src/credentials.rs new file mode 100644 index 0000000..9ae9ab6 --- /dev/null +++ b/src/wasm_sandbox/src/credentials.rs @@ -0,0 +1,49 @@ +//! Scoped-credential registry for outgoing HTTP requests. +//! +//! A [`CredentialEntry`] binds a logical credential identifier to the +//! metadata required to inject a token header at request time: +//! +//! * `target` — URL-prefix scope (e.g. `"https://api.example.com/"`). +//! The outgoing-handler only injects the credential when +//! the request URL starts with this prefix. +//! * `header` — HTTP header name (e.g. `"Authorization"`). +//! * `prefix` — Value prefix prepended to the resolved token +//! (e.g. `"Bearer "`). +//! * `resolver` — Opaque resolver identifier. Today this is a simple +//! string key; a future commit will support async +//! resolution callbacks. +//! +//! The registry lives on [`crate::HostState`] behind +//! `Arc>>` and is populated by +//! the host before the guest runs. Guests bind a credential to a +//! specific outgoing request via the WIT `attach` function. + +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; + +/// Metadata for a single scoped credential. +#[derive(Debug, Clone)] +pub struct CredentialEntry { + /// URL-prefix scope. Only requests whose URL starts with this + /// value are eligible for credential injection. + pub target: String, + + /// HTTP header name to set (e.g. `"Authorization"`). + pub header: String, + + /// Value prefix prepended to the resolved token + /// (e.g. `"Bearer "`). May be empty. + pub prefix: String, + + /// Opaque resolver identifier. The outgoing-handler will use + /// this to obtain the actual secret value at dispatch time. + pub resolver: String, +} + +/// Shared, thread-safe credential registry keyed by credential id. +pub type CredentialRegistry = Arc>>; + +/// Creates an empty credential registry. +pub fn empty_registry() -> CredentialRegistry { + Arc::new(Mutex::new(HashMap::new())) +} diff --git a/src/wasm_sandbox/src/lib.rs b/src/wasm_sandbox/src/lib.rs index 987e0a7..7cbcc9d 100644 --- a/src/wasm_sandbox/src/lib.rs +++ b/src/wasm_sandbox/src/lib.rs @@ -14,6 +14,7 @@ use hyperlight_wasm::{ LoadedWasmSandbox, SandboxBuilder as HyperlightSandboxBuilder, Snapshot as WasmSnapshot, }; +pub mod credentials; mod wasi_impl; pub(crate) mod bindings { @@ -41,6 +42,29 @@ pub struct HostState { pub(crate) fs: Arc>, pub(crate) network: Arc>, pub(crate) active_requests: Arc, + pub(crate) credential_registry: credentials::CredentialRegistry, +} + +impl HostState { + /// Register a scoped credential that guests can later `attach` to + /// outgoing requests. This is a host-side-only API — it is NOT + /// exposed through WIT so guests cannot register their own + /// credentials. + pub fn register_credential( + &self, + id: String, + entry: credentials::CredentialEntry, + ) -> Result<(), String> { + let mut registry = self + .credential_registry + .lock() + .map_err(|_| "credential registry mutex poisoned".to_string())?; + if registry.contains_key(&id) { + return Err(format!("credential '{}' already registered", id)); + } + registry.insert(id, entry); + Ok(()) + } } #[allow(refining_impl_trait)] @@ -222,21 +246,19 @@ impl bindings::hyperlight::sandbox::Tools for HostState { } // --------------------------------------------------------------------------- -// Scoped credentials — skeleton stub (commit B). +// Scoped credentials — `attach` implementation (commit C). // -// The full design lands in follow-up commits: -// * Credential registry on `HostState` (host-side `register_credential`). -// * `attach` records a request -> credential binding in per-Sandbox state. -// * The outgoing-handler dispatch path consults that binding, calls the -// resolver, enforces the credential's target scope, and injects the -// `
: ` pair before the existing `allow_domain` -// gate runs. +// The guest calls `attach(request, credential_id)` to bind a +// previously-registered credential to an outgoing HTTP request. +// This records the binding inside the `OutgoingRequest` itself so +// the outgoing-handler dispatch path can later resolve and inject +// the token header. // -// Until then, every `attach` call is rejected with `Unknown` so guests -// fail loudly if they try to use the API before the registry exists. -// This keeps the host-side trait surface satisfied so `cargo check` -// passes after the WIT addition, without silently pretending credentials -// work. +// Error semantics: +// * `Unknown` — credential id not found in the registry. +// * `AlreadyAttached` — the request already has a credential. +// * `ScopeMismatch` / `ResolverFailed` — reserved for the +// outgoing-handler (commit D/E). // --------------------------------------------------------------------------- impl bindings::hyperlight::sandbox::Credentials< @@ -247,20 +269,41 @@ impl { fn attach( &mut self, - _request: hyperlight_common::resource::BorrowedResourceGuard< + request: hyperlight_common::resource::BorrowedResourceGuard< '_, crate::wasi_impl::resource::Resource< crate::wasi_impl::types::http_outgoing_request::OutgoingRequest, >, >, - _credential: String, + credential: String, ) -> Result< Result<(), bindings::hyperlight::sandbox::credentials::CredentialError>, hyperlight_host::HyperlightError, > { - Ok(Err( - bindings::hyperlight::sandbox::credentials::CredentialError::Unknown, - )) + use bindings::hyperlight::sandbox::credentials::CredentialError; + + use crate::wasi_impl::resource::BlockOn; + + // Verify the credential exists in the host-side registry. + { + let registry = self.credential_registry.lock().map_err(|_| { + hyperlight_host::HyperlightError::Error( + "credential registry mutex poisoned".to_string(), + ) + })?; + if !registry.contains_key(&credential) { + return Ok(Err(CredentialError::Unknown)); + } + } + + // Write the credential binding into the request. + let mut guard = request.write().block_on(); + if guard.attached_credential.is_some() { + return Ok(Err(CredentialError::AlreadyAttached)); + } + guard.attached_credential = Some(credential); + + Ok(Ok(())) } } @@ -292,6 +335,7 @@ impl WasmComponentSandbox { fs: fs.clone(), network: network.clone(), active_requests: Arc::new(AtomicUsize::new(0)), + credential_registry: credentials::empty_registry(), }; let mut proto = HyperlightSandboxBuilder::new() diff --git a/src/wasm_sandbox/src/wasi_impl/types/http_outgoing_request.rs b/src/wasm_sandbox/src/wasi_impl/types/http_outgoing_request.rs index 621e8f3..701aab5 100644 --- a/src/wasm_sandbox/src/wasi_impl/types/http_outgoing_request.rs +++ b/src/wasm_sandbox/src/wasi_impl/types/http_outgoing_request.rs @@ -11,6 +11,9 @@ pub struct OutgoingRequest { pub headers: Resource, pub body: Resource, body_taken: bool, + /// Credential identifier bound via `attach()`. Consumed by the + /// outgoing-handler dispatch path to inject the resolved token. + pub attached_credential: Option, } impl OutgoingRequest { @@ -23,6 +26,7 @@ impl OutgoingRequest { headers, body: Resource::default(), body_taken: false, + attached_credential: None, } } From 7ca8f25b360f7b1a69596b4a2126d51516590453 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Wed, 13 May 2026 22:07:45 +0100 Subject: [PATCH 05/11] feat(credentials): hook outgoing-handler to inject credential headers Wire the scoped-credential system into the HTTP outgoing-handler dispatch path in http_handler.rs: - After building request_url, check if the request has an attached credential. If so, look it up in the registry, enforce scope (URL prefix match), and resolve the token value. - Scope check runs BEFORE the network permission gate so a mis-scoped credential is rejected immediately with HTTPRequestDenied. - After collecting guest headers, filter out any guest-set header whose name matches the credential header (case-insensitive). This prevents the guest from overriding the host-injected token. - Inject the resolved \
: \ pair. Token resolution is currently static: the resolver string on the CredentialEntry IS the token value. Async resolution callbacks are a planned follow-up. Security properties: - Credential scope enforced per-request (URL prefix match) - Guest cannot override host-injected auth headers - Registry lock released before any I/O - No credential values appear in error messages Signed-off-by: Simon Davies --- .../src/wasi_impl/http_handler.rs | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/wasm_sandbox/src/wasi_impl/http_handler.rs b/src/wasm_sandbox/src/wasi_impl/http_handler.rs index 47df79a..2f1a7d9 100644 --- a/src/wasm_sandbox/src/wasi_impl/http_handler.rs +++ b/src/wasm_sandbox/src/wasi_impl/http_handler.rs @@ -80,6 +80,48 @@ impl let request_url = url::Url::parse(&format!("{scheme_str}://{authority}{path}")) .map_err(|e| HyperlightError::Error(format!("invalid request URL: {e}")))?; + // ----------------------------------------------------------------- + // Scoped credential — scope check & token resolution. + // + // If a credential is attached to this request, verify that the + // request URL falls within the credential's target scope and + // resolve the token now so we can inject the header later. + // + // Scope is enforced BEFORE the network permission check so a + // mis-scoped credential is rejected immediately with a clear + // error rather than leaking through to the allow-list gate. + // ----------------------------------------------------------------- + let credential_header: Option<(String, String)> = + if let Some(ref cred_id) = request_data.attached_credential { + let registry = self.credential_registry.lock().map_err(|_| { + HyperlightError::Error("credential registry mutex poisoned".to_string()) + })?; + let entry = match registry.get(cred_id) { + Some(e) => e.clone(), + // Defensive: attach() validated this, but the registry + // could have been cleared between attach and dispatch. + None => { + return Ok(Err(ErrorCode::InternalError(Some( + "attached credential not found in registry".to_string(), + )))); + } + }; + + // Scope check: request URL must start with the + // credential's target prefix. + if !request_url.as_str().starts_with(&entry.target) { + return Ok(Err(ErrorCode::HTTPRequestDenied)); + } + + // Resolve the token. For now the resolver string IS the + // token value (static credentials). A future commit will + // support async resolution callbacks. + let header_value = format!("{}{}", entry.prefix, entry.resolver); + Some((entry.header.clone(), header_value)) + } else { + None + }; + { let Ok(network) = self.network.lock() else { return Ok(Err(ErrorCode::HTTPRequestDenied)); @@ -100,7 +142,7 @@ impl let active_requests = self.active_requests.clone(); // Collect guest headers eagerly in sync context. - let guest_headers: Vec<(String, String)> = request_data + let mut guest_headers: Vec<(String, String)> = request_data .headers .read() .block_on() @@ -109,6 +151,14 @@ impl .map(|(k, v)| (k, String::from_utf8_lossy(&v).into_owned())) .collect(); + // Inject the credential header, replacing any guest-set header + // with the same name so the guest cannot override the + // host-injected token. + if let Some((ref name, ref value)) = credential_header { + guest_headers.retain(|(k, _)| !k.eq_ignore_ascii_case(name)); + guest_headers.push((name.clone(), value.clone())); + } + let future_response = Resource::new(FutureIncomingResponse::default()); let future_response_clone = future_response.clone(); let future_response_panic = future_response.clone(); From bd648e0f95528afb4565564006b023c598ba3199 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 09:26:36 +0100 Subject: [PATCH 06/11] feat(credentials): thread registry through all layers + Python SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move CredentialEntry and CredentialRegistry types from the Wasm backend up to hyperlight_sandbox (the backend-agnostic mid-level crate) so any backend can participate. Changes across 6 crates: hyperlight-sandbox (mid-level): - New credentials module with CredentialEntry, CredentialRegistry, and empty_registry(). - Guest::build() now accepts a CredentialRegistry parameter. - Sandbox stores the registry and exposes register_credential(). - SandboxBuilder threads the registry through to build(). hyperlight-wasm-sandbox: - credentials.rs now re-exports from hyperlight_sandbox::credentials. - Wasm::build() and WasmComponentSandbox::with_tools() accept the registry instead of creating their own. - Removed HostState::register_credential() — now lives on Sandbox. hyperlight-javascript-sandbox / hyperlight-nanvix-sandbox: - Accept the credentials parameter in Guest::build() (ignored). hyperlight-sandbox-backend-wasm (PyO3): - register_credential() PyO3 method with pending buffer for lazy init. - Pending credentials drained alongside pending networks on first run. hyperlight-sandbox-pyo3-common: - Fix clippy: match-with-single-pattern -> if let. - Fix clippy: collapse nested if-let chain with let-chains. hyperlight_sandbox Python SDK: - Sandbox.register_credential() with keyword args for target, header, prefix, and resolver. Signed-off-by: Simon Davies --- src/hyperlight_sandbox/src/credentials.rs | 47 ++++++++++++ src/hyperlight_sandbox/src/lib.rs | 72 ++++++++++++++++--- src/javascript_sandbox/src/lib.rs | 1 + .../core/hyperlight_sandbox/__init__.py | 26 +++++++ src/sdk/python/pyo3_common/src/lib.rs | 27 +++---- src/sdk/python/wasm_backend/src/lib.rs | 63 ++++++++++++++++ src/wasm_sandbox/src/credentials.rs | 51 +------------ src/wasm_sandbox/src/lib.rs | 28 ++------ 8 files changed, 218 insertions(+), 97 deletions(-) create mode 100644 src/hyperlight_sandbox/src/credentials.rs diff --git a/src/hyperlight_sandbox/src/credentials.rs b/src/hyperlight_sandbox/src/credentials.rs new file mode 100644 index 0000000..3fd4458 --- /dev/null +++ b/src/hyperlight_sandbox/src/credentials.rs @@ -0,0 +1,47 @@ +//! Scoped-credential registry for outgoing HTTP requests. +//! +//! A [`CredentialEntry`] binds a logical credential identifier to the +//! metadata required to inject a token header at request time: +//! +//! * `target` — URL-prefix scope. The outgoing-handler only injects +//! the credential when the request URL starts with this prefix. +//! * `header` — HTTP header name (e.g. `"Authorization"`). +//! * `prefix` — Value prefix prepended to the resolved token +//! (e.g. `"Bearer "`). +//! * `resolver` — Opaque resolver identifier. Today this is a simple +//! string key; a future commit will support async resolution +//! callbacks. +//! +//! The registry is populated by the host before the guest runs. +//! Guests bind a credential to a specific outgoing request via WIT +//! `attach`. + +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; + +/// Metadata for a single scoped credential. +#[derive(Debug, Clone)] +pub struct CredentialEntry { + /// URL-prefix scope. Only requests whose URL starts with this + /// value are eligible for credential injection. + pub target: String, + + /// HTTP header name to set (e.g. `"Authorization"`). + pub header: String, + + /// Value prefix prepended to the resolved token + /// (e.g. `"Bearer "`). May be empty. + pub prefix: String, + + /// Opaque resolver identifier. The outgoing-handler will use + /// this to obtain the actual secret value at dispatch time. + pub resolver: String, +} + +/// Shared, thread-safe credential registry keyed by credential id. +pub type CredentialRegistry = Arc>>; + +/// Creates an empty credential registry. +pub fn empty_registry() -> CredentialRegistry { + Arc::new(Mutex::new(HashMap::new())) +} diff --git a/src/hyperlight_sandbox/src/lib.rs b/src/hyperlight_sandbox/src/lib.rs index d00e139..4db30e3 100644 --- a/src/hyperlight_sandbox/src/lib.rs +++ b/src/hyperlight_sandbox/src/lib.rs @@ -3,6 +3,7 @@ extern crate alloc; pub mod cap_fs; +pub mod credentials; pub mod http; pub mod network; pub mod runtime; @@ -17,6 +18,7 @@ pub use cap_fs::{ CapFs, DescriptorFlags, DescriptorStat, DescriptorType, Dir, DirPerms, FilePerms, FsError, OpenFlags, }; +pub use credentials::{CredentialEntry, CredentialRegistry}; pub use network::{HttpMethod, MethodFilter, NetworkPermission, NetworkPermissions}; use serde::{Deserialize, Serialize}; pub use tools::{ArgType, ToolRegistry, ToolSchema}; @@ -114,6 +116,7 @@ pub trait Guest: Sized { tools: ToolRegistry, network: std::sync::Arc>, fs: std::sync::Arc>, + credentials: CredentialRegistry, ) -> Result; } @@ -138,6 +141,7 @@ pub struct Sandbox { inner: G::Sandbox, network: std::sync::Arc>, fs: std::sync::Arc>, + credentials: CredentialRegistry, } impl Sandbox { @@ -145,8 +149,20 @@ impl Sandbox { pub fn new(guest: G, config: SandboxConfig, tools: ToolRegistry) -> Result { let network = std::sync::Arc::new(std::sync::Mutex::new(NetworkPermissions::new())); let fs = std::sync::Arc::new(std::sync::Mutex::new(CapFs::new())); - let inner = guest.build(config, tools, network.clone(), fs.clone())?; - Ok(Self { inner, network, fs }) + let credentials = credentials::empty_registry(); + let inner = guest.build( + config, + tools, + network.clone(), + fs.clone(), + credentials.clone(), + )?; + Ok(Self { + inner, + network, + fs, + credentials, + }) } /// Create a sandbox with a read-only input directory. @@ -159,8 +175,20 @@ impl Sandbox { let network = std::sync::Arc::new(std::sync::Mutex::new(NetworkPermissions::new())); let fs = CapFs::new().with_input(input_dir)?; let fs = std::sync::Arc::new(std::sync::Mutex::new(fs)); - let inner = guest.build(config, tools, network.clone(), fs.clone())?; - Ok(Self { inner, network, fs }) + let credentials = credentials::empty_registry(); + let inner = guest.build( + config, + tools, + network.clone(), + fs.clone(), + credentials.clone(), + )?; + Ok(Self { + inner, + network, + fs, + credentials, + }) } /// Execute guest code. @@ -212,6 +240,24 @@ impl Sandbox { .map_err(|_| anyhow::anyhow!("network mutex poisoned"))? .allow_domain(target, methods) } + + /// Register a scoped credential that guests can later `attach` to + /// outgoing requests. + /// + /// Must be called before `run()`. Credentials are immutable once + /// registered and persist for the lifetime of the sandbox. + pub fn register_credential(&self, id: impl Into, entry: CredentialEntry) -> Result<()> { + let id = id.into(); + let mut registry = self + .credentials + .lock() + .map_err(|_| anyhow::anyhow!("credential registry mutex poisoned"))?; + if registry.contains_key(&id) { + anyhow::bail!("credential '{}' already registered", id); + } + registry.insert(id, entry); + Ok(()) + } } // --------------------------------------------------------------------------- @@ -350,9 +396,19 @@ where None => vfs, }; let fs = std::sync::Arc::new(std::sync::Mutex::new(vfs)); - let inner = self - .guest - .build(self.config, self.tools, network.clone(), fs.clone())?; - Ok(Sandbox { inner, network, fs }) + let credentials = credentials::empty_registry(); + let inner = self.guest.build( + self.config, + self.tools, + network.clone(), + fs.clone(), + credentials.clone(), + )?; + Ok(Sandbox { + inner, + network, + fs, + credentials, + }) } } diff --git a/src/javascript_sandbox/src/lib.rs b/src/javascript_sandbox/src/lib.rs index 01f0e5c..1984418 100644 --- a/src/javascript_sandbox/src/lib.rs +++ b/src/javascript_sandbox/src/lib.rs @@ -125,6 +125,7 @@ impl Guest for HyperlightJs { tools: ToolRegistry, network: std::sync::Arc>, fs: std::sync::Arc>, + _credentials: hyperlight_sandbox::CredentialRegistry, ) -> Result { JsGuestSandbox::new(config, tools, network, fs) } diff --git a/src/sdk/python/core/hyperlight_sandbox/__init__.py b/src/sdk/python/core/hyperlight_sandbox/__init__.py index f8f25cc..47cdf52 100644 --- a/src/sdk/python/core/hyperlight_sandbox/__init__.py +++ b/src/sdk/python/core/hyperlight_sandbox/__init__.py @@ -180,6 +180,32 @@ def output_path(self) -> str | None: def allow_domain(self, target: str, methods: list[str] | None = None) -> None: self._inner.allow_domain(target, methods) + def register_credential( + self, + id: str, + *, + target: str, + header: str = "Authorization", + prefix: str = "Bearer ", + resolver: str, + ) -> None: + """Register a scoped credential for outgoing HTTP requests. + + Must be called before ``run()``. Guest code can then bind the + credential to an individual request via WIT ``attach``. + + Args: + id: Unique identifier for this credential. + target: URL-prefix scope. Only requests whose URL starts + with this value are eligible for injection. + header: HTTP header name to set (default ``Authorization``). + prefix: Value prefix prepended to the resolved token + (default ``Bearer ``). + resolver: Opaque resolver key. Currently used as the + literal token value (static credentials). + """ + self._inner.register_credential(id, target, header, prefix, resolver) + def snapshot(self): """Capture the current sandbox state. diff --git a/src/sdk/python/pyo3_common/src/lib.rs b/src/sdk/python/pyo3_common/src/lib.rs index 4176e72..e20f9d1 100644 --- a/src/sdk/python/pyo3_common/src/lib.rs +++ b/src/sdk/python/pyo3_common/src/lib.rs @@ -92,9 +92,8 @@ pub fn resolve_maybe_coroutine<'py>( } let asyncio = py.import("asyncio")?; - match asyncio.call_method1("run", (obj,)) { - Ok(result) => return Ok(result.unbind()), - Err(_) => {} + if let Ok(result) = asyncio.call_method1("run", (obj,)) { + return Ok(result.unbind()); } let resolver = PyModule::from_code( @@ -348,20 +347,14 @@ fn infer_type_from_annotation( // Handle Annotated[T, ...] — unwrap to get the base type T. // typing.get_origin(ann) is typing.Annotated → typing.get_args(ann)[0] is T. let py = annotation.py(); - if let Ok(typing) = py.import("typing") { - if let Ok(origin) = typing.call_method1("get_origin", (&annotation,)) { - // Check if origin is typing.Annotated (available as typing.Annotated since 3.9+) - if let Ok(annotated_type) = typing.getattr("Annotated") { - if origin.is(&annotated_type) { - if let Ok(args) = typing.call_method1("get_args", (&annotation,)) { - // args is a tuple; first element is the base type. - if let Ok(base_type) = args.get_item(0) { - return type_obj_to_arg_type(&base_type); - } - } - } - } - } + if let Ok(typing) = py.import("typing") + && let Ok(origin) = typing.call_method1("get_origin", (&annotation,)) + && let Ok(annotated_type) = typing.getattr("Annotated") + && origin.is(&annotated_type) + && let Ok(args) = typing.call_method1("get_args", (&annotation,)) + && let Ok(base_type) = args.get_item(0) + { + return type_obj_to_arg_type(&base_type); } None diff --git a/src/sdk/python/wasm_backend/src/lib.rs b/src/sdk/python/wasm_backend/src/lib.rs index 4f862a2..f753277 100644 --- a/src/sdk/python/wasm_backend/src/lib.rs +++ b/src/sdk/python/wasm_backend/src/lib.rs @@ -16,6 +16,15 @@ type WasmSnapshotInner = hyperlight_sandbox::Snapshot<< ::Sandbox as hyperlight_sandbox::GuestSandbox >::SnapshotData>; +/// Buffered credential registration for lazy sandbox init. +struct PendingCredential { + id: String, + target: String, + header: String, + prefix: String, + resolver: String, +} + #[pyclass] pub struct PySnapshot { inner: WasmSnapshotInner, @@ -26,6 +35,7 @@ pub struct WasmSandbox { inner: Option, tools: HashMap>, pending_networks: Vec<(String, Option>)>, + pending_credentials: Vec, config: SandboxConfig, input_dir: Option, output_dir: Option, @@ -48,6 +58,7 @@ impl WasmSandbox { inner: None, tools: HashMap::new(), pending_networks: Vec::new(), + pending_credentials: Vec::new(), config: SandboxConfig { module_path: module_path.to_string(), heap_size: match heap_size { @@ -115,6 +126,19 @@ impl WasmSandbox { .allow_domain(&target, methods) .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; } + for cred in std::mem::take(&mut self.pending_credentials) { + sandbox + .register_credential( + cred.id, + hyperlight_sandbox::CredentialEntry { + target: cred.target, + header: cred.header, + prefix: cred.prefix, + resolver: cred.resolver, + }, + ) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + } self.inner = Some(sandbox); } let sandbox = self.inner.as_mut().unwrap(); @@ -164,6 +188,45 @@ impl WasmSandbox { Ok(()) } + /// Register a scoped credential for outgoing HTTP requests. + /// + /// Must be called before `run()`. The credential can then be + /// attached to individual requests by guest code via WIT `attach`. + #[pyo3(signature = (id, target, header, prefix, resolver))] + fn register_credential( + &mut self, + id: &str, + target: &str, + header: &str, + prefix: &str, + resolver: &str, + ) -> PyResult<()> { + if let Some(sandbox) = self.inner.as_ref() { + // Register directly on the live sandbox. + sandbox + .register_credential( + id, + hyperlight_sandbox::CredentialEntry { + target: target.to_string(), + header: header.to_string(), + prefix: prefix.to_string(), + resolver: resolver.to_string(), + }, + ) + .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; + } else { + // Buffer for later — will be applied when sandbox initialises. + self.pending_credentials.push(PendingCredential { + id: id.to_string(), + target: target.to_string(), + header: header.to_string(), + prefix: prefix.to_string(), + resolver: resolver.to_string(), + }); + } + Ok(()) + } + fn get_output_files(&self) -> PyResult> { let sandbox = self .inner diff --git a/src/wasm_sandbox/src/credentials.rs b/src/wasm_sandbox/src/credentials.rs index 9ae9ab6..4831777 100644 --- a/src/wasm_sandbox/src/credentials.rs +++ b/src/wasm_sandbox/src/credentials.rs @@ -1,49 +1,4 @@ -//! Scoped-credential registry for outgoing HTTP requests. -//! -//! A [`CredentialEntry`] binds a logical credential identifier to the -//! metadata required to inject a token header at request time: -//! -//! * `target` — URL-prefix scope (e.g. `"https://api.example.com/"`). -//! The outgoing-handler only injects the credential when -//! the request URL starts with this prefix. -//! * `header` — HTTP header name (e.g. `"Authorization"`). -//! * `prefix` — Value prefix prepended to the resolved token -//! (e.g. `"Bearer "`). -//! * `resolver` — Opaque resolver identifier. Today this is a simple -//! string key; a future commit will support async -//! resolution callbacks. -//! -//! The registry lives on [`crate::HostState`] behind -//! `Arc>>` and is populated by -//! the host before the guest runs. Guests bind a credential to a -//! specific outgoing request via the WIT `attach` function. +//! Re-exports from [hyperlight_sandbox::credentials] for use within +//! the Wasm backend. -use std::collections::HashMap; -use std::sync::{Arc, Mutex}; - -/// Metadata for a single scoped credential. -#[derive(Debug, Clone)] -pub struct CredentialEntry { - /// URL-prefix scope. Only requests whose URL starts with this - /// value are eligible for credential injection. - pub target: String, - - /// HTTP header name to set (e.g. `"Authorization"`). - pub header: String, - - /// Value prefix prepended to the resolved token - /// (e.g. `"Bearer "`). May be empty. - pub prefix: String, - - /// Opaque resolver identifier. The outgoing-handler will use - /// this to obtain the actual secret value at dispatch time. - pub resolver: String, -} - -/// Shared, thread-safe credential registry keyed by credential id. -pub type CredentialRegistry = Arc>>; - -/// Creates an empty credential registry. -pub fn empty_registry() -> CredentialRegistry { - Arc::new(Mutex::new(HashMap::new())) -} +pub use hyperlight_sandbox::credentials::*; diff --git a/src/wasm_sandbox/src/lib.rs b/src/wasm_sandbox/src/lib.rs index 7cbcc9d..10a8015 100644 --- a/src/wasm_sandbox/src/lib.rs +++ b/src/wasm_sandbox/src/lib.rs @@ -32,8 +32,9 @@ impl Guest for Wasm { tools: ToolRegistry, network: std::sync::Arc>, fs: std::sync::Arc>, + credentials: credentials::CredentialRegistry, ) -> Result { - WasmComponentSandbox::with_tools(config, tools, network, fs) + WasmComponentSandbox::with_tools(config, tools, network, fs, credentials) } } @@ -45,28 +46,6 @@ pub struct HostState { pub(crate) credential_registry: credentials::CredentialRegistry, } -impl HostState { - /// Register a scoped credential that guests can later `attach` to - /// outgoing requests. This is a host-side-only API — it is NOT - /// exposed through WIT so guests cannot register their own - /// credentials. - pub fn register_credential( - &self, - id: String, - entry: credentials::CredentialEntry, - ) -> Result<(), String> { - let mut registry = self - .credential_registry - .lock() - .map_err(|_| "credential registry mutex poisoned".to_string())?; - if registry.contains_key(&id) { - return Err(format!("credential '{}' already registered", id)); - } - registry.insert(id, entry); - Ok(()) - } -} - #[allow(refining_impl_trait)] impl bindings::root::component::RootImports for HostState { type Tools = HostState; @@ -318,6 +297,7 @@ impl WasmComponentSandbox { tools: ToolRegistry, network: Arc>, fs: Arc>, + credentials: credentials::CredentialRegistry, ) -> Result { // Verify the shared tokio runtime is available before proceeding. hyperlight_sandbox::runtime::RUNTIME @@ -335,7 +315,7 @@ impl WasmComponentSandbox { fs: fs.clone(), network: network.clone(), active_requests: Arc::new(AtomicUsize::new(0)), - credential_registry: credentials::empty_registry(), + credential_registry: credentials, }; let mut proto = HyperlightSandboxBuilder::new() From c36cfaea70d5bc47fe450080499983f2d2ed064a Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 13:36:14 +0100 Subject: [PATCH 07/11] build(wasm): set WIT_WORLD via workspace cargo config + detect WIT staleness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WIT_WORLD is consumed at compile time by hyperlight_wasm_macro (proc-macro), hyperlight_wasm/build.rs, and hyperlight_wasm_runtime/build.rs. The runtime build script emits cfg(component) only when WIT_WORLD is set; without it the runtime falls back to the legacy flatbuffer host-function ABI while the host, built via the proc-macro's host_bindgen!, always uses component-model bindings. The mismatch surfaces at sandbox start as 'GuestError: Host function vector parameter missing length'. The Justfile already exports WIT_WORLD for just children, but bare cargo invocations (IDE, CI direct cargo, developer ad-hoc) inherited nothing. The wasm_backend and dotnet/ffi sub-crates carry their own .cargo/config.toml as a workaround; a workspace-root .cargo/config.toml now covers every cargo invocation, so direct cargo test --manifest-path src/wasm_sandbox/Cargo.toml now matches the component-mode ABI just like just wasm test. Also extend _clean-stale-wasm to invalidate cached host bindings when the WIT source is newer than the cached fingerprints. Proc-macros cannot emit rerun-if-changed, so a WIT edit would otherwise leave stale bindings in target/. The Windows variant gets an explicit xit 0 because Get-ChildItem -ErrorAction SilentlyContinue still flips $? to false. Signed-off-by: Simon Davies --- .cargo/config.toml | 16 ++++++ src/wasm_sandbox/Justfile | 55 ++++++++++++++++--- .../guests/javascript/package-lock.json | 27 ++++++++- 3 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..92e5956 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,16 @@ +# WIT_WORLD is consumed at COMPILE time by: +# - hyperlight_wasm_macro (proc-macro) -> std::env::var_os("WIT_WORLD").unwrap() +# - hyperlight_wasm/build.rs -> rerun-if-env-changed=WIT_WORLD +# - hyperlight_wasm_runtime/build.rs -> emits cfg(component) IFF WIT_WORLD is set +# +# Without it, hyperlight_wasm_runtime falls back to the legacy flatbuffer-based +# host-function ABI, while hyperlight-wasm-sandbox (built with WIT_WORLD via the +# proc-macro's host_bindgen!) uses the component-model ABI. Mixing the two yields +# "GuestError: Host function vector parameter missing length" at sandbox start. +# +# `just wasm test` exports WIT_WORLD via its recipe, but bare `cargo` invocations +# (e.g. from an IDE or a developer running `cargo test --manifest-path ...`) +# would otherwise miss it. Cargo looks for `.cargo/config.toml` by walking up the +# CWD tree, so we put it at the repo root to cover every workspace cargo call. +[env] +WIT_WORLD = { value = "src/wasm_sandbox/wit/sandbox-world.wasm", relative = true } diff --git a/src/wasm_sandbox/Justfile b/src/wasm_sandbox/Justfile index 2a47213..5c97398 100644 --- a/src/wasm_sandbox/Justfile +++ b/src/wasm_sandbox/Justfile @@ -53,14 +53,38 @@ invalidate-wit-caches: -{{rmrf}} {{repo-root}}/src/sdk/python/wasm_backend/target/release/build/hyperlight-wasm-* -{{rmrf}} {{repo-root}}/src/sdk/python/wasm_backend/target/release/.fingerprint/hyperlight-wasm-* -# Only clean when rust-cache left stale state (fingerprints exist but runtime binary missing). +# Clean stale hyperlight-wasm caches when ANY of: +# 1. fingerprints exist but the guest runtime binary is missing (rust-cache restored +# .fingerprint/ without the corresponding target/hyperlight-wasm-runtime/ output), OR +# 2. the WIT source file is newer than the cached host bindings/fingerprints. +# hyperlight-wasm-sandbox calls `hyperlight_component_macro::host_bindgen!("wit/sandbox-world.wasm")` +# at compile time. Proc-macros cannot emit `cargo:rerun-if-changed`, so when the WIT +# changes cargo doesn't notice and the SDKs fail at runtime with +# "Host function vector parameter missing length". [unix] _clean-stale-wasm: #!/usr/bin/env bash + wit_src="{{repo-root}}/src/wasm_sandbox/wit/hyperlight-sandbox.wit" for profile in debug release; do - if compgen -G "{{repo-root}}/target/$profile/build/hyperlight-wasm-*" > /dev/null && \ - [ ! -f "{{repo-root}}/target/hyperlight-wasm-runtime/x86_64-hyperlight-none/$profile/hyperlight-wasm-runtime" ]; then - echo "Cleaning stale hyperlight-wasm $profile build artifacts..." + if ! compgen -G "{{repo-root}}/target/$profile/build/hyperlight-wasm-*" > /dev/null; then + continue + fi + reason="" + runtime="{{repo-root}}/target/hyperlight-wasm-runtime/x86_64-hyperlight-none/$profile/hyperlight-wasm-runtime" + if [ ! -f "$runtime" ]; then + reason="runtime binary missing" + elif [ -f "$wit_src" ]; then + for fp in "{{repo-root}}/target/$profile/.fingerprint/hyperlight-wasm-"* \ + "{{repo-root}}/target/$profile/.fingerprint/hyperlight-host-"*; do + [ -e "$fp" ] || continue + if [ "$wit_src" -nt "$fp" ]; then + reason="WIT source newer than cached host bindings" + break + fi + done + fi + if [ -n "$reason" ]; then + echo "Cleaning stale hyperlight-wasm $profile build artifacts ($reason)..." rm -rf {{repo-root}}/target/hyperlight-wasm-runtime {{repo-root}}/target/hls \ {{repo-root}}/target/*/build/hyperlight-wasm-* {{repo-root}}/target/*/.fingerprint/hyperlight-wasm-* \ {{repo-root}}/target/*/build/hyperlight-host-* {{repo-root}}/target/*/.fingerprint/hyperlight-host-* \ @@ -73,12 +97,26 @@ _clean-stale-wasm: [windows] _clean-stale-wasm: + $witSrc = '{{repo-root}}/src/wasm_sandbox/wit/hyperlight-sandbox.wit'; \ + $witMtime = if (Test-Path $witSrc) { (Get-Item $witSrc).LastWriteTimeUtc } else { $null }; \ foreach ($profile in @('debug', 'release')) { \ + $fpDir = '{{repo-root}}/target/' + $profile + '/.fingerprint'; \ $bp = '{{repo-root}}/target/' + $profile + '/build'; \ $rp = '{{repo-root}}/target/hyperlight-wasm-runtime/x86_64-hyperlight-none/' + $profile + '/hyperlight-wasm-runtime'; \ - if ((Get-ChildItem -Path $bp -Filter 'hyperlight-wasm-*' -ErrorAction SilentlyContinue) -and \ - -not (Test-Path $rp)) { \ - Write-Host ('Cleaning stale hyperlight-wasm ' + $profile + ' build artifacts...'); \ + $hlwBuild = @(Get-ChildItem -Path $bp -Filter 'hyperlight-wasm-*' -ErrorAction SilentlyContinue); \ + if ($hlwBuild.Count -eq 0) { continue }; \ + $reason = $null; \ + if (-not (Test-Path $rp)) { \ + $reason = 'runtime binary missing'; \ + } elseif ($witMtime) { \ + $hostFps = @(Get-ChildItem -Path $fpDir -Filter 'hyperlight-wasm-*' -ErrorAction SilentlyContinue) + \ + @(Get-ChildItem -Path $fpDir -Filter 'hyperlight-host-*' -ErrorAction SilentlyContinue); \ + foreach ($fp in $hostFps) { \ + if ($witMtime -gt $fp.LastWriteTimeUtc) { $reason = 'WIT source newer than cached host bindings'; break }; \ + }; \ + }; \ + if ($reason) { \ + Write-Host ('Cleaning stale hyperlight-wasm ' + $profile + ' build artifacts (' + $reason + ')...'); \ Remove-Item -Recurse -Force -ErrorAction SilentlyContinue '{{repo-root}}/target/hyperlight-wasm-runtime','{{repo-root}}/target/hls'; \ foreach ($t in @('{{repo-root}}/target', '{{repo-root}}/src/sdk/python/wasm_backend/target')) { \ foreach ($p in @('debug', 'release')) { \ @@ -91,7 +129,8 @@ _clean-stale-wasm: }; \ break; \ } \ - } + }; \ + exit 0 guest-build-aot target=default-target: guest-build-wasm ensure-tools hyperlight-wasm-aot compile --component \ diff --git a/src/wasm_sandbox/guests/javascript/package-lock.json b/src/wasm_sandbox/guests/javascript/package-lock.json index 817f597..a1f070b 100644 --- a/src/wasm_sandbox/guests/javascript/package-lock.json +++ b/src/wasm_sandbox/guests/javascript/package-lock.json @@ -1,12 +1,12 @@ { "name": "hyperlight-sandbox-js-guest", - "version": "0.3.0", + "version": "0.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hyperlight-sandbox-js-guest", - "version": "0.3.0", + "version": "0.4.0", "devDependencies": { "@bytecodealliance/componentize-js": "^0.20.0", "@bytecodealliance/jco": "^1.19.0" @@ -216,6 +216,29 @@ "wizer-win32-x64": "wizer" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", From cda573be64057603641f730d30a2c1a2ddb49a61 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 13:36:35 +0100 Subject: [PATCH 08/11] feat(credentials): guest-side helper + integration tests (Phase 1) Adds the missing guest-facing surface for the scoped-credentials feature defined in hyperlight:sandbox/credentials (Phase 1 host plumbing landed in the earlier WIT/RootImports/CredentialRegistry commits). Guest helper additions (src/wasm_sandbox/guests/python): - sandbox_executor.py: credential= kwarg on http_get / http_post / the shared _http_request helper, plus standalone attach_credential(req, id) for callers building wasi-http requests by hand. - hyperlight.py: re-export attach_credential so guest scripts can rom hyperlight import attach_credential. Tests (src/wasm_sandbox/tests/credential_integration.rs, 8 cases): - credential_header_injected_on_get / _on_post -> happy path - no_credential_means_no_auth_header -> default unchanged - duplicate_credential_registration_rejected -> registry rejects re-use - unknown_credential_raises_error -> unknown id surfaces error - guest_cannot_override_credential_header -> host injection wins - scope_mismatch_denied -> scope enforcement - double_attach_rejected -> single-attach invariant All 8 pass via just wasm test and direct cargo test. Signed-off-by: Simon Davies --- src/wasm_sandbox/guests/python/hyperlight.py | 3 +- .../guests/python/sandbox_executor.py | 63 ++- .../tests/credential_integration.rs | 448 ++++++++++++++++++ 3 files changed, 505 insertions(+), 9 deletions(-) create mode 100644 src/wasm_sandbox/tests/credential_integration.rs diff --git a/src/wasm_sandbox/guests/python/hyperlight.py b/src/wasm_sandbox/guests/python/hyperlight.py index a225fda..2befcfd 100644 --- a/src/wasm_sandbox/guests/python/hyperlight.py +++ b/src/wasm_sandbox/guests/python/hyperlight.py @@ -2,5 +2,6 @@ from sandbox_executor import _call_tool as call_tool from sandbox_executor import http_get, http_post +from sandbox_executor import attach_credential -__all__ = ["call_tool", "http_get", "http_post"] +__all__ = ["call_tool", "http_get", "http_post", "attach_credential"] diff --git a/src/wasm_sandbox/guests/python/sandbox_executor.py b/src/wasm_sandbox/guests/python/sandbox_executor.py index 83b30c9..e59b9dc 100644 --- a/src/wasm_sandbox/guests/python/sandbox_executor.py +++ b/src/wasm_sandbox/guests/python/sandbox_executor.py @@ -15,6 +15,7 @@ import wit_world.imports.tools as tools import wit_world.imports.outgoing_handler as outgoing_handler import wit_world.imports.wasi_http_types as http_types +import wit_world.imports.credentials as credentials def _call_tool(tool_name: str, **kwargs): @@ -26,17 +27,30 @@ def _call_tool(tool_name: str, **kwargs): return json.loads(result_json) -def http_get(url: str) -> dict: - """Make an HTTP GET request via WASI-HTTP. Returns {"status": int, "body": str}.""" - return _http_request("GET", url) +def http_get(url: str, credential: str = None) -> dict: + """Make an HTTP GET request via WASI-HTTP. Returns {"status": int, "body": str}. + If credential is set, attaches the named credential to the request. + The host will inject the credential's header at dispatch time — the + guest never sees the secret value. + """ + return _http_request("GET", url, credential=credential) -def http_post(url: str, body: str = "", content_type: str = "application/json") -> dict: - """Make an HTTP POST request via WASI-HTTP. Returns {"status": int, "body": str}.""" - return _http_request("POST", url, body=body, content_type=content_type) +def http_post(url: str, body: str = "", content_type: str = "application/json", + credential: str = None) -> dict: + """Make an HTTP POST request via WASI-HTTP. Returns {"status": int, "body": str}. -def _http_request(method: str, url: str, body: str = "", content_type: str = "") -> dict: + If credential is set, attaches the named credential to the request. + The host will inject the credential's header at dispatch time — the + guest never sees the secret value. + """ + return _http_request("POST", url, body=body, content_type=content_type, + credential=credential) + + +def _http_request(method: str, url: str, body: str = "", content_type: str = "", + credential: str = None) -> dict: """Internal: make an HTTP request via WASI-HTTP outgoing-handler.""" # Parse URL into scheme, authority, path scheme_str, rest = url.split("://", 1) if "://" in url else ("https", url) @@ -81,6 +95,16 @@ def _http_request(method: str, url: str, body: str = "", content_type: str = "") req.set_authority(authority) req.set_path_with_query(path) + # Attach credential if specified — the host resolves the secret + # and injects the header at dispatch time. + if credential is not None: + try: + credentials.attach(req, credential) + except Exception as e: + raise RuntimeError( + f"Failed to attach credential '{credential}': {e}" + ) from e + # Write body if present if body: outgoing_body = req.body() @@ -138,6 +162,23 @@ def _http_request(method: str, url: str, body: str = "", content_type: str = "") return {"status": status, "body": body_text} +def attach_credential(request, credential_id: str): + """Attach a registered credential to an outgoing-request by name. + + Low-level helper for guests building WASI-HTTP requests manually. + Most callers should use the `credential=` kwarg on `http_get`/`http_post` + instead. + + Raises RuntimeError if the credential is unknown or already attached. + """ + try: + credentials.attach(request, credential_id) + except Exception as e: + raise RuntimeError( + f"Failed to attach credential '{credential_id}': {e}" + ) from e + + class Executor: """Implements the WIT executor interface for componentize-py.""" @@ -152,7 +193,13 @@ def run(self, code: str) -> ExecutionResult: exit_code = 0 try: - exec(code, {"__builtins__": __builtins__, "call_tool": _call_tool, "http_get": http_get, "http_post": http_post}) + exec(code, { + "__builtins__": __builtins__, + "call_tool": _call_tool, + "http_get": http_get, + "http_post": http_post, + "attach_credential": attach_credential, + }) except SystemExit as e: exit_code = e.code if isinstance(e.code, int) else 1 except Exception as e: diff --git a/src/wasm_sandbox/tests/credential_integration.rs b/src/wasm_sandbox/tests/credential_integration.rs new file mode 100644 index 0000000..b5f0f46 --- /dev/null +++ b/src/wasm_sandbox/tests/credential_integration.rs @@ -0,0 +1,448 @@ +//! Integration tests: scoped-credential injection end-to-end. +//! +//! Each test spins up a local [`EchoServer`], registers one or more +//! credentials, then runs guest Python code that exercises the +//! `credential=` kwarg on `http_get`/`http_post`. The echo server +//! reflects all received headers so we can assert exactly what the +//! host injected (or blocked). + +use std::path::Path; + +use hyperlight_sandbox::test_utils::EchoServer; +use hyperlight_sandbox::{CredentialEntry, HttpMethod, SandboxBuilder}; +use hyperlight_wasm_sandbox::Wasm; + +fn python_guest_path() -> String { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("guests/python/python-sandbox.aot") + .display() + .to_string() +} + +/// Helper to build a [`CredentialEntry`] with sensible defaults. +fn cred(target: &str, resolver: &str) -> CredentialEntry { + CredentialEntry { + target: target.to_string(), + header: "authorization".to_string(), + prefix: "Bearer ".to_string(), + resolver: resolver.to_string(), + } +} + +// ----------------------------------------------------------------------- +// Happy path: credential header is injected +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn credential_header_injected_on_get() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .register_credential("test_cred", cred(&base_url, "secret-token-42")) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + let code = format!( + r#" +resp = http_get("{base_url}/api/data", credential="test_cred") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); + + let echo: serde_json::Value = + serde_json::from_str(result.stdout.trim()).expect("failed to parse echo response"); + let headers = echo["headers"].as_object().expect("missing headers"); + assert_eq!( + headers.get("authorization").and_then(|v| v.as_str()), + Some("Bearer secret-token-42"), + "credential header not injected or has wrong value" + ); +} + +#[tokio::test] +async fn credential_header_injected_on_post() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .register_credential("post_cred", cred(&base_url, "post-token-99")) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Post]) + .expect("allow_domain failed"); + + let code = format!( + r#" +resp = http_post("{base_url}/submit", body='{{"key": "val"}}', credential="post_cred") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); + + let echo: serde_json::Value = + serde_json::from_str(result.stdout.trim()).expect("failed to parse echo response"); + let headers = echo["headers"].as_object().expect("missing headers"); + assert_eq!( + headers.get("authorization").and_then(|v| v.as_str()), + Some("Bearer post-token-99"), + ); +} + +// ----------------------------------------------------------------------- +// Error: unknown credential name → guest RuntimeError +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn unknown_credential_raises_error() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + // Note: no credential registered — guest tries to attach "ghost" + let code = format!( + r#" +resp = http_get("{base_url}/api", credential="ghost") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_ne!(result.exit_code, 0, "expected non-zero exit code"); + assert!( + result.stderr.contains("credential") || result.stderr.contains("RuntimeError"), + "stderr should mention credential error, got: {}", + result.stderr + ); +} + +// ----------------------------------------------------------------------- +// Error: scope mismatch — credential bound to different URL prefix +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn scope_mismatch_denied() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + // Credential scoped to https://example.com — won't match the local server + sandbox + .register_credential("wrong_scope", cred("https://example.com/api", "nope")) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + let code = format!( + r#" +resp = http_get("{base_url}/api/data", credential="wrong_scope") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_ne!( + result.exit_code, 0, + "expected non-zero exit code for scope mismatch" + ); + let stderr_lc = result.stderr.to_ascii_lowercase(); + assert!( + stderr_lc.contains("denied") || stderr_lc.contains("failed"), + "stderr should indicate request was denied, got: {}", + result.stderr + ); +} + +// ----------------------------------------------------------------------- +// Error: double-attach — attaching a second credential to the same req +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn double_attach_rejected() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .register_credential("cred_a", cred(&base_url, "token-a")) + .expect("register_credential failed"); + + sandbox + .register_credential("cred_b", cred(&base_url, "token-b")) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + // Guest code uses attach_credential directly to attempt double-attach + let code = format!( + r#" +import wit_world.imports.wasi_http_types as http_types +import wit_world.imports.credentials as creds + +fields = http_types.Fields.from_list([("user-agent", b"test")]) +req = http_types.OutgoingRequest(fields) +req.set_method(http_types.Method_Get()) +req.set_scheme(http_types.Scheme_Http()) +req.set_authority("{authority}") +req.set_path_with_query("/double") + +# First attach — should succeed +creds.attach(req, "cred_a") + +# Second attach — should fail with already-attached +try: + creds.attach(req, "cred_b") + print("ERROR: second attach did not raise") +except Exception as e: + print(f"OK: {{e}}") +"#, + authority = base_url.trim_start_matches("http://").trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); + assert!( + result.stdout.contains("OK:"), + "expected OK from double-attach rejection, got stdout: {}", + result.stdout + ); +} + +// ----------------------------------------------------------------------- +// Security: guest-set Authorization header is replaced by credential +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn guest_cannot_override_credential_header() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .register_credential("legit", cred(&base_url, "real-token")) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + // Guest manually sets Authorization header, then also attaches a + // credential. The host must strip the guest's header and inject + // the credential's value instead. + let code = format!( + r#" +import wit_world.imports.wasi_http_types as http_types +import wit_world.imports.outgoing_handler as outgoing_handler +import wit_world.imports.credentials as creds + +fields = http_types.Fields.from_list([ + ("user-agent", b"test"), + ("authorization", b"Bearer evil-guest-token"), +]) +req = http_types.OutgoingRequest(fields) +req.set_method(http_types.Method_Get()) +req.set_scheme(http_types.Scheme_Http()) +req.set_authority("{authority}") +req.set_path_with_query("/sneaky") + +creds.attach(req, "legit") + +future_resp = outgoing_handler.handle(req, None) +pollable = future_resp.subscribe() +pollable.block() +resp_result = future_resp.get() +resp = resp_result +if hasattr(resp, 'value'): + resp = resp.value +if hasattr(resp, 'value'): + resp = resp.value +import json +body_stream = resp.consume().stream() +chunks = [] +while True: + try: + chunk = body_stream.read(65536) + if chunk: + chunks.append(chunk) + else: + break + except: + break +print(b"".join(chunks).decode()) +"#, + authority = base_url.trim_start_matches("http://").trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); + + let echo: serde_json::Value = + serde_json::from_str(result.stdout.trim()).expect("failed to parse echo response"); + let headers = echo["headers"].as_object().expect("missing headers"); + let auth_val = headers + .get("authorization") + .and_then(|v| v.as_str()) + .expect("authorization header missing"); + + assert_eq!( + auth_val, "Bearer real-token", + "credential header must be the host-injected value, not the guest's" + ); + assert!( + !auth_val.contains("evil"), + "guest's fake authorization header must be stripped" + ); +} + +// ----------------------------------------------------------------------- +// No credential attached — request goes through without auth header +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn no_credential_means_no_auth_header() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + let code = format!( + r#" +resp = http_get("{base_url}/open") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); + + let echo: serde_json::Value = + serde_json::from_str(result.stdout.trim()).expect("failed to parse echo response"); + let headers = echo["headers"].as_object().expect("missing headers"); + assert!( + headers.get("authorization").is_none(), + "no credential attached — authorization header should be absent" + ); +} + +// ----------------------------------------------------------------------- +// Host-side duplicate registration is rejected +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn duplicate_credential_registration_rejected() { + let sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + sandbox + .register_credential("dup", cred("https://example.com", "tok")) + .expect("first registration should succeed"); + + let err = sandbox + .register_credential("dup", cred("https://example.com", "tok2")) + .expect_err("second registration should fail"); + + assert!( + format!("{err}").contains("already registered"), + "error should mention 'already registered', got: {err}" + ); +} From a85359108c5b5ad106a2dc582ada1c2548f488a2 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 15:08:11 +0100 Subject: [PATCH 09/11] build(wasm_sandbox): commit compiled WIT artifact + CI drift check host_bindgen!() consumes a compiled WIT component (sandbox-world.wasm), which was previously .gitignored and only produced by `just wasm guest-compile-wit`. That left silent breakage for source-distribution consumers (`pip install git+...`, `cargo install`, etc.) because the artifact is read by transitive deps -- specifically the hyperlight-wasm-runtime proc-macro -- BEFORE our own build scripts can run. A build.rs in this crate cannot solve the bootstrap (the runtime is compiled first in the dep graph, and would race ABI with our fresh bindings even if it succeeded). The pragmatic, well-trodden fix used by most WIT-component projects: check the compiled artifact into git so it exists from clone time. Changes: - .gitignore: add `!src/wasm_sandbox/wit/sandbox-world.wasm` to opt this specific artifact out of the broad `*.wasm` exclusion. - Commit the current 16235-byte canonical artifact produced by `wasm-tools component wit ... -w`. - CI: add a `Check WIT artifact is in sync` step to the wasm-sandbox matrix job that regenerates the file via `just wasm guest-compile-wit` then `git diff --exit-code`s it, failing fast if a contributor edits the .wit source without committing the regenerated artifact. Developer flow stays the same: edit .wit, run `just wasm guest-compile-wit` (also chained inside `just wasm build`), commit both files together. Signed-off-by: Simon Davies --- .github/workflows/ci.yml | 9 +++++++++ .gitignore | 5 +++++ src/wasm_sandbox/wit/sandbox-world.wasm | Bin 0 -> 16235 bytes 3 files changed, 14 insertions(+) create mode 100644 src/wasm_sandbox/wit/sandbox-world.wasm diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a33bbb1..3cd079a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,15 @@ jobs: sudo udevadm trigger --name-match=kvm sudo chmod 666 /dev/kvm + - name: Check WIT artifact is in sync with .wit source + # sandbox-world.wasm is the compiled WIT used by host_bindgen!. It + # is consumed by transitive deps (hyperlight-wasm-runtime) before + # our crate's build scripts run, so it must live in git. Detect any + # drift between the committed artifact and the .wit source. + run: | + just wasm guest-compile-wit + git diff --exit-code -- src/wasm_sandbox/wit/sandbox-world.wasm + - name: Build run: just wasm build diff --git a/.gitignore b/.gitignore index d7b3fbb..8a9146e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,11 @@ target/ .venv/ *.aot *.wasm +# Exception: the compiled WIT artifact is checked in as a build input. +# host_bindgen! reads this file *before* our build scripts can run (it is +# consumed by transitive deps like hyperlight-wasm-runtime), so the file +# must exist from `git clone` time. CI regenerates and diffs to catch drift. +!src/wasm_sandbox/wit/sandbox-world.wasm __pycache__/ *.so *.pyd diff --git a/src/wasm_sandbox/wit/sandbox-world.wasm b/src/wasm_sandbox/wit/sandbox-world.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a8a3e89d8a232dd727a2ce3475ff6b1027a85612 GIT binary patch literal 16235 zcmcgz>yISYRlldZrsw_M+4rM8v$l6_*NnY>#MwZyoc6U{8 zRrSuc7s~;{8@}-e@lX^IP=eqiN(4rH0E9pUkn#oio%^a=)iq8?B=*D3Ow~P)d(OG% zbx(;P8?Orzi+}rs-e}MpU!da^N*Y;46G8WcAWv+bgt;HakD@e*$6=gPgC-fjYkFdx z-v#N(lwV}z(NMlw@Wg5qM|l*C{O)OwT1|2JG{~a6-BEPppt|?s;hn=57X%$Q=>dq{ zqgIv&`7{GZp76rQQBKqpy9F$sXdt3v&l3w_nkH$JXu!~37LNKPGEZFl(m2cqN$<<@ z{b8Q?y|6Pq@v}UQ;uC5Zq)~DtS7@XSY~K@0lVmgsI-{_H_kB;CH+apG!!!(fGswhH zXU^wWbw){dNKKj$O=eizh+;60Ju)7a&yL(9*x?77n?B@7R8fk&U+4naTBUsPo}y1gd(DcjlEHj<$f{=(;$zM*zX6?D1_2Pt2;`v zuqUviHHE}i;uecE@M!WLJ)jj@qI(S~_~qs(j8Da?CoUN&xeQ22(V8drYu`!(OPCQPd6Tq9>lNUtsB(l})i{j-;~vOrOdY&Z1X3T6Da? z=Wnrk;^5J6z~Cuy7MIymW_d4)so50gtVffNH0CA7Tt1^3_43@=b#bp~+z>P)SA4Up z1#&#o*jN5fxNy+taN(K8wMxfuCmVT~j-wb(UY_$NT=g}(vGO|&w
?K@=}40wGW zP`%WU>yXV-g&-Y67Y#o5l^0DVonb?VsT~%OC91UG)iUd z=x&uLmJz7d?6jn(?Vo@IYwb)Dh5B~r7@Mm`3_+)!Sd3zX;5bJB;XjvpQxz3pnOd05 zI60*j|ABzBl7?9_nsVHrMQQEioeshn%JRgv^$#!*iItYwt?+^cUa(UvFm!08DW1}{ zfRLFTjgvUZlQ`=7h(_I^HiumpGo_8iEQDw6Wv8og5F=K}KW5B!kcW9R4%re^8Y9`p zL3BBWg0H%?PJ=Sz&Xz*{fm zm@~;`O2gvsBNS)RyV%Dvja#iaNyouxB?});5lxU@wNiwEWW0PDf%7;Fd&@mU8u{B& zoFJA?v(OW*p!W#wuPIh({B$emcEc=NJx!*go-h60Vla|v%tj~ZAyG0sc%5lBTk0Vm zvq%;mPLn)XKvI_F8_buVCy75o_80DfdUygq(3$0-uej@mNCEvxnw-EyGW?F?l1?Xi z*n^2Z3Pw?{5hZI;=J%pB>|)0=Z&9BtBWj z{(2$ri+2ifq_ai*!mRGX+@}40)Q#}iABSUL-zh!ICP5eYlDr@fe8_XhlYF+xzk#Xb z5mF+gfvZ!Xn@o}v%tHl!p3gS$Bb#;yh67&OA0?*}B{HdTlw+|si6-GPi`Gx#(F{RD zZX6N{hj3Ysb6?7l#k|%{lMKR;8-gW3SV`)4lOD8&uy)=`N$u1obu?aDoW?_($#_lb zQlr@F4uUl3Lg@Ozvc=%_qkgiU&BmPsK~c(iEe%hmP^ILjl|h7I4i8tDf}hVO;AD#) zHd*dK9-o9L0YF!XWj<**-{T1_B3E3G!&BcrLTby7WQEm<{Y=@loTK3)r7e$E$+oxdUm&8k$@QaOJ?6%Lv+2dcacUey#A;5rtdtuQ@ZfMW5( z6T2uF0!d*IWCI_HnqtG3uu`$saS83Gr@v;hT5nf6gIBrM@ckPna% z$`v;#_F7#qm4}7mm&3IZnF4wkH!q%XSN8$w@v~(Oz&(JnxhdEwq zO(1yPmE%X9D$5azbfxwH(%pKVSU*sWE=vzQJ{TE`;+YyA)FCMjoFC-$F|c#dW#^~P zAcV6@KaIs1FIH8sA@^~ou&nGr9$P?uqMoA^@#>M|0u)Eas+ST(ZMmZj_Ok`*gC+jk z?zK+sX(%HoNZ+%HF7TD%Z3m^GaA;f(5WG>ZplPgp5~l}P^)V}zg(M$@>488G#g@+w zX5;}G2lu4&0LcIyL#CHq1^g-EO1nmTC8tfF0@!sI>>B{969k_}>GJ5)RuGQ=Y-^K& z+Ar4-^>*I}071$=+@!vxLhtqTh!_44k2js}}Fyb2b-BUw~_ z_uE4JB`~~fb!Ae@QnIAtl=U9!9sN8Fh=%OKo5;ETN{GJ(rahT=&k&r)s^uj!F}jan zFYATk^%3VVrZsQ@<-(?u#MAL2=lSS5I1jlbL0cecG|*&4CkpK~WEE_YhP4QOdBGHl z4yj2RvNR2~OLV-Af-Mg7(wd*<$?1ga@_GEr-lkqK+P@5JsH&6VeuT%a-J~Vi84rO6? zn!@{aXHaC^N7|dqB;T!2oO)>8;N_DZZn0n0n;AvO?9XX2`dlY;qPWLJ!iISWoG7|> z*oz~Po5qM)NSCo<2c%&$osjEJ59sOT#f`WS3=cSuuHejKy|1TB(IJyCbsz9H_rW3^`524yr9UwygSh@0DUTiz^ z&f-2Ulu(!Paia?qtx~iGAA0eU%oMoA&?!+8N0KIQ!BB^aZJyyQ zFKvjRYn#M4i^{@ACStLoF;oXoF}oXJ<~^60wo~~ybf)Nr@s-UWnV@=yL!zhb{ugB7 z`W{R1mI;RrD5nzh;QJta>JmP1GE)Z{J&_RAqp#9?RiNCgkUnM7&z(WK4grcv8~Pnu z85egYLY{c`4777=pQcE58u>nOS3Kh+fi4Am!}BZ+R%yaT$ZeK_GNoIqHc=PTmG62b|O1 z348WRfZDI8Rt`|G3mb17oRt7|V2=7Om*sW)L|Lx*=b;IBdJ`qxc;?`*#IvW3E8102 zsT>*{IF3q+j^7Eo!%>1k4K#w$NPIx=yRv%LabphrFbt7@jyN=-!+~_TN4F}p-)D=t zZG5Q%%d~6YZ-ex@OB(*)h93vq0gZZmCxViL-M>yp)W+ADxOL|uij zxQ6Ez-WGGxFeTZhy1o)<7;RUOpxLxz?%ZurJ@I9W0XMS4sWFRNeCLkh5}h(R=!Lp} zi`!P}3R>R%W+dlba2vJZyqUiC3Qyc!lv$TreWZS9gS$PC`4YpUwhz&`3F}E*s9U0G zsc}P1%b?NJp5t-Dq;Y!6y*F$E-5yN__p&`6IK1I(+E3C>)I(DYzei)fHAL8xlX?T( z$e{b9p)tPO+Im!Uz3>&s>N2O=K#a&R`(pR8=|15D68Tvd_dNY2q*`MZYp;j!6(IKr+OIZ8V zz+Tj_7HL6>oAzs0(MQcWYh!rbjAnqF;aivu`7B;@3L9@zs(BzfHp#z#R*@sek9(3|YsH zG8F!+fO>(3r!@5G;j^pElJ3C5NG*f(tk}clMvlQT*$U+*Y9Dg}FrW+W^JyGBf~hIH zzU01n^DUk$8AKgSS^}#24t-IGTEV&fRNZqGV$bQi>LD(P$X#q1zu+vE*N^tiMdyvW zzpi~HJ2a3ly1>ls4$B{#0E}{c05^c# z7#HGd>8ZN&mWyy1g4gFuuh|4uj(sSul-{W02iFS+5CQID>FpOj|7P*((%dUK5ro+s zA=;&P+9$!yN|npx{`m@OvxXD@Bk@!TUY{-u&Xf?88L*2OgKx3x!z~ZlM7bn`T)#4u z>ycL$DdZP4d-|m-&i(Q$%T*csL6)sY}4cwBrSJn73swy4|CxX>{TJ>2G|Wo zUA_FUpC)5jEMjf|t+L6s$$(#%Db9w#=)jJt^Aw3g1Sz^(U5Aplx(<^+eD^Py3pEF! zk*YH8qXHMgRTxws7y;0wk>LUB_9{H6a7Z7o#k|d!s}O3yg+5_Y!Pf=K0sCoz-kKH_ z*64)sbr$rw3USOd#v#2ygNtU_pTOxjHNO*rq*pmqZh$`NtVh7GiRj#Vo;&bQBm4*W zbcU<=Ax5-SCJb795pNp|bHFN=)2E&BqPaD}6yJ03Kow9&XmVQA-vnw~7S4gGvz_7E zJh}!0`!k*gwV>bnP*Ap2eAq%iOVK3&nKbB|Li`2bu9a-r#&+$M`J(y~MQxD$PC-)N zQ`@_cD%2tS5!^^?4zb+T(cEgSqtC-)u`AVa__j%)_T)vjtxxBGxoXx3?mGlsCC|ZB zmHdT*>SpELO-cR*V~2C7n0y6~Io+T4E8F}FDi zg}FJKT((cu_Ut^-95`>!E~Z~{HdZp%IXGjkzf93(cA9?!OS@XKG!yo9221bI;4;^q z+Gf5h#P%g@uUeMtu<^Vrr8xJb#VM}wGr({>|mFQad?)jE5BM((vB}wD5h_!UOsb@H+fY z>%D>MzktfNxT>f)fbe&~f}IpT6Cqp1?}C+O8e%JQ>g)GN{61he z2YEhGX{=J}AD|bczNX?grBSaJ(9pUv*JI#^)gA*sJG0W~mrk~;pE!?4Fc>#KcMChSs=EQ{9P!nk5C>yJ;5(MRpLZP*ni7ox5 z3uXy(U64c8=qIC!mY*x@wpl~pe##!ImWQ`etjqZ0ry?@A3Z1)HP` zxNO)>lO(^3Mitsx*wzvMiFVQoK27FdfmZxcV+~)x4Ef8NUee9z$v$QX(Iniz`(&Tj z@K1iRe|P`W)6uB?#W&u5vn{{YZp(#jmI*f&+MQY3QbO_SPiE~~pL}bEWIb+!Uk>=U z58sL3mfw_QZD_ZxdoCmVm4@vspLRMxbnA0T{ii0zfv4`2LWugirh literal 0 HcmV?d00001 From a5fd123648bd4ba411cb194633f978c553845a92 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 15:55:03 +0100 Subject: [PATCH 10/11] fix(wasm_backend): remove buggy local .cargo/config.toml shadowing root The local config at src/sdk/python/wasm_backend/.cargo/config.toml has been present since the initial commit (b0c7399). It set: [env] WIT_WORLD = { value = "../../../../wasm_sandbox/wit/sandbox-world.wasm", relative = true } Cargo resolves `relative = true` against the directory containing the `.cargo/` directory (the workspace member root, not the `.cargo/` dir itself). Counting four `..` from src/sdk/python/wasm_backend/ lands at the *parent* of the repo root, then `wasm_sandbox/...` -> a path that does not exist. The real artifact lives at src/wasm_sandbox/... so the correct prefix would have been `../../../` (three `..`), not four. Because cargo merges configs deepest-first and this local file shadowed the root .cargo/config.toml (which is correctly written), every cargo invocation made from within src/sdk/python/wasm_backend/ -- including `maturin build` invoked by `pip install` -- saw WIT_WORLD pointing at a non-existent path. The hyperlight_wasm_macro::wasm_guest_bindgen proc macro in hyperlight-wasm-runtime then panicked with: proc macro panicked: called `Result::unwrap()` on an `Err` value: Os { code: 3, kind: NotFound, message: "The system cannot find the path specified." } This was masked everywhere it should have surfaced because every `just` recipe that exercises this code path exports WIT_WORLD as an absolute path before invoking cargo, bypassing the buggy resolution. The repo-root .cargo/config.toml (added previously) already covers every cargo invocation that walks up from inside the workspace, so the local config is redundant. Remove it to eliminate the shadow and let the correctly-resolved root config take effect. Verified empirically: in a fresh clone of feat/scoped-credentials at a853591, `cargo build --lib --release` from src/sdk/python/wasm_backend/ with no env vars set previously panicked at the proc-macro; after removing this file (the only change), the same command finishes the release build in ~1m18s. Signed-off-by: Simon Davies --- src/sdk/python/wasm_backend/.cargo/config.toml | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 src/sdk/python/wasm_backend/.cargo/config.toml diff --git a/src/sdk/python/wasm_backend/.cargo/config.toml b/src/sdk/python/wasm_backend/.cargo/config.toml deleted file mode 100644 index 27b7acc..0000000 --- a/src/sdk/python/wasm_backend/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -WIT_WORLD = { value = "../../../../wasm_sandbox/wit/sandbox-world.wasm", relative = true } \ No newline at end of file From c86ff7e7ad123e181b8740a54a3d84eeb18763e8 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 14 May 2026 21:02:02 +0100 Subject: [PATCH 11/11] feat(credentials): resolver becomes a per-request callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the static-token storage model with a host-side callback that produces the token at request-dispatch time, so resolvers can refresh tokens (IMDS, OAuth, Key Vault, ...) without re-registering credentials. Core (`hyperlight_sandbox`): * `ResolverFn = Arc Result + Send + Sync>`, invoked once per credentialed outgoing request. The registry mutex is released *before* the resolver runs, so a slow resolver cannot stall unrelated requests. * `CredentialEntry::with_static_resolver` for tests / short-lived tokens. * Manual `Debug` impl on `CredentialEntry` renders the resolver as `` so captured secrets cannot leak via logs, panics, or `dbg!` output. * Re-export `ResolverFn` from the crate root. Wire path (`wasi_impl/http_handler.rs`): * Clone the credential entry by id, drop the mutex, enforce scope (URL prefix) before the existing `allow_domain` network gate, invoke the resolver, filter any guest-set header of the same name (case-insensitive), then inject `
: `. * On resolver `Err`, the diagnostic is dropped before crossing the guest boundary; the guest sees only `InternalError("credential resolver failed")`. `ResolverFn` rustdoc updated to match this behaviour (was previously inaccurate). Python SDK (`hyperlight_sandbox` / `wasm_backend`): * `register_credential(..., resolver: Callable[[], str])` accepts any zero-arg Python callable. The PyO3 bridge re-acquires the GIL on every invocation. When the resolver raises, only the exception **type name** is forwarded across the FFI boundary; the message body is dropped (it may have been assembled from secret material). Integration tests (`src/wasm_sandbox/tests/credential_integration.rs`): * `resolver_invoked_per_request` — atomic counter + rotating tokens prove the resolver runs on every request, not once at registration. * `resolver_failure_surfaces_as_error` — resolver returns a secret-bearing diagnostic; the test asserts the diagnostic is absent from guest stdout and from the surfaced error payload. * `isolated_registries_across_sandboxes` — two sandboxes register the same credential id with different tokens; each sees only its own. Hygiene: * Fix joined-line whitespace bug in `wasm_backend/src/lib.rs`. * Sort `sandbox_executor` imports in guest `hyperlight.py` for the new `attach_credential` entry (was `I001`). Signed-off-by: Simon Davies --- src/hyperlight_sandbox/src/credentials.rs | 72 ++++- src/hyperlight_sandbox/src/lib.rs | 2 +- .../core/hyperlight_sandbox/__init__.py | 13 +- src/sdk/python/wasm_backend/src/lib.rs | 48 ++- src/wasm_sandbox/guests/python/hyperlight.py | 3 +- .../src/wasi_impl/http_handler.rs | 49 ++- .../tests/credential_integration.rs | 291 +++++++++++++++++- 7 files changed, 436 insertions(+), 42 deletions(-) diff --git a/src/hyperlight_sandbox/src/credentials.rs b/src/hyperlight_sandbox/src/credentials.rs index 3fd4458..b36ab8e 100644 --- a/src/hyperlight_sandbox/src/credentials.rs +++ b/src/hyperlight_sandbox/src/credentials.rs @@ -8,19 +8,39 @@ //! * `header` — HTTP header name (e.g. `"Authorization"`). //! * `prefix` — Value prefix prepended to the resolved token //! (e.g. `"Bearer "`). -//! * `resolver` — Opaque resolver identifier. Today this is a simple -//! string key; a future commit will support async resolution -//! callbacks. +//! * `resolver` — A host-side callback invoked on every credentialed +//! outgoing request to produce a fresh secret value. The host calls +//! the resolver synchronously from the WASI HTTP dispatch path, so +//! implementations should be fast and (where appropriate) memoise +//! internally. Errors returned by the resolver surface to the guest +//! as a request-level dispatch failure with a host-redacted message. //! //! The registry is populated by the host before the guest runs. //! Guests bind a credential to a specific outgoing request via WIT //! `attach`. use std::collections::HashMap; +use std::fmt; use std::sync::{Arc, Mutex}; +/// Host-side callback that produces the secret token value for a +/// credential at request-dispatch time. +/// +/// The returned `String` is treated as the literal token; the host +/// prepends [`CredentialEntry::prefix`] to it to form the outgoing +/// header value. +/// +/// On error, the returned diagnostic string is **dropped** by the +/// outgoing-handler before any guest-visible error is produced — it +/// is neither sent to the guest nor logged by this crate. The wire +/// path surfaces only a fixed `"credential resolver failed"` +/// indication. Resolver authors who need diagnostics should record +/// them inside the resolver itself (e.g. via the host's own logger) +/// before returning the `Err`. +pub type ResolverFn = Arc Result + Send + Sync>; + /// Metadata for a single scoped credential. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct CredentialEntry { /// URL-prefix scope. Only requests whose URL starts with this /// value are eligible for credential injection. @@ -33,9 +53,47 @@ pub struct CredentialEntry { /// (e.g. `"Bearer "`). May be empty. pub prefix: String, - /// Opaque resolver identifier. The outgoing-handler will use - /// this to obtain the actual secret value at dispatch time. - pub resolver: String, + /// Resolver callback. Invoked on every credentialed outgoing + /// request; see [`ResolverFn`] for the contract. + pub resolver: ResolverFn, +} + +impl fmt::Debug for CredentialEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // The resolver is a function pointer that may close over secret + // material; we never want it (or its captures) to appear in a + // log line, panic message, or `dbg!` output. + f.debug_struct("CredentialEntry") + .field("target", &self.target) + .field("header", &self.header) + .field("prefix", &self.prefix) + .field("resolver", &"") + .finish() + } +} + +impl CredentialEntry { + /// Build a [`CredentialEntry`] whose resolver returns a fixed + /// token string on every invocation. + /// + /// Convenience constructor for tests, examples, and trivially + /// short-lived secrets. Production callers that need refresh + /// behaviour (managed identities, OAuth, …) should construct + /// the entry directly with a custom [`ResolverFn`]. + pub fn with_static_resolver( + target: impl Into, + header: impl Into, + prefix: impl Into, + token: impl Into, + ) -> Self { + let token = token.into(); + Self { + target: target.into(), + header: header.into(), + prefix: prefix.into(), + resolver: Arc::new(move || Ok(token.clone())), + } + } } /// Shared, thread-safe credential registry keyed by credential id. diff --git a/src/hyperlight_sandbox/src/lib.rs b/src/hyperlight_sandbox/src/lib.rs index 4db30e3..8472962 100644 --- a/src/hyperlight_sandbox/src/lib.rs +++ b/src/hyperlight_sandbox/src/lib.rs @@ -18,7 +18,7 @@ pub use cap_fs::{ CapFs, DescriptorFlags, DescriptorStat, DescriptorType, Dir, DirPerms, FilePerms, FsError, OpenFlags, }; -pub use credentials::{CredentialEntry, CredentialRegistry}; +pub use credentials::{CredentialEntry, CredentialRegistry, ResolverFn}; pub use network::{HttpMethod, MethodFilter, NetworkPermission, NetworkPermissions}; use serde::{Deserialize, Serialize}; pub use tools::{ArgType, ToolRegistry, ToolSchema}; diff --git a/src/sdk/python/core/hyperlight_sandbox/__init__.py b/src/sdk/python/core/hyperlight_sandbox/__init__.py index 47cdf52..2429e42 100644 --- a/src/sdk/python/core/hyperlight_sandbox/__init__.py +++ b/src/sdk/python/core/hyperlight_sandbox/__init__.py @@ -187,7 +187,7 @@ def register_credential( target: str, header: str = "Authorization", prefix: str = "Bearer ", - resolver: str, + resolver: Callable[[], str], ) -> None: """Register a scoped credential for outgoing HTTP requests. @@ -201,8 +201,15 @@ def register_credential( header: HTTP header name to set (default ``Authorization``). prefix: Value prefix prepended to the resolved token (default ``Bearer ``). - resolver: Opaque resolver key. Currently used as the - literal token value (static credentials). + resolver: A callable invoked with no arguments on every + credentialed outgoing request to produce a fresh token + value as a ``str``. Called synchronously from the host + HTTP dispatch path, so it must be fast and thread-safe; + long-running fetches (e.g. IMDS, OAuth) should be + memoised by the caller. Any exception raised by the + callable surfaces to guest code as a host-redacted + request-level error (only the exception **type name** + is propagated; the message body is dropped). """ self._inner.register_credential(id, target, header, prefix, resolver) diff --git a/src/sdk/python/wasm_backend/src/lib.rs b/src/sdk/python/wasm_backend/src/lib.rs index f753277..b58ae2f 100644 --- a/src/sdk/python/wasm_backend/src/lib.rs +++ b/src/sdk/python/wasm_backend/src/lib.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; +use std::sync::Arc; use hyperlight_sandbox::{ - DEFAULT_HEAP_SIZE, DEFAULT_STACK_SIZE, DirPerms, FilePerms, HttpMethod, Sandbox, + DEFAULT_HEAP_SIZE, DEFAULT_STACK_SIZE, DirPerms, FilePerms, HttpMethod, ResolverFn, Sandbox, SandboxBuilder, SandboxConfig, }; use hyperlight_sandbox_pyo3_common::{ @@ -22,7 +23,37 @@ struct PendingCredential { target: String, header: String, prefix: String, - resolver: String, + resolver: ResolverFn, +} + +/// Wrap a Python callable as a [`ResolverFn`] suitable for storage in +/// the credential registry. +/// +/// On each invocation the wrapper re-acquires the Python GIL, calls +/// the supplied callable with no arguments, and extracts the result +/// as a Python `str`. Exceptions are mapped to a redacted Rust error +/// — only the exception **type name** is surfaced, never the message +/// (which may contain secret material assembled by user code). +fn python_callable_to_resolver(callable: Py) -> ResolverFn { + Arc::new(move || -> Result { + Python::attach(|py| { + let bound = callable.bind(py); + match bound.call0() { + Ok(result) => result + .extract::() + .map_err(|_| "credential resolver did not return a str".to_string()), + Err(err) => { + let type_name = err + .get_type(py) + .qualname() + .ok() + .and_then(|n| n.extract::().ok()) + .unwrap_or_else(|| "Exception".to_string()); + Err(format!("python resolver raised {type_name}")) + } + } + }) + }) } #[pyclass] @@ -192,6 +223,12 @@ impl WasmSandbox { /// /// Must be called before `run()`. The credential can then be /// attached to individual requests by guest code via WIT `attach`. + /// + /// `resolver` is a Python callable that takes no arguments and + /// returns the secret token as a `str`. It is invoked synchronously + /// from the WASI HTTP dispatch path on every credentialed request, + /// so it must be fast and thread-safe; long-running token fetches + /// should be memoised by the caller. #[pyo3(signature = (id, target, header, prefix, resolver))] fn register_credential( &mut self, @@ -199,8 +236,9 @@ impl WasmSandbox { target: &str, header: &str, prefix: &str, - resolver: &str, + resolver: Py, ) -> PyResult<()> { + let resolver_fn = python_callable_to_resolver(resolver); if let Some(sandbox) = self.inner.as_ref() { // Register directly on the live sandbox. sandbox @@ -210,7 +248,7 @@ impl WasmSandbox { target: target.to_string(), header: header.to_string(), prefix: prefix.to_string(), - resolver: resolver.to_string(), + resolver: resolver_fn, }, ) .map_err(|e| PyRuntimeError::new_err(format!("{e}")))?; @@ -221,7 +259,7 @@ impl WasmSandbox { target: target.to_string(), header: header.to_string(), prefix: prefix.to_string(), - resolver: resolver.to_string(), + resolver: resolver_fn, }); } Ok(()) diff --git a/src/wasm_sandbox/guests/python/hyperlight.py b/src/wasm_sandbox/guests/python/hyperlight.py index 2befcfd..57da675 100644 --- a/src/wasm_sandbox/guests/python/hyperlight.py +++ b/src/wasm_sandbox/guests/python/hyperlight.py @@ -1,7 +1,6 @@ """Hyperlight guest-side helpers, available to user code via `from hyperlight import call_tool`.""" from sandbox_executor import _call_tool as call_tool -from sandbox_executor import http_get, http_post -from sandbox_executor import attach_credential +from sandbox_executor import attach_credential, http_get, http_post __all__ = ["call_tool", "http_get", "http_post", "attach_credential"] diff --git a/src/wasm_sandbox/src/wasi_impl/http_handler.rs b/src/wasm_sandbox/src/wasi_impl/http_handler.rs index 2f1a7d9..375727b 100644 --- a/src/wasm_sandbox/src/wasi_impl/http_handler.rs +++ b/src/wasm_sandbox/src/wasi_impl/http_handler.rs @@ -90,20 +90,27 @@ impl // Scope is enforced BEFORE the network permission check so a // mis-scoped credential is rejected immediately with a clear // error rather than leaking through to the allow-list gate. + // + // The credential-registry mutex is dropped before the resolver + // is invoked — resolvers may perform slow I/O (e.g. an IMDS + // round-trip on cache miss) and we do not want to serialise + // unrelated credentialed requests behind one slow resolver. // ----------------------------------------------------------------- let credential_header: Option<(String, String)> = if let Some(ref cred_id) = request_data.attached_credential { - let registry = self.credential_registry.lock().map_err(|_| { - HyperlightError::Error("credential registry mutex poisoned".to_string()) - })?; - let entry = match registry.get(cred_id) { - Some(e) => e.clone(), - // Defensive: attach() validated this, but the registry - // could have been cleared between attach and dispatch. - None => { - return Ok(Err(ErrorCode::InternalError(Some( - "attached credential not found in registry".to_string(), - )))); + let entry = { + let registry = self.credential_registry.lock().map_err(|_| { + HyperlightError::Error("credential registry mutex poisoned".to_string()) + })?; + match registry.get(cred_id) { + Some(e) => e.clone(), + // Defensive: attach() validated this, but the registry + // could have been cleared between attach and dispatch. + None => { + return Ok(Err(ErrorCode::InternalError(Some( + "attached credential not found in registry".to_string(), + )))); + } } }; @@ -113,10 +120,22 @@ impl return Ok(Err(ErrorCode::HTTPRequestDenied)); } - // Resolve the token. For now the resolver string IS the - // token value (static credentials). A future commit will - // support async resolution callbacks. - let header_value = format!("{}{}", entry.prefix, entry.resolver); + // Resolve the token by invoking the registered + // callback. The resolver returns the literal secret + // value on success; on failure we surface a fixed, + // host-redacted message so the guest never sees the + // resolver's diagnostic text (which could contain + // secret material). + let token = match (entry.resolver)() { + Ok(t) => t, + Err(_diag) => { + return Ok(Err(ErrorCode::InternalError(Some( + "credential resolver failed".to_string(), + )))); + } + }; + + let header_value = format!("{}{}", entry.prefix, token); Some((entry.header.clone(), header_value)) } else { None diff --git a/src/wasm_sandbox/tests/credential_integration.rs b/src/wasm_sandbox/tests/credential_integration.rs index b5f0f46..6423275 100644 --- a/src/wasm_sandbox/tests/credential_integration.rs +++ b/src/wasm_sandbox/tests/credential_integration.rs @@ -7,9 +7,11 @@ //! host injected (or blocked). use std::path::Path; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; use hyperlight_sandbox::test_utils::EchoServer; -use hyperlight_sandbox::{CredentialEntry, HttpMethod, SandboxBuilder}; +use hyperlight_sandbox::{CredentialEntry, HttpMethod, ResolverFn, SandboxBuilder}; use hyperlight_wasm_sandbox::Wasm; fn python_guest_path() -> String { @@ -19,14 +21,11 @@ fn python_guest_path() -> String { .to_string() } -/// Helper to build a [`CredentialEntry`] with sensible defaults. -fn cred(target: &str, resolver: &str) -> CredentialEntry { - CredentialEntry { - target: target.to_string(), - header: "authorization".to_string(), - prefix: "Bearer ".to_string(), - resolver: resolver.to_string(), - } +/// Helper to build a [`CredentialEntry`] with sensible defaults and a +/// static token value. Tests that need rotation or fault injection +/// build a custom [`ResolverFn`] inline instead. +fn cred(target: &str, token: &str) -> CredentialEntry { + CredentialEntry::with_static_resolver(target, "authorization", "Bearer ", token) } // ----------------------------------------------------------------------- @@ -446,3 +445,277 @@ async fn duplicate_credential_registration_rejected() { "error should mention 'already registered', got: {err}" ); } + +// ----------------------------------------------------------------------- +// Resolver is invoked per-request — proves token refresh contract +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn resolver_invoked_per_request() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + // Resolver that returns a different token on each invocation. + // This is the canonical proof that the host calls the resolver + // for every outgoing credentialed request, not just once at + // registration time. + let counter = Arc::new(AtomicUsize::new(0)); + let counter_for_resolver = Arc::clone(&counter); + let resolver: ResolverFn = Arc::new(move || { + let n = counter_for_resolver.fetch_add(1, Ordering::SeqCst); + Ok(format!("rotating-token-{n}")) + }); + + sandbox + .register_credential( + "rotating", + CredentialEntry { + target: base_url.clone(), + header: "authorization".to_string(), + prefix: "Bearer ".to_string(), + resolver, + }, + ) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + let code = format!( + r#" +import json +r1 = http_get("{base_url}/api/one", credential="rotating") +r2 = http_get("{base_url}/api/two", credential="rotating") +print(json.dumps([json.loads(r1["body"]), json.loads(r2["body"])])) +"#, + base_url = base_url.trim_end_matches('/') + ); + + (sandbox.run(&code).expect("sandbox run failed"), counter) + }) + .await + .unwrap(); + + let (exec, counter) = result; + assert_eq!(exec.exit_code, 0, "stderr: {}", exec.stderr); + + let echoes: Vec = + serde_json::from_str(exec.stdout.trim()).expect("failed to parse echo array"); + assert_eq!(echoes.len(), 2, "expected two echoed responses"); + assert_eq!( + echoes[0]["headers"]["authorization"].as_str(), + Some("Bearer rotating-token-0"), + "first request should see token-0" + ); + assert_eq!( + echoes[1]["headers"]["authorization"].as_str(), + Some("Bearer rotating-token-1"), + "second request should see token-1 — resolver MUST be called per request" + ); + assert_eq!( + counter.load(Ordering::SeqCst), + 2, + "resolver should have been invoked exactly twice" + ); +} + +// ----------------------------------------------------------------------- +// Resolver failure surfaces as a request error with no token leakage +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn resolver_failure_surfaces_as_error() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let result = tokio::task::spawn_blocking(move || { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox"); + + // Resolver that always fails. The diagnostic string MUST NOT + // appear in any guest-visible error — the host redacts it to a + // fixed message. + let resolver: ResolverFn = + Arc::new(|| Err("secret-bearing diagnostic that must not leak".to_string())); + + sandbox + .register_credential( + "broken", + CredentialEntry { + target: base_url.clone(), + header: "authorization".to_string(), + prefix: "Bearer ".to_string(), + resolver, + }, + ) + .expect("register_credential failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain failed"); + + let code = format!( + r#" +try: + resp = http_get("{base_url}/api/data", credential="broken") + print("UNEXPECTED_OK:" + resp["body"]) +except Exception as e: + print("ERR:" + repr(e)) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox run failed") + }) + .await + .unwrap(); + + assert_eq!(result.exit_code, 0, "stderr: {}", result.stderr); + assert!( + result.stdout.starts_with("ERR:"), + "guest should have raised an exception, got stdout: {}", + result.stdout + ); + // The host-redacted message is the only thing the guest may see. + assert!( + !result.stdout.contains("secret-bearing"), + "resolver diagnostic must NOT leak to guest, stdout was: {}", + result.stdout + ); + assert!( + !result.stdout.contains("must not leak"), + "resolver diagnostic must NOT leak to guest, stdout was: {}", + result.stdout + ); +} + +// ----------------------------------------------------------------------- +// Multi-tenant isolation: two sandboxes that register the same +// credential id with DIFFERENT tokens must each see only their own +// token. Proves the credential registry is per-`Sandbox` instance +// — there is no global key table, no shared `Arc`, no cross-instance +// lookup path. +// +// If this test ever fails it means the host has acquired a shared +// registry by mistake (e.g. a `lazy_static!`, a `OnceCell`, or a +// stray `Arc::clone` between sandboxes). Treat as critical. +// ----------------------------------------------------------------------- + +#[tokio::test] +async fn isolated_registries_across_sandboxes() { + let server = EchoServer::start().await; + let base_url = server.url(""); + + let (result_a, result_b) = tokio::task::spawn_blocking(move || { + // ---- Sandbox A: id="shared" → token-tenant-A ---- + let result_a = { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox A"); + + sandbox + .register_credential("shared", cred(&base_url, "token-tenant-A")) + .expect("register_credential on sandbox A failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain on sandbox A failed"); + + let code = format!( + r#" +resp = http_get("{base_url}/tenant-a", credential="shared") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox A run failed") + }; + + // ---- Sandbox B: same id="shared" → token-tenant-B ---- + let result_b = { + let mut sandbox = SandboxBuilder::new() + .guest(Wasm) + .module_path(python_guest_path()) + .build() + .expect("failed to create sandbox B"); + + sandbox + .register_credential("shared", cred(&base_url, "token-tenant-B")) + .expect("register_credential on sandbox B failed"); + + sandbox + .allow_domain(&base_url, vec![HttpMethod::Get]) + .expect("allow_domain on sandbox B failed"); + + let code = format!( + r#" +resp = http_get("{base_url}/tenant-b", credential="shared") +print(resp["body"]) +"#, + base_url = base_url.trim_end_matches('/') + ); + + sandbox.run(&code).expect("sandbox B run failed") + }; + + (result_a, result_b) + }) + .await + .unwrap(); + + assert_eq!( + result_a.exit_code, 0, + "sandbox A stderr: {}", + result_a.stderr + ); + assert_eq!( + result_b.exit_code, 0, + "sandbox B stderr: {}", + result_b.stderr + ); + + let echo_a: serde_json::Value = + serde_json::from_str(result_a.stdout.trim()).expect("failed to parse echo response A"); + let echo_b: serde_json::Value = + serde_json::from_str(result_b.stdout.trim()).expect("failed to parse echo response B"); + + assert_eq!( + echo_a["headers"]["authorization"].as_str(), + Some("Bearer token-tenant-A"), + "sandbox A must see ONLY its own token" + ); + assert_eq!( + echo_b["headers"]["authorization"].as_str(), + Some("Bearer token-tenant-B"), + "sandbox B must see ONLY its own token" + ); + + // Belt-and-braces: neither sandbox's stdout contains the other's + // token. Catches any future regression where, say, a debug log + // path or a shared registry accidentally surfaces the foreign + // value to the guest. + assert!( + !result_a.stdout.contains("token-tenant-B"), + "sandbox A leaked sandbox B's token: {}", + result_a.stdout + ); + assert!( + !result_b.stdout.contains("token-tenant-A"), + "sandbox B leaked sandbox A's token: {}", + result_b.stdout + ); +}