3 unstable releases
0.2.0 | Sep 20, 2024 |
---|---|
0.1.1 | Sep 19, 2024 |
0.1.0 | Sep 18, 2024 |
#98 in Cargo plugins
31KB
288 lines
cargo-task-wasm
About
This project provides a new cargo task
subcommand that can be used to run
project-local tasks inside a secure WebAssembly sandbox. It looks for files in a
tasks/
subdirectory of your project's root, and compiles those to Wasm
Components. This is an attempt at
formalizing cargo-xtask pattern into a
first-class, secure workflow.
Roadmap
- Sketch out a repository layout or whatever workflow example
- Create a new
cargo
subcommand - Hook up wasmtime to the subcommand
- Add support for manual paths in a
[tasks]
section inCargo.toml
- Figure out how to configure capabilities for the tasks
- Add support for compiling cargo deps as part of subcommands
- Store config in Cargo metadata section
- Add support for using submodules
- Add the remainder of the capabilities
- Add support for installing tasks from crates.io
- Support workspaces and
[workspace.metadata]
Installation
The cargo task
subcommand compiles Rust to Wasm Components targeting WASI
0.2. In order to do that a working WASI 0.2 toolchain needs
to be present on the host system.
$ rustup +beta target add wasip2 # Install the WASI 0.2 target
$ cargo install cargo-task-wasm # Install the `cargo task` subcommand
Usage
Usage: cargo task <TASK_NAME> [ARGS]...
Arguments:
<TASK_NAME> The name of the task to run
[ARGS]... Optional arguments to pass to the task
Options:
-h, --help Print help
-V, --version Print version
Examples:
cargo task codegen # run a task called `codegen`
Configuration
Capabilities
Tasks in cargo task
follow the principle of least
privilege. By
default they only get access to the working directory, and can access any
additional command line arguments passed to it. Additional permissions can be
configured via a [package.metadata.tasks]
section in Cargo.toml
.
[package]
name = "example"
version = "0.1.0"
edition = "2021"
[package.metadata.tasks]
env-filter = { inherit-env = ["FOO"] } # inherit specific env vars
env-all = { inherit-env = true } # inherit all env vars
The reason why this is stored in [package.metadata.tasks]
rather than a
top-level [tasks]
section is because that is the canonical extension
point
Cargo recommends using for third-party extensions. Should a cargo tasks
command ever become a first-class extension to Cargo, the package.metadata
prefix can be dropped.
Dependencies
Tasks must specify their own dependencies via
[package.metadata.task-dependencies]
in Cargo.toml
. These dependencies are
separate from Cargo's existing [dev-dependencies]
and [build-dependencies]
because these dependencies must be able to be compiled to Rust's wasm32-wasip2
target. Not all dev or build deps may fit these requirements, which is why task
dependencies are listed separately.
[package]
name = "example"
version = "0.1.0"
edition = "2021"
[package.metadata.task-dependencies]
wstd = "0.4.0"
Paths
Tasks are discovered in the local tasks/
directory of your project. This is a
treated as standalone workspace where each file is treated as an individual task
to be compiled and executed. This behaves not unlike the tests/
directory in
Cargo projects. It is possible to use both submodules and dependencies with
tasks like you would expect. A typical project structure will look like this:
example/
├── Cargo.toml
├── src
│ └── lib.rs
└── tasks
├── codegen.rs
└── test.rs
This structure will give you access to the cargo task codegen
and cargo task test
subcommands.
Limitations
By default tasks only get access to the local project directory and any
additional arguments passed via the CLI. Additional capabilities such as network
or filesystem access can be configured via Cargo.toml
. Sandboxing is provided
by the Wasmtime runtime, and the available APIs are part of the
wasi:cli/command
world. Some limitations however still exist, and are good to
be aware of:
- Limited ecosystem support: At the time of writing WASI 0.2 is a fairly new compile target, and so ecoystem support is still in its infancy. Not all crates are expected to work, and may need to be updated first.
- Limited stdlib support: For similar reasons: not all functionality in the stdlib will work yet. In particular network support for WASI 0.2 is still being implemented. This is expected to land in Rust 1.84 in the second half of 2024. If you want to access the network before then, you can try and use the wasi or wstd crates.
- No threading support: At the time of writing support for threading in WASI 0.2 has not yet been implemented. Work on this is still ongoing upstream in the WASI subgroup. Consensus on a design seems to have formed, and implementation work has started - but this is unlikely to stabilize before the start of 2025.
- No support for exec/fork: WASI 0.2 does not allow you to spawn or fork new processes. Providing access to this would be a sandbox escape, and so we don't provide access to it. This means it's not possible to shell out to call global tools, which may at times be impractical but is also a necessary limitation to guarantee security.
In the future we hope to provide a way to instrument Cargo or Rustc directly from inside the sandbox. However this will need to be carefully evaluated and designed to ensure the sandbox cannot be escaped.
See Also
- Custom tasks in Cargo (Aaron Turon, 2018) - First proposed a
cargo task
subcommand for custom tasks. matklad/cargo-xtask
(Alex Kladov, 2019) - A convention-based implementation ofcargo task
.dtolnay/watt
(David Tolnay 2019) - Executing Rust procedural macros compiled as WebAssembly.
Safety
This crate uses #![deny(unsafe_code)]
to ensure everything is implemented in
100% Safe Rust.
Contributing
Want to join us? Check out our "Contributing" guide and take a look at some of these issues:
Acknowledgements
This project was built as a collaboration between Michael Woerister and Yosh Wuyts as part of the 2024 Microsoft Hackathon, targeting the Microsoft Secure Future Initiative. Special thanks to Pat Hickey for showing us how to configure Wasmtime as a Rust library.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~35–47MB
~870K SLoC