OXYGENHUB

The WASM tier: WASI modules run by wasmtime on any runner (closes #75) 28cc603f737d

runtime "wasm" runs WASI preview 1 modules with wasmtime 49 (Cranelift):
no rootfs, no network, the job's files preopened at /src (and as the
current directory), its mounts at their targets, the sandbox's memory
limit held by wasmtime. exec names a module among the job's files or a
glob of them (each runs in turn; the exit code is the first non-zero
after all ran; a trap is 134). As the syscall tier, the module runs in a
child (flow __wasm SPEC) so the runner streams its output, stops it at
the time limit or on cancel and measures its memory; the job's files are
a directory, so outputs, caches and reports work as there. Every runner
offers the tier; preflight checks only memory. The receipt's
environment names wasmtime 49.0.4, the runner binary and each module's
BLAKE3. Secrets and identities are refused for now.

Tests: the parser (no rootfs, no network) and an integration test of
modules written in WAT run by flow run: output and arguments, a glob of
two with one failing, a file created in the workspace, an escape out of
it refused, memory over the limit refused, a trap. Spec 4.1, handover.md,
changelog. The image gains cargo-nextest (refs #81) and must be rebuilt
for wasmtime's crates before this is pushed.
Author
Andy McCall @andymccall <[email protected]>
via
agent agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key b5c28de55d40
When
· 2026-10-25 12:48 UTC
Signature
◈ sealed by agent:claude@andymccall
Hash
28cc603f737d188c5cb531f955ad89368f6e12c470527642b95634ac9283ba61
Depends on
00b245154ee2 1408324d5d55 2594278f49b2 280ef951d193 39e737fbc7a9 6d53fb7d00ec 82cf6e91d398 85ad9087a566 8efb7e14532b 9a6fac2b40a9 9e8f4a56630b a083cc802892 b11e30f5031d c3db750ed96e d60aac6c3f8a e0918b887850 ea56c56eaf90 eb5c4db673e5 ecce3719da80 f4e51e63582d f849c7889471 fad6152112b1 fc2a6d1817c0 fe128fa67a06
Depended on by
21a3ea4aab88 1215f05ff8d0 77c8c24066ef cce63af9ec54 494a1b9a8ac2 6f66e397539c e6949d87205b 3554afefb6aa 67851a868a3b f201e1bc5bcd 4f5e2af75816 fa963b1b7eb6 5cf1e8aefbb6
In bookmarks
main
In tags
v0.4.0 v0.5.0 v0.5.1 v0.5.2 v0.5.3
Edits
114 atoms, 2 tree operations, 15 files

Browse the tree at this change

added crates/flow/src/wasm.rs +347 −0
1 +
//! The WASM tier (spec §4.1, oxygenflow#75): a job's `exec` names a WASI
2 +
//! preview 1 module, or a glob of modules run one after another, which
3 +
//! wasmtime runs with the job's workspace at `/src` and nothing else: no
4 +
//! network, no other file of the runner. Every runner can offer it, and it
5 +
//! is the tier phones and browsers run (docs/handover.md).
6 +
//!
7 +
//! As in the syscall tier the module runs in a child of the runner
8 +
//! (`flow __wasm SPEC`), so the runner streams its output as it comes,
9 +
//! stops it at the time limit or when the run is cancelled, and measures
10 +
//! its memory the same way; wasmtime itself also holds it to the sandbox's
11 +
//! memory limit.
12 +
13 +
use crate::microvm::{Outcome, Sink};
14 +
use crate::syscall::{lines, self_hash, FAILED};
15 +
use anyhow::{bail, Context, Result};
16 +
use flow_core::api::Record;
17 +
use flow_core::{Environment, Job, MountSource, Sandbox};
18 +
use serde::{Deserialize, Serialize};
19 +
use std::path::{Path, PathBuf};
20 +
use std::sync::mpsc;
21 +
use std::time::{Duration, Instant};
22 +
23 +
/// The runtime, named in every receipt this tier writes.
24 +
pub const WASMTIME: &str = "49.0.4";
25 +
26 +
/// A line the helper writes to say something about the job itself (which
27 +
/// module starts), shown as the runner's own note rather than the job's.
28 +
const NOTE: &str = "\u{1e}N ";
29 +
30 +
/// The exit code for a module that trapped (crashed) rather than exiting.
31 +
const TRAPPED: i32 = 134;
32 +
33 +
/// What the helper runs, written by the runner for `flow __wasm`.
34 +
#[derive(Serialize, Deserialize)]
35 +
struct Spec {
36 +
    /// The job's files, preopened as `/src` (and as the current directory).
37 +
    workspace: PathBuf,
38 +
    /// The modules to run in turn, relative to the workspace.
39 +
    modules: Vec<String>,
40 +
    /// The arguments after the module.
41 +
    args: Vec<String>,
42 +
    env: Vec<(String, String)>,
43 +
    memory_mib: u32,
44 +
    /// The job's mounts: a directory of the runner and where the module sees it.
45 +
    preopens: Vec<(PathBuf, String)>,
46 +
}
47 +
48 +
/// The receipt environment of a job in this tier: the runtime and its
49 +
/// version, this runner's binary, the memory allowed, and every module run
50 +
/// with its hash, so the receipt says exactly what code ran.
51 +
pub fn environment(sandbox: &Sandbox, job: &Job, modules: &[(String, String)]) -> Environment {
52 +
    Environment {
53 +
        runtime: "wasm".into(),
54 +
        parts: vec![
55 +
            ("wasmtime".into(), WASMTIME.into()),
56 +
            ("flow".into(), self_hash().to_string()),
57 +
            ("memory_mib".into(), sandbox.memory_mib.to_string()),
58 +
        ]
59 +
        .into_iter()
60 +
        .chain(modules.iter().map(|(path, hash)| (format!("module {path}"), hash.clone())))
61 +
        .collect(),
62 +
        rootfs: String::new(),
63 +
        argv: job.exec.clone(),
64 +
        env: job.env.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
65 +
    }
66 +
}
67 +
68 +
/// The modules `program` names in `workspace`: one file, or the files a
69 +
/// glob matches (`*` in its last part only), sorted. A path may start with
70 +
/// `/src/`, where the module sees the workspace.
71 +
pub fn modules(workspace: &Path, program: &str) -> Result<Vec<String>> {
72 +
    let rel = program.strip_prefix("/src/").unwrap_or(program).trim_start_matches("./");
73 +
    if rel.is_empty() || rel.starts_with('/') || rel.split('/').any(|p| p == "..") {
74 +
        bail!("module {program:?}: give a path inside the job's files, such as target/wasm32-wasip1/debug/app.wasm");
75 +
    }
76 +
    let (dir, last) = rel.rsplit_once('/').unwrap_or(("", rel));
77 +
    if dir.contains('*') {
78 +
        bail!("module {program:?}: only the file name may hold `*`");
79 +
    }
80 +
    if !last.contains('*') {
81 +
        if !workspace.join(rel).is_file() {
82 +
            bail!("module {rel} is not among the job's files (its scope or an earlier job's artifact)");
83 +
        }
84 +
        return Ok(vec![rel.to_string()]);
85 +
    }
86 +
    let mut found: Vec<String> = std::fs::read_dir(workspace.join(dir))
87 +
        .with_context(|| format!("module {program:?}: the directory {dir} is not among the job's files"))?
88 +
        .filter_map(|e| e.ok())
89 +
        .filter(|e| e.file_type().is_ok_and(|t| t.is_file()))
90 +
        .filter_map(|e| e.file_name().into_string().ok())
91 +
        .filter(|name| wildcard(last, name))
92 +
        .map(|name| if dir.is_empty() { name } else { format!("{dir}/{name}") })
93 +
        .collect();
94 +
    found.sort();
95 +
    if found.is_empty() {
96 +
        bail!("no module matches {program:?}");
97 +
    }
98 +
    Ok(found)
99 +
}
100 +
101 +
/// Whether `name` matches `pattern`, where `*` stands for any run of characters.
102 +
fn wildcard(pattern: &str, name: &str) -> bool {
103 +
    let parts: Vec<&str> = pattern.split('*').collect();
104 +
    let (first, last) = (parts[0], parts[parts.len() - 1]);
105 +
    if parts.len() == 1 {
106 +
        return pattern == name;
107 +
    }
108 +
    if !name.starts_with(first) || !name[first.len()..].ends_with(last) || name.len() < first.len() + last.len() {
109 +
        return false;
110 +
    }
111 +
    let mut rest = &name[first.len()..name.len() - last.len()];
112 +
    for middle in &parts[1..parts.len() - 1] {
113 +
        match rest.find(middle) {
114 +
            Some(i) => rest = &rest[i + middle.len()..],
115 +
            None => return false,
116 +
        }
117 +
    }
118 +
    true
119 +
}
120 +
121 +
/// Run `job` in this tier with its files in `workspace` (as the syscall
122 +
/// tier lays them out); `scratch` holds the helper's spec and the job's
123 +
/// mounts.
124 +
pub fn run(sandbox: &Sandbox, job: &Job, workspace: &Path, scratch: &Path, timeout: Duration, sink: &mut dyn Sink) -> Result<Outcome> {
125 +
    if !job.secrets.is_empty() || !job.identities.is_empty() {
126 +
        bail!("job {}: the WASM tier takes no secrets or identities yet; run it in a microvm or syscall sandbox", job.name);
127 +
    }
128 +
    let Some(program) = job.exec.first() else { bail!("job {}: exec names no module", job.name) };
129 +
    let modules = modules(workspace, program)?;
130 +
    let hashed: Vec<(String, String)> =
131 +
        modules.iter().map(|m| Ok((m.clone(), crate::home::hash_file(&workspace.join(m))?))).collect::<Result<_>>()?;
132 +
    let environment = environment(sandbox, job, &hashed);
133 +
    let mut preopens = Vec::new();
134 +
    let mut disks = 0;
135 +
    for (i, m) in job.mounts.iter().enumerate() {
136 +
        let dir = match m.source {
137 +
            MountSource::Disk => {
138 +
                disks += 1;
139 +
                crate::syscall::disk_dir(scratch, disks - 1)
140 +
            }
141 +
            MountSource::Tmpfs => scratch.join(format!("tmpfs-{i}")),
142 +
        };
143 +
        std::fs::create_dir_all(&dir)?;
144 +
        preopens.push((dir, m.target.clone()));
145 +
    }
146 +
    let spec = Spec {
147 +
        workspace: workspace.to_path_buf(),
148 +
        modules,
149 +
        args: job.exec[1..].to_vec(),
150 +
        env: job.env.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
151 +
        memory_mib: sandbox.memory_mib,
152 +
        preopens,
153 +
    };
154 +
    let spec_path = scratch.join("wasm.json");
155 +
    std::fs::write(&spec_path, serde_json::to_vec(&spec)?)?;
156 +
157 +
    let started = Instant::now();
158 +
    let mut child = std::process::Command::new("/proc/self/exe")
159 +
        .arg("__wasm")
160 +
        .arg(&spec_path)
161 +
        .env_clear()
162 +
        .current_dir(scratch)
163 +
        .stdin(std::process::Stdio::null())
164 +
        .stdout(std::process::Stdio::piped())
165 +
        .stderr(std::process::Stdio::piped())
166 +
        .spawn()
167 +
        .context("start the WASM helper")?;
168 +
    let (tx, rx) = mpsc::channel::<(bool, Vec<u8>)>();
169 +
    let out = child.stdout.take().unwrap();
170 +
    let err = child.stderr.take().unwrap();
171 +
    let tx2 = tx.clone();
172 +
    let readers = [std::thread::spawn(move || lines(out, true, tx)), std::thread::spawn(move || lines(err, false, tx2))];
173 +
    let t = |s: &Instant| s.elapsed().as_millis() as u64;
174 +
    let (mut timed_out, mut cancelled, mut failed_to_start) = (false, false, false);
175 +
    let mut peak_memory_mib = None;
176 +
    let deadline = started + timeout;
177 +
    loop {
178 +
        if let Some(m) = crate::facts::peak_rss_mib(child.id()) {
179 +
            peak_memory_mib = Some(m);
180 +
        }
181 +
        match rx.recv_timeout(Duration::from_millis(200)) {
182 +
            Ok((stdout, line)) => {
183 +
                let text = String::from_utf8_lossy(&line).into_owned();
184 +
                let rec = |stream: &str, text: &str| Record { t: t(&started), stream: stream.into(), text: text.into() };
185 +
                if let Some(note) = text.strip_prefix(NOTE).filter(|_| !stdout) {
186 +
                    sink.record(rec("flow", note));
187 +
                } else if let Some(why) = text.strip_prefix(FAILED).filter(|_| !stdout) {
188 +
                    failed_to_start = true;
189 +
                    sink.record(rec("flow", &format!("the WASM tier could not run the job: {why}")));
190 +
                } else {
191 +
                    sink.record(rec(if stdout { "out" } else { "err" }, &text));
192 +
                }
193 +
            }
194 +
            Err(mpsc::RecvTimeoutError::Timeout) => {}
195 +
            Err(mpsc::RecvTimeoutError::Disconnected) => break,
196 +
        }
197 +
        if !timed_out && !cancelled && sink.cancelled() {
198 +
            cancelled = true;
199 +
            let _ = child.kill();
200 +
            sink.record(Record { t: t(&started), stream: "flow".into(), text: "stopped: the run was cancelled".into() });
201 +
        }
202 +
        if Instant::now() >= deadline && !timed_out && !cancelled {
203 +
            timed_out = true;
204 +
            let _ = child.kill();
205 +
            sink.record(Record {
206 +
                t: t(&started),
207 +
                stream: "flow".into(),
208 +
                text: format!("stopped at the time limit of {} s", timeout.as_secs()),
209 +
            });
210 +
        }
211 +
    }
212 +
    let status = child.wait()?;
213 +
    for r in readers {
214 +
        let _ = r.join();
215 +
    }
216 +
    let _ = std::fs::remove_file(&spec_path);
217 +
    let exit_code = status.code();
218 +
    if exit_code.is_none() && !timed_out && !cancelled && !failed_to_start {
219 +
        sink.record(Record {
220 +
            t: t(&started),
221 +
            stream: "flow".into(),
222 +
            text: format!("the WASM helper ended without an exit code ({status})"),
223 +
        });
224 +
    }
225 +
    Ok(Outcome {
226 +
        exit_code: if timed_out || cancelled { None } else { exit_code },
227 +
        duration_ms: t(&started),
228 +
        environment,
229 +
        timed_out,
230 +
        cancelled,
231 +
        peak_memory_mib,
232 +
        pruned: Vec::new(),
233 +
    })
234 +
}
235 +
236 +
/// `flow __wasm SPEC`: run the spec's modules in turn, each in a fresh
237 +
/// instance; the exit code is the first non-zero one, after all have run,
238 +
/// so one failing module does not hide another's results.
239 +
pub fn wasm_main(spec_path: &Path) -> i32 {
240 +
    match helper(spec_path) {
241 +
        Ok(code) => code,
242 +
        Err(e) => {
243 +
            eprintln!("{FAILED}{e:#}");
244 +
            125
245 +
        }
246 +
    }
247 +
}
248 +
249 +
/// wasmtime's own error, as this crate's: with its whole chain of causes.
250 +
fn ww<T>(r: wasmtime::Result<T>, what: impl FnOnce() -> String) -> Result<T> {
251 +
    r.map_err(|e| anyhow::anyhow!("{}: {e:#}", what()))
252 +
}
253 +
254 +
struct State {
255 +
    wasi: wasmtime_wasi::p1::WasiP1Ctx,
256 +
    limits: wasmtime::StoreLimits,
257 +
}
258 +
259 +
fn helper(spec_path: &Path) -> Result<i32> {
260 +
    let spec: Spec = serde_json::from_slice(&std::fs::read(spec_path)?).context("read the spec")?;
261 +
    let engine = ww(wasmtime::Engine::new(&wasmtime::Config::new()), || "start wasmtime".into())?;
262 +
    let mut linker: wasmtime::Linker<State> = wasmtime::Linker::new(&engine);
263 +
    ww(wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |s: &mut State| &mut s.wasi), || "link WASI".into())?;
264 +
    let mut first_failure = 0;
265 +
    for path in &spec.modules {
266 +
        let code = run_module(&engine, &linker, &spec, path)?;
267 +
        if spec.modules.len() > 1 {
268 +
            eprintln!("{NOTE}{path}: exit {code}");
269 +
        }
270 +
        if first_failure == 0 && code != 0 {
271 +
            first_failure = code;
272 +
        }
273 +
    }
274 +
    Ok(first_failure)
275 +
}
276 +
277 +
fn run_module(engine: &wasmtime::Engine, linker: &wasmtime::Linker<State>, spec: &Spec, path: &str) -> Result<i32> {
278 +
    use wasmtime_wasi::{FsPerms, WasiCtxBuilder};
279 +
    if spec.modules.len() > 1 {
280 +
        eprintln!("{NOTE}running {path}");
281 +
    }
282 +
    let module = ww(wasmtime::Module::from_file(engine, spec.workspace.join(path)), || format!("module {path} does not load"))?;
283 +
    let name = path.rsplit('/').next().unwrap_or(path);
284 +
    let mut argv = vec![name.to_string()];
285 +
    argv.extend(spec.args.iter().cloned());
286 +
    let mut wasi = WasiCtxBuilder::new();
287 +
    wasi.inherit_stdout().inherit_stderr().args(&argv).envs(&spec.env).env("PWD", "/src").allow_blocking_current_thread(true);
288 +
    let open = |wasi: &mut WasiCtxBuilder, dir: &Path, at: &str| {
289 +
        ww(wasi.preopened_dir(dir, at, FsPerms::ReadWrite).map(|_| ()), || format!("open {} as {at}", dir.display()))
290 +
    };
291 +
    open(&mut wasi, &spec.workspace, "/src")?;
292 +
    // Relative paths resolve against the workspace too.
293 +
    open(&mut wasi, &spec.workspace, ".")?;
294 +
    for (dir, target) in &spec.preopens {
295 +
        open(&mut wasi, dir, target)?;
296 +
    }
297 +
    let limits = wasmtime::StoreLimitsBuilder::new().memory_size(spec.memory_mib as usize * 1024 * 1024).build();
298 +
    let mut store = wasmtime::Store::new(engine, State { wasi: wasi.build_p1(), limits });
299 +
    store.limiter(|s| &mut s.limits);
300 +
    let instance = ww(linker.instantiate(&mut store, &module), || format!("module {path} cannot start here"))?;
301 +
    let start =
302 +
        ww(instance.get_typed_func::<(), ()>(&mut store, "_start"), || format!("module {path} has no _start: is it a WASI command?"))?;
303 +
    Ok(match start.call(&mut store, ()) {
304 +
        Ok(()) => 0,
305 +
        Err(e) => match e.downcast_ref::<wasmtime_wasi::I32Exit>() {
306 +
            Some(exit) => exit.0,
307 +
            None => {
308 +
                eprintln!("{NOTE}{path} trapped: {e:#}");
309 +
                TRAPPED
310 +
            }
311 +
        },
312 +
    })
313 +
}
314 +
315 +
#[cfg(test)]
316 +
mod tests {
317 +
    use super::*;
318 +
319 +
    #[test]
320 +
    fn globs_match_names_with_stars() {
321 +
        assert!(wildcard("*.wasm", "oxy_core-1a2b.wasm"));
322 +
        assert!(wildcard("oxy_core-*.wasm", "oxy_core-1a2b.wasm"));
323 +
        assert!(!wildcard("oxy_core-*.wasm", "oxy_core-1a2b.d"));
324 +
        assert!(wildcard("a*b*c", "aXbYc") && !wildcard("a*b*c", "aXcYb"));
325 +
        assert!(wildcard("plain.wasm", "plain.wasm") && !wildcard("plain.wasm", "other.wasm"));
326 +
    }
327 +
328 +
    #[test]
329 +
    fn modules_are_files_of_the_job() {
330 +
        let dir = tempfile::tempdir().unwrap();
331 +
        let deps = dir.path().join("target/wasm32-wasip1/debug/deps");
332 +
        std::fs::create_dir_all(&deps).unwrap();
333 +
        for f in ["b-2.wasm", "a-1.wasm", "a-1.d"] {
334 +
            std::fs::write(deps.join(f), b"").unwrap();
335 +
        }
336 +
        let ws = dir.path();
337 +
        assert_eq!(
338 +
            modules(ws, "/src/target/wasm32-wasip1/debug/deps/*.wasm").unwrap(),
339 +
            ["target/wasm32-wasip1/debug/deps/a-1.wasm", "target/wasm32-wasip1/debug/deps/b-2.wasm"]
340 +
        );
341 +
        assert_eq!(modules(ws, "./target/wasm32-wasip1/debug/deps/b-2.wasm").unwrap(), ["target/wasm32-wasip1/debug/deps/b-2.wasm"]);
342 +
        assert!(modules(ws, "target/wasm32-wasip1/debug/deps/*.so").unwrap_err().to_string().contains("no module matches"));
343 +
        assert!(modules(ws, "../etc/passwd").is_err());
344 +
        assert!(modules(ws, "/etc/x.wasm").is_err());
345 +
        assert!(modules(ws, "target/*/debug/a.wasm").unwrap_err().to_string().contains("only the file name"));
346 +
    }
347 +
}
added crates/flow/tests/wasm.rs +133 −0
1 +
//! The WASM tier (oxygenflow#75): modules written as text, run by `flow
2 +
//! run` through wasmtime. Every machine offers the tier, so nothing is
3 +
//! skipped.
4 +
5 +
use std::path::Path;
6 +
use std::process::Command;
7 +
8 +
const IMPORTS: &str = r#"
9 +
  (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
10 +
  (import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32)))
11 +
  (import "wasi_snapshot_preview1" "path_open"
12 +
    (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
13 +
  (import "wasi_snapshot_preview1" "args_sizes_get" (func $args_sizes_get (param i32 i32) (result i32)))
14 +
  (memory (export "memory") 1)
15 +
"#;
16 +
17 +
/// A module whose `_start` is `body`, with the WASI calls above.
18 +
fn module(dir: &Path, path: &str, data: &str, body: &str) {
19 +
    let text = format!("(module {IMPORTS} {data} (func (export \"_start\") (local $e i32) {body}))");
20 +
    let bytes = wat::parse_str(&text).unwrap_or_else(|e| panic!("{path}: {e}"));
21 +
    let file = dir.join(path);
22 +
    std::fs::create_dir_all(file.parent().unwrap()).unwrap();
23 +
    std::fs::write(file, bytes).unwrap();
24 +
}
25 +
26 +
/// Print the `len` bytes at 16 to fd `fd`.
27 +
fn print(fd: i32, len: i32) -> String {
28 +
    format!("(i32.store (i32.const 0) (i32.const 16)) (i32.store (i32.const 4) (i32.const {len})) (drop (call $fd_write (i32.const {fd}) (i32.const 0) (i32.const 1) (i32.const 8)))")
29 +
}
30 +
31 +
#[test]
32 +
fn wasi_modules_run_confined_in_the_wasm_tier() {
33 +
    let dir = tempfile::tempdir().unwrap();
34 +
    let home = dir.path().join("home");
35 +
    let work = dir.path().join("work");
36 +
    let tiers = Command::new(env!("CARGO_BIN_EXE_flow")).arg("--home").arg(&home).arg("tiers").output().unwrap();
37 +
    assert!(String::from_utf8_lossy(&tiers.stdout).contains("wasm"), "{}", String::from_utf8_lossy(&tiers.stdout));
38 +
39 +
    // Prints, and says how many arguments it had (2: its name and one).
40 +
    module(
41 +
        &work,
42 +
        "mods/hello.wasm",
43 +
        r#"(data (i32.const 16) "hello from wasm\n")"#,
44 +
        &format!(
45 +
            "{} (drop (call $args_sizes_get (i32.const 100) (i32.const 104))) (if (i32.ne (i32.load (i32.const 100)) (i32.const 2)) (then (call $proc_exit (i32.const 7))))",
46 +
            print(1, 16)
47 +
        ),
48 +
    );
49 +
    // Two modules under one glob: the first passes, the second exits 3.
50 +
    module(&work, "mods/each/a.wasm", r#"(data (i32.const 16) "module a\n")"#, &print(1, 9));
51 +
    module(&work, "mods/each/b.wasm", r#"(data (i32.const 16) "module b\n")"#, &format!("{} (call $proc_exit (i32.const 3))", print(2, 9)));
52 +
    // Creates a file in the workspace (preopen 3 is /src).
53 +
    module(
54 +
        &work,
55 +
        "mods/writer.wasm",
56 +
        r#"(data (i32.const 64) "made.txt") (data (i32.const 16) "made in wasm\n")"#,
57 +
        "(local.set $e (call $path_open (i32.const 3) (i32.const 0) (i32.const 64) (i32.const 8) (i32.const 9) (i64.const 0x1fffffff) (i64.const 0x1fffffff) (i32.const 0) (i32.const 200)))
58 +
         (if (local.get $e) (then (call $proc_exit (i32.const 10))))
59 +
         (i32.store (i32.const 0) (i32.const 16)) (i32.store (i32.const 4) (i32.const 13))
60 +
         (drop (call $fd_write (i32.load (i32.const 200)) (i32.const 0) (i32.const 1) (i32.const 8)))",
61 +
    );
62 +
    // Tries to create a file outside the workspace: refused, so it exits 0.
63 +
    module(
64 +
        &work,
65 +
        "mods/escape.wasm",
66 +
        r#"(data (i32.const 64) "../escaped")"#,
67 +
        "(local.set $e (call $path_open (i32.const 3) (i32.const 0) (i32.const 64) (i32.const 10) (i32.const 9) (i64.const 0x1fffffff) (i64.const 0x1fffffff) (i32.const 0) (i32.const 200)))
68 +
         (if (i32.eqz (local.get $e)) (then (call $proc_exit (i32.const 9))))",
69 +
    );
70 +
    // Asks for 512 MiB in a 256 MiB sandbox: refused, so it exits 0.
71 +
    module(
72 +
        &work,
73 +
        "mods/greedy.wasm",
74 +
        "",
75 +
        "(if (i32.ne (memory.grow (i32.const 8192)) (i32.const -1)) (then (call $proc_exit (i32.const 9))))",
76 +
    );
77 +
    module(&work, "mods/trap.wasm", "", "unreachable");
78 +
79 +
    std::fs::create_dir_all(work.join(".flow")).unwrap();
80 +
    std::fs::write(
81 +
        work.join(".flow/pipeline.kdl"),
82 +
        r#"schema-version 1
83 +
sandbox "w" {
84 +
    runtime "wasm"
85 +
    memory-limit "256MiB"
86 +
}
87 +
job "hello" {
88 +
    sandbox "w"
89 +
    exec "/src/mods/hello.wasm" "one"
90 +
}
91 +
job "each" {
92 +
    sandbox "w"
93 +
    exec "mods/each/*.wasm"
94 +
}
95 +
job "writer" {
96 +
    sandbox "w"
97 +
    exec "mods/writer.wasm"
98 +
}
99 +
job "escape" {
100 +
    sandbox "w"
101 +
    exec "mods/escape.wasm"
102 +
}
103 +
job "greedy" {
104 +
    sandbox "w"
105 +
    exec "mods/greedy.wasm"
106 +
}
107 +
job "trap" {
108 +
    sandbox "w"
109 +
    exec "mods/trap.wasm"
110 +
}
111 +
"#,
112 +
    )
113 +
    .unwrap();
114 +
    let run = Command::new(env!("CARGO_BIN_EXE_flow")).arg("--home").arg(&home).arg("run").current_dir(&work).output().unwrap();
115 +
    let out = String::from_utf8_lossy(&run.stdout).to_string() + &String::from_utf8_lossy(&run.stderr);
116 +
    for want in [
117 +
        "hello from wasm",
118 +
        "── hello passed",
119 +
        "running mods/each/a.wasm",
120 +
        "module a",
121 +
        "mods/each/b.wasm: exit 3",
122 +
        "── each failed (exit 3)",
123 +
        "── writer passed",
124 +
        "── escape passed",
125 +
        "── greedy passed",
126 +
        "mods/trap.wasm trapped",
127 +
        "── trap failed (exit 134)",
128 +
    ] {
129 +
        assert!(out.contains(want), "{want:?} not in:\n{out}");
130 +
    }
131 +
    assert!(!dir.path().join("escaped").exists() && !work.join("escaped").exists(), "a module wrote outside the workspace");
132 +
    assert_eq!(run.status.code(), Some(1), "two jobs failed:\n{out}");
133 +
}
modified CHANGELOG.md +2 −0
…
3 unchanged lines
4 4
5 5
## Unreleased
6 6
7 +
- **The WASM tier (#75):** `runtime "wasm"` runs WASI preview 1 modules with wasmtime 49 on any runner (`flow tiers` offers `wasm` everywhere): no rootfs, no network, the job's files at `/src`, its mounts at their targets, the memory limit enforced by wasmtime. `exec` names a module or a glob of them (`target/wasm32-wasip1/debug/deps/*.wasm` runs each test binary in turn); the receipt names wasmtime's version and every module's hash. The tier phones and browsers will run (docs/handover.md). Secrets and identities are not offered in it yet.
8 +
- **cargo-nextest in the Rust image (#81):** for JUnit test reports beside `cargo llvm-cov`'s coverage.
7 9
## 0.3.1 (2026-10-25)
8 10
9 11
- **Runners read repositories with oxy 0.6.0:** a tag withdrawn on the hub (oxygenhub#301) is dropped when a runner fetches, a keyless agent's changes verify in a repository that pins its owner's newest key (oxygen#135) or has never seen it (oxygen#134), and shallow clones of big repositories work (oxygen#137). The runner itself is unchanged.
…
84 unchanged lines
modified Cargo.lock +1220 −16
…
2 unchanged lines
3 3
version = 4
4 4
5 5
[[package]]
6 +
name = "addr2line"
7 +
version = "0.26.1"
8 +
source = "registry+https://github.com/rust-lang/crates.io-index"
9 +
checksum = "59317f77929f0e679d39364702289274de2f0f0b22cbf50b2b8cff2169a0b27a"
10 +
dependencies = [
11 +
 "gimli",
12 +
]
13 +
14 +
[[package]]
6 15
name = "adler2"
7 16
version = "2.0.1"
8 17
source = "registry+https://github.com/rust-lang/crates.io-index"
…
7 unchanged lines
16 25
dependencies = [
17 26
 "memchr",
18 27
]
28 +
29 +
[[package]]
30 +
name = "allocator-api2"
31 +
version = "0.2.21"
32 +
source = "registry+https://github.com/rust-lang/crates.io-index"
33 +
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
34 +
35 +
[[package]]
36 +
name = "ambient-authority"
37 +
version = "0.0.2"
38 +
source = "registry+https://github.com/rust-lang/crates.io-index"
39 +
checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b"
19 40
20 41
[[package]]
21 42
name = "anstream"
…
50 unchanged lines
72 93
version = "1.0.104"
73 94
source = "registry+https://github.com/rust-lang/crates.io-index"
74 95
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
96 +
97 +
[[package]]
98 +
name = "arbitrary"
99 +
version = "1.5.0"
100 +
source = "registry+https://github.com/rust-lang/crates.io-index"
101 +
checksum = "3bc62ac97cc33321f50863d514c3bc38a453947a8f9e781137e47c7401020aed"
75 102
76 103
[[package]]
77 104
name = "arrayvec"
…
41 unchanged lines
119 146
]
120 147
121 148
[[package]]
149 +
name = "async-trait"
150 +
version = "0.1.92"
151 +
source = "registry+https://github.com/rust-lang/crates.io-index"
152 +
checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
153 +
dependencies = [
154 +
 "proc-macro2",
155 +
 "quote",
156 +
 "syn 3.0.6",
157 +
]
158 +
159 +
[[package]]
122 160
name = "autocfg"
123 161
version = "1.5.1"
124 162
source = "registry+https://github.com/rust-lang/crates.io-index"
…
42 unchanged lines
167 205
 "cc",
168 206
 "cfg-if",
169 207
 "constant_time_eq",
170 -
 "cpufeatures",
208 +
 "cpufeatures 0.3.1",
171 209
 "rayon-core",
172 210
]
173 211
174 212
[[package]]
175 213
name = "block-buffer"
214 +
version = "0.10.4"
215 +
source = "registry+https://github.com/rust-lang/crates.io-index"
216 +
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
217 +
dependencies = [
218 +
 "generic-array",
219 +
]
220 +
221 +
[[package]]
222 +
name = "block-buffer"
176 223
version = "0.12.1"
177 224
source = "registry+https://github.com/rust-lang/crates.io-index"
178 225
checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa"
…
9 unchanged lines
188 235
dependencies = [
189 236
 "memchr",
190 237
 "serde_core",
238 +
]
239 +
240 +
[[package]]
241 +
name = "bumpalo"
242 +
version = "3.20.3"
243 +
source = "registry+https://github.com/rust-lang/crates.io-index"
244 +
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
245 +
dependencies = [
246 +
 "allocator-api2",
247 +
]
248 +
249 +
[[package]]
250 +
name = "bytes"
251 +
version = "1.12.1"
252 +
source = "registry+https://github.com/rust-lang/crates.io-index"
253 +
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
254 +
255 +
[[package]]
256 +
name = "cap-primitives"
257 +
version = "4.0.3"
258 +
source = "registry+https://github.com/rust-lang/crates.io-index"
259 +
checksum = "8b5f74729fd2f44701d1a8eb47e906cdb3ccd9ec0f02baad85a744b791940b18"
260 +
dependencies = [
261 +
 "ambient-authority",
262 +
 "fs-set-times",
263 +
 "io-extras",
264 +
 "io-lifetimes 3.0.1",
265 +
 "ipnet",
266 +
 "maybe-owned",
267 +
 "rustix",
268 +
 "rustix-linux-procfs",
269 +
 "windows-sys 0.61.2",
270 +
 "winx",
191 271
]
192 272
193 273
[[package]]
…
21 unchanged lines
215 295
checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
216 296
217 297
[[package]]
298 +
name = "chacha20"
299 +
version = "0.10.2"
300 +
source = "registry+https://github.com/rust-lang/crates.io-index"
301 +
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
302 +
dependencies = [
303 +
 "cfg-if",
304 +
 "cpufeatures 0.3.1",
305 +
 "rand_core 0.10.1",
306 +
]
307 +
308 +
[[package]]
218 309
name = "clap"
219 310
version = "4.6.7"
220 311
source = "registry+https://github.com/rust-lang/crates.io-index"
…
38 unchanged lines
259 350
version = "0.5.4"
260 351
source = "registry+https://github.com/rust-lang/crates.io-index"
261 352
checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
353 +
354 +
[[package]]
355 +
name = "cobs"
356 +
version = "0.3.0"
357 +
source = "registry+https://github.com/rust-lang/crates.io-index"
358 +
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
359 +
dependencies = [
360 +
 "thiserror 2.0.21",
361 +
]
262 362
263 363
[[package]]
264 364
name = "colorchoice"
…
14 unchanged lines
279 379
checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
280 380
281 381
[[package]]
382 +
name = "core_detect"
383 +
version = "1.0.0"
384 +
source = "registry+https://github.com/rust-lang/crates.io-index"
385 +
checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48"
386 +
387 +
[[package]]
388 +
name = "cpp_demangle"
389 +
version = "0.5.1"
390 +
source = "registry+https://github.com/rust-lang/crates.io-index"
391 +
checksum = "0667304c32ea56cb4cd6d2d7c0cfe9a2f8041229db8c033af7f8d69492429def"
392 +
dependencies = [
393 +
 "cfg-if",
394 +
]
395 +
396 +
[[package]]
282 397
name = "cpufeatures"
398 +
version = "0.2.17"
399 +
source = "registry+https://github.com/rust-lang/crates.io-index"
400 +
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
401 +
dependencies = [
402 +
 "libc",
403 +
]
404 +
405 +
[[package]]
406 +
name = "cpufeatures"
283 407
version = "0.3.1"
284 408
source = "registry+https://github.com/rust-lang/crates.io-index"
285 409
checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566"
286 410
dependencies = [
287 411
 "libc",
412 +
]
413 +
414 +
[[package]]
415 +
name = "cranelift-assembler-x64"
416 +
version = "0.136.4"
417 +
source = "registry+https://github.com/rust-lang/crates.io-index"
418 +
checksum = "c9c587da2696fbaa58e7a2fa2e5bfdd365d0928219f36992304ac1f15e5bc254"
419 +
dependencies = [
420 +
 "cranelift-assembler-x64-meta",
288 421
]
289 422
290 423
[[package]]
424 +
name = "cranelift-assembler-x64-meta"
425 +
version = "0.136.4"
426 +
source = "registry+https://github.com/rust-lang/crates.io-index"
427 +
checksum = "f28a60027b7556b680b051651291053ec381edf4ffbc01784997ae51a64269bb"
428 +
dependencies = [
429 +
 "cranelift-srcgen",
430 +
]
431 +
432 +
[[package]]
433 +
name = "cranelift-bforest"
434 +
version = "0.136.4"
435 +
source = "registry+https://github.com/rust-lang/crates.io-index"
436 +
checksum = "62bfdb846acebfd591d601994ea283c98d525ac0bc9a84ca3f2c36bcf5b69ff1"
437 +
dependencies = [
438 +
 "cranelift-entity",
439 +
 "wasmtime-internal-core",
440 +
]
441 +
442 +
[[package]]
443 +
name = "cranelift-bitset"
444 +
version = "0.136.4"
445 +
source = "registry+https://github.com/rust-lang/crates.io-index"
446 +
checksum = "aa9f8cc1080739d5f72b4ee7e00aff7d589f1284beaf0a19472c07878be7f299"
447 +
dependencies = [
448 +
 "serde",
449 +
 "serde_derive",
450 +
 "wasmtime-internal-core",
451 +
]
452 +
453 +
[[package]]
454 +
name = "cranelift-codegen"
455 +
version = "0.136.4"
456 +
source = "registry+https://github.com/rust-lang/crates.io-index"
457 +
checksum = "d85417d493ecec833b5134546b4a252c78cc0bd5be11729a35d25dcff9e4e70b"
458 +
dependencies = [
459 +
 "bumpalo",
460 +
 "cranelift-assembler-x64",
461 +
 "cranelift-bforest",
462 +
 "cranelift-bitset",
463 +
 "cranelift-codegen-meta",
464 +
 "cranelift-codegen-shared",
465 +
 "cranelift-control",
466 +
 "cranelift-entity",
467 +
 "cranelift-isle",
468 +
 "gimli",
469 +
 "hashbrown 0.17.1",
470 +
 "libm",
471 +
 "log",
472 +
 "postcard",
473 +
 "pulley-interpreter",
474 +
 "regalloc2",
475 +
 "rustc-hash",
476 +
 "serde",
477 +
 "serde_derive",
478 +
 "sha2 0.10.9",
479 +
 "smallvec",
480 +
 "target-lexicon",
481 +
 "wasmtime-internal-core",
482 +
]
483 +
484 +
[[package]]
485 +
name = "cranelift-codegen-meta"
486 +
version = "0.136.4"
487 +
source = "registry+https://github.com/rust-lang/crates.io-index"
488 +
checksum = "d01c8ed0098360bae69ad6b82952d4247516799ce8050d45ad168d6689f4eae6"
489 +
dependencies = [
490 +
 "cranelift-assembler-x64-meta",
491 +
 "cranelift-codegen-shared",
492 +
 "cranelift-srcgen",
493 +
 "heck",
494 +
 "pulley-interpreter",
495 +
]
496 +
497 +
[[package]]
498 +
name = "cranelift-codegen-shared"
499 +
version = "0.136.4"
500 +
source = "registry+https://github.com/rust-lang/crates.io-index"
501 +
checksum = "04f9b86d809cec9c4e88b201f1b3ed3b0347674c9ccfbb8c355228669e34be81"
502 +
503 +
[[package]]
504 +
name = "cranelift-control"
505 +
version = "0.136.4"
506 +
source = "registry+https://github.com/rust-lang/crates.io-index"
507 +
checksum = "ce182038fb10b719841e65fdf5deeee258c684f63439f5be680c2be059274b58"
508 +
dependencies = [
509 +
 "arbitrary",
510 +
]
511 +
512 +
[[package]]
513 +
name = "cranelift-entity"
514 +
version = "0.136.4"
515 +
source = "registry+https://github.com/rust-lang/crates.io-index"
516 +
checksum = "7bca812b03a7b942796391f25bc02aa70a1a007fee3ce2756490c788429e9c39"
517 +
dependencies = [
518 +
 "cranelift-bitset",
519 +
 "serde",
520 +
 "serde_derive",
521 +
 "wasmtime-internal-core",
522 +
]
523 +
524 +
[[package]]
525 +
name = "cranelift-frontend"
526 +
version = "0.136.4"
527 +
source = "registry+https://github.com/rust-lang/crates.io-index"
528 +
checksum = "a0c30563d2aef95e8d1a00a920199c99117b350339599f0e9487a7a1cf5d59de"
529 +
dependencies = [
530 +
 "cranelift-codegen",
531 +
 "hashbrown 0.17.1",
532 +
 "log",
533 +
 "smallvec",
534 +
 "target-lexicon",
535 +
]
536 +
537 +
[[package]]
538 +
name = "cranelift-isle"
539 +
version = "0.136.4"
540 +
source = "registry+https://github.com/rust-lang/crates.io-index"
541 +
checksum = "9c54184333a275698edb1d3bdff226131a25d47133d792aa716e47e32b8b7f05"
542 +
543 +
[[package]]
544 +
name = "cranelift-native"
545 +
version = "0.136.4"
546 +
source = "registry+https://github.com/rust-lang/crates.io-index"
547 +
checksum = "eb67a4c8a3180b5f1d77dffcd6317c05386ced42e5a31c7004523a9d99dc85c1"
548 +
dependencies = [
549 +
 "cranelift-codegen",
550 +
 "libc",
551 +
 "target-lexicon",
552 +
]
553 +
554 +
[[package]]
555 +
name = "cranelift-srcgen"
556 +
version = "0.136.4"
557 +
source = "registry+https://github.com/rust-lang/crates.io-index"
558 +
checksum = "b533db1679b4b728568bd490da6533cf50974c48a4d7534e78f1e0e02bc39769"
559 +
560 +
[[package]]
291 561
name = "crc32fast"
292 562
version = "1.5.2"
293 563
source = "registry+https://github.com/rust-lang/crates.io-index"
…
26 unchanged lines
320 590
version = "0.8.23"
321 591
source = "registry+https://github.com/rust-lang/crates.io-index"
322 592
checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6"
593 +
594 +
[[package]]
595 +
name = "crypto-common"
596 +
version = "0.1.7"
597 +
source = "registry+https://github.com/rust-lang/crates.io-index"
598 +
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
599 +
dependencies = [
600 +
 "generic-array",
601 +
 "typenum",
602 +
]
323 603
324 604
[[package]]
325 605
name = "crypto-common"
…
22 unchanged lines
348 628
checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23"
349 629
dependencies = [
350 630
 "cfg-if",
351 -
 "cpufeatures",
631 +
 "cpufeatures 0.3.1",
352 632
 "curve25519-dalek-derive",
353 -
 "digest",
633 +
 "digest 0.11.3",
354 634
 "fiat-crypto",
355 635
 "rustc_version",
356 636
 "subtle",
…
46 unchanged lines
403 683
version = "0.5.8"
404 684
source = "registry+https://github.com/rust-lang/crates.io-index"
405 685
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
686 +
687 +
[[package]]
688 +
name = "digest"
689 +
version = "0.10.7"
690 +
source = "registry+https://github.com/rust-lang/crates.io-index"
691 +
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
692 +
dependencies = [
693 +
 "block-buffer 0.10.4",
694 +
 "crypto-common 0.1.7",
695 +
]
406 696
407 697
[[package]]
408 698
name = "digest"
…
1 unchanged lines
410 700
source = "registry+https://github.com/rust-lang/crates.io-index"
411 701
checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
412 702
dependencies = [
413 -
 "block-buffer",
703 +
 "block-buffer 0.12.1",
414 704
 "const-oid",
415 -
 "crypto-common",
705 +
 "crypto-common 0.2.2",
416 706
]
417 707
418 708
[[package]]
…
24 unchanged lines
443 733
dependencies = [
444 734
 "curve25519-dalek",
445 735
 "ed25519",
446 -
 "sha2",
736 +
 "sha2 0.11.0",
447 737
 "subtle",
448 738
 "zeroize",
449 739
]
…
3 unchanged lines
453 743
version = "1.18.0"
454 744
source = "registry+https://github.com/rust-lang/crates.io-index"
455 745
checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34"
746 +
747 +
[[package]]
748 +
name = "embedded-io"
749 +
version = "0.4.0"
750 +
source = "registry+https://github.com/rust-lang/crates.io-index"
751 +
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
752 +
753 +
[[package]]
754 +
name = "embedded-io"
755 +
version = "0.6.1"
756 +
source = "registry+https://github.com/rust-lang/crates.io-index"
757 +
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
758 +
759 +
[[package]]
760 +
name = "encoding_rs"
761 +
version = "0.8.42"
762 +
source = "registry+https://github.com/rust-lang/crates.io-index"
763 +
checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679"
764 +
dependencies = [
765 +
 "cfg-if",
766 +
 "core_detect",
767 +
 "multiversion_no_op",
768 +
 "rustversion",
769 +
 "scopeguard",
770 +
 "simdutf8",
771 +
]
456 772
457 773
[[package]]
458 774
name = "equivalent"
…
61 unchanged lines
520 836
 "tempfile",
521 837
 "toml",
522 838
 "ureq",
839 +
 "wasmtime",
840 +
 "wasmtime-wasi",
841 +
 "wat",
523 842
]
524 843
525 844
[[package]]
…
31 unchanged lines
557 876
 "serde_json",
558 877
 "tempfile",
559 878
]
879 +
880 +
[[package]]
881 +
name = "fnv"
882 +
version = "1.0.7"
883 +
source = "registry+https://github.com/rust-lang/crates.io-index"
884 +
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
560 885
561 886
[[package]]
887 +
name = "foldhash"
888 +
version = "0.2.0"
889 +
source = "registry+https://github.com/rust-lang/crates.io-index"
890 +
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
891 +
892 +
[[package]]
562 893
name = "form_urlencoded"
563 894
version = "1.2.2"
564 895
source = "registry+https://github.com/rust-lang/crates.io-index"
565 896
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
566 897
dependencies = [
567 898
 "percent-encoding",
899 +
]
900 +
901 +
[[package]]
902 +
name = "fs-set-times"
903 +
version = "0.20.3"
904 +
source = "registry+https://github.com/rust-lang/crates.io-index"
905 +
checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a"
906 +
dependencies = [
907 +
 "io-lifetimes 2.0.4",
908 +
 "rustix",
909 +
 "windows-sys 0.52.0",
568 910
]
569 911
570 912
[[package]]
…
9 unchanged lines
580 922
 "page_size",
581 923
 "smallvec",
582 924
 "zerocopy",
925 +
]
926 +
927 +
[[package]]
928 +
name = "futures"
929 +
version = "0.3.34"
930 +
source = "registry+https://github.com/rust-lang/crates.io-index"
931 +
checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
932 +
dependencies = [
933 +
 "futures-channel",
934 +
 "futures-core",
935 +
 "futures-io",
936 +
 "futures-sink",
937 +
 "futures-task",
938 +
 "futures-util",
939 +
]
940 +
941 +
[[package]]
942 +
name = "futures-channel"
943 +
version = "0.3.34"
944 +
source = "registry+https://github.com/rust-lang/crates.io-index"
945 +
checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
946 +
dependencies = [
947 +
 "futures-core",
948 +
 "futures-sink",
949 +
]
950 +
951 +
[[package]]
952 +
name = "futures-core"
953 +
version = "0.3.34"
954 +
source = "registry+https://github.com/rust-lang/crates.io-index"
955 +
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
956 +
957 +
[[package]]
958 +
name = "futures-io"
959 +
version = "0.3.34"
960 +
source = "registry+https://github.com/rust-lang/crates.io-index"
961 +
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
962 +
963 +
[[package]]
964 +
name = "futures-sink"
965 +
version = "0.3.34"
966 +
source = "registry+https://github.com/rust-lang/crates.io-index"
967 +
checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
968 +
969 +
[[package]]
970 +
name = "futures-task"
971 +
version = "0.3.34"
972 +
source = "registry+https://github.com/rust-lang/crates.io-index"
973 +
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
974 +
975 +
[[package]]
976 +
name = "futures-util"
977 +
version = "0.3.34"
978 +
source = "registry+https://github.com/rust-lang/crates.io-index"
979 +
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
980 +
dependencies = [
981 +
 "futures-channel",
982 +
 "futures-core",
983 +
 "futures-io",
984 +
 "futures-sink",
985 +
 "futures-task",
986 +
 "memchr",
987 +
 "pin-project-lite",
988 +
 "slab",
989 +
]
990 +
991 +
[[package]]
992 +
name = "generic-array"
993 +
version = "0.14.7"
994 +
source = "registry+https://github.com/rust-lang/crates.io-index"
995 +
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
996 +
dependencies = [
997 +
 "typenum",
998 +
 "version_check",
583 999
]
584 1000
585 1001
[[package]]
…
17 unchanged lines
603 1019
 "libc",
604 1020
 "r-efi",
605 1021
 "rand_core 0.10.1",
1022 +
]
1023 +
1024 +
[[package]]
1025 +
name = "gimli"
1026 +
version = "0.33.0"
1027 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1028 +
checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c"
1029 +
dependencies = [
1030 +
 "fnv",
1031 +
 "hashbrown 0.16.1",
1032 +
 "indexmap",
1033 +
 "stable_deref_trait",
606 1034
]
607 1035
608 1036
[[package]]
…
11 unchanged lines
620 1048
621 1049
[[package]]
622 1050
name = "hashbrown"
1051 +
version = "0.16.1"
1052 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1053 +
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
1054 +
1055 +
[[package]]
1056 +
name = "hashbrown"
623 1057
version = "0.17.1"
624 1058
source = "registry+https://github.com/rust-lang/crates.io-index"
625 1059
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
1060 +
dependencies = [
1061 +
 "foldhash",
1062 +
 "serde",
1063 +
 "serde_core",
1064 +
]
626 1065
627 1066
[[package]]
628 1067
name = "heck"
…
101 unchanged lines
730 1169
]
731 1170
732 1171
[[package]]
1172 +
name = "id-arena"
1173 +
version = "2.3.0"
1174 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1175 +
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
1176 +
1177 +
[[package]]
733 1178
name = "idna"
734 1179
version = "1.1.0"
735 1180
source = "registry+https://github.com/rust-lang/crates.io-index"
…
37 unchanged lines
773 1218
checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
774 1219
dependencies = [
775 1220
 "equivalent",
776 -
 "hashbrown",
1221 +
 "hashbrown 0.17.1",
1222 +
 "serde",
1223 +
 "serde_core",
1224 +
]
1225 +
1226 +
[[package]]
1227 +
name = "io-extras"
1228 +
version = "0.19.0"
1229 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1230 +
checksum = "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f"
1231 +
dependencies = [
1232 +
 "io-lifetimes 3.0.1",
1233 +
 "windows-sys 0.52.0",
777 1234
]
778 1235
779 1236
[[package]]
1237 +
name = "io-lifetimes"
1238 +
version = "2.0.4"
1239 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1240 +
checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983"
1241 +
1242 +
[[package]]
1243 +
name = "io-lifetimes"
1244 +
version = "3.0.1"
1245 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1246 +
checksum = "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96"
1247 +
1248 +
[[package]]
1249 +
name = "ipnet"
1250 +
version = "2.12.2"
1251 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1252 +
checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0"
1253 +
1254 +
[[package]]
780 1255
name = "is_terminal_polyfill"
781 1256
version = "1.70.2"
782 1257
source = "registry+https://github.com/rust-lang/crates.io-index"
783 1258
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
1259 +
1260 +
[[package]]
1261 +
name = "itertools"
1262 +
version = "0.14.0"
1263 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1264 +
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
1265 +
dependencies = [
1266 +
 "either",
1267 +
]
784 1268
785 1269
[[package]]
786 1270
name = "itoa"
…
43 unchanged lines
830 1314
checksum = "d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598"
831 1315
dependencies = [
832 1316
 "cfg-if",
833 -
 "cpufeatures",
1317 +
 "cpufeatures 0.3.1",
834 1318
]
835 1319
836 1320
[[package]]
…
3 unchanged lines
840 1324
checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb"
841 1325
842 1326
[[package]]
1327 +
name = "leb128"
1328 +
version = "0.2.7"
1329 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1330 +
checksum = "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52"
1331 +
1332 +
[[package]]
1333 +
name = "leb128fmt"
1334 +
version = "0.1.0"
1335 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1336 +
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
1337 +
1338 +
[[package]]
843 1339
name = "libc"
844 1340
version = "0.2.189"
845 1341
source = "registry+https://github.com/rust-lang/crates.io-index"
846 1342
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
1343 +
1344 +
[[package]]
1345 +
name = "libm"
1346 +
version = "0.2.16"
1347 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1348 +
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
847 1349
848 1350
[[package]]
849 1351
name = "linux-raw-sys"
…
12 unchanged lines
862 1364
version = "0.4.34"
863 1365
source = "registry+https://github.com/rust-lang/crates.io-index"
864 1366
checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
1367 +
1368 +
[[package]]
1369 +
name = "mach2"
1370 +
version = "0.6.0"
1371 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1372 +
checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
1373 +
1374 +
[[package]]
1375 +
name = "maybe-owned"
1376 +
version = "0.3.4"
1377 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1378 +
checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4"
865 1379
866 1380
[[package]]
867 1381
name = "memchr"
…
2 unchanged lines
870 1384
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
871 1385
872 1386
[[package]]
1387 +
name = "memfd"
1388 +
version = "0.6.6"
1389 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1390 +
checksum = "57804b2c9b69967f1536a56f86297e367a33b19e98852ed624b84551cdbc0d90"
1391 +
dependencies = [
1392 +
 "rustix",
1393 +
]
1394 +
1395 +
[[package]]
873 1396
name = "miette"
874 1397
version = "7.6.0"
875 1398
source = "registry+https://github.com/rust-lang/crates.io-index"
…
1 unchanged lines
877 1400
dependencies = [
878 1401
 "cfg-if",
879 1402
 "miette-derive",
880 -
 "unicode-width",
1403 +
 "unicode-width 0.1.14",
881 1404
]
882 1405
883 1406
[[package]]
…
24 unchanged lines
908 1431
]
909 1432
910 1433
[[package]]
1434 +
name = "mio"
1435 +
version = "1.2.4"
1436 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1437 +
checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee"
1438 +
dependencies = [
1439 +
 "libc",
1440 +
 "wasi",
1441 +
 "windows-sys 0.61.2",
1442 +
]
1443 +
1444 +
[[package]]
911 1445
name = "ml-dsa"
912 1446
version = "0.1.1"
913 1447
source = "registry+https://github.com/rust-lang/crates.io-index"
914 1448
checksum = "add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d"
915 1449
dependencies = [
916 1450
 "const-oid",
917 -
 "crypto-common",
1451 +
 "crypto-common 0.2.2",
918 1452
 "ctutils",
919 1453
 "hybrid-array",
920 1454
 "module-lattice",
…
14 unchanged lines
935 1469
]
936 1470
937 1471
[[package]]
1472 +
name = "multiversion_no_op"
1473 +
version = "1.0.0"
1474 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1475 +
checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d"
1476 +
1477 +
[[package]]
938 1478
name = "nix"
939 1479
version = "0.29.0"
940 1480
source = "registry+https://github.com/rust-lang/crates.io-index"
…
50 unchanged lines
991 1531
]
992 1532
993 1533
[[package]]
1534 +
name = "object"
1535 +
version = "0.40.0"
1536 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1537 +
checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c"
1538 +
dependencies = [
1539 +
 "crc32fast",
1540 +
 "hashbrown 0.17.1",
1541 +
 "indexmap",
1542 +
 "memchr",
1543 +
]
1544 +
1545 +
[[package]]
994 1546
name = "oid-registry"
995 1547
version = "0.8.1"
996 1548
source = "registry+https://github.com/rust-lang/crates.io-index"
…
26 unchanged lines
1023 1575
 "libc",
1024 1576
 "memchr",
1025 1577
 "ml-dsa",
1026 -
 "rand",
1578 +
 "rand 0.8.8",
1027 1579
 "rayon",
1028 1580
 "rustls",
1029 1581
 "rustls-pemfile",
1030 1582
 "serde_json",
1031 -
 "sha2",
1583 +
 "sha2 0.11.0",
1032 1584
 "similar",
1033 1585
 "thiserror 1.0.69",
1034 1586
 "ureq",
…
28 unchanged lines
1063 1615
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
1064 1616
1065 1617
[[package]]
1618 +
name = "pin-project-lite"
1619 +
version = "0.2.17"
1620 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1621 +
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
1622 +
1623 +
[[package]]
1066 1624
name = "pkcs8"
1067 1625
version = "0.11.0"
1068 1626
source = "registry+https://github.com/rust-lang/crates.io-index"
…
8 unchanged lines
1077 1635
version = "0.3.34"
1078 1636
source = "registry+https://github.com/rust-lang/crates.io-index"
1079 1637
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
1638 +
1639 +
[[package]]
1640 +
name = "postcard"
1641 +
version = "1.1.3"
1642 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1643 +
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
1644 +
dependencies = [
1645 +
 "cobs",
1646 +
 "embedded-io 0.4.0",
1647 +
 "embedded-io 0.6.1",
1648 +
 "serde",
1649 +
]
1080 1650
1081 1651
[[package]]
1082 1652
name = "potential_utf"
…
26 unchanged lines
1109 1679
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
1110 1680
dependencies = [
1111 1681
 "unicode-ident",
1682 +
]
1683 +
1684 +
[[package]]
1685 +
name = "pulley-interpreter"
1686 +
version = "49.0.4"
1687 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1688 +
checksum = "5cd3de43f4f4cff536de8902097edbdf749321b97dda548f36a37918eb85bba3"
1689 +
dependencies = [
1690 +
 "cranelift-bitset",
1691 +
 "log",
1692 +
 "pulley-macros",
1693 +
 "wasmtime-internal-core",
1112 1694
]
1113 1695
1114 1696
[[package]]
1697 +
name = "pulley-macros"
1698 +
version = "49.0.4"
1699 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1700 +
checksum = "8319a8fa5269b4895957f8795861c42822bd26218e495f70060a963323d94847"
1701 +
dependencies = [
1702 +
 "proc-macro2",
1703 +
 "quote",
1704 +
 "syn 2.0.119",
1705 +
]
1706 +
1707 +
[[package]]
1115 1708
name = "quote"
1116 1709
version = "1.0.47"
1117 1710
source = "registry+https://github.com/rust-lang/crates.io-index"
…
20 unchanged lines
1138 1731
]
1139 1732
1140 1733
[[package]]
1734 +
name = "rand"
1735 +
version = "0.10.3"
1736 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1737 +
checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"
1738 +
dependencies = [
1739 +
 "chacha20",
1740 +
 "getrandom 0.4.3",
1741 +
 "rand_core 0.10.1",
1742 +
]
1743 +
1744 +
[[package]]
1141 1745
name = "rand_chacha"
1142 1746
version = "0.3.1"
1143 1747
source = "registry+https://github.com/rust-lang/crates.io-index"
…
50 unchanged lines
1194 1798
 "time",
1195 1799
 "x509-parser",
1196 1800
 "yasna",
1801 +
]
1802 +
1803 +
[[package]]
1804 +
name = "regalloc2"
1805 +
version = "0.15.2"
1806 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1807 +
checksum = "757712e8e61590d6d4f5d563483755538b5aa13467837a3b41cd9832509a7f85"
1808 +
dependencies = [
1809 +
 "allocator-api2",
1810 +
 "bumpalo",
1811 +
 "hashbrown 0.17.1",
1812 +
 "log",
1813 +
 "rustc-hash",
1814 +
 "serde",
1815 +
 "smallvec",
1197 1816
]
1198 1817
1199 1818
[[package]]
…
26 unchanged lines
1226 1845
 "untrusted",
1227 1846
 "windows-sys 0.52.0",
1228 1847
]
1848 +
1849 +
[[package]]
1850 +
name = "rustc-demangle"
1851 +
version = "0.1.28"
1852 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1853 +
checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb"
1229 1854
1230 1855
[[package]]
1856 +
name = "rustc-hash"
1857 +
version = "2.1.3"
1858 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1859 +
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
1860 +
1861 +
[[package]]
1231 1862
name = "rustc_version"
1232 1863
version = "0.4.1"
1233 1864
source = "registry+https://github.com/rust-lang/crates.io-index"
…
25 unchanged lines
1259 1890
]
1260 1891
1261 1892
[[package]]
1893 +
name = "rustix-linux-procfs"
1894 +
version = "0.1.1"
1895 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1896 +
checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056"
1897 +
dependencies = [
1898 +
 "once_cell",
1899 +
 "rustix",
1900 +
]
1901 +
1902 +
[[package]]
1262 1903
name = "rustls"
1263 1904
version = "0.23.45"
1264 1905
source = "registry+https://github.com/rust-lang/crates.io-index"
…
38 unchanged lines
1303 1944
]
1304 1945
1305 1946
[[package]]
1947 +
name = "rustversion"
1948 +
version = "1.0.23"
1949 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1950 +
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
1951 +
1952 +
[[package]]
1306 1953
name = "same-file"
1307 1954
version = "1.0.6"
1308 1955
source = "registry+https://github.com/rust-lang/crates.io-index"
…
3 unchanged lines
1312 1959
]
1313 1960
1314 1961
[[package]]
1962 +
name = "scopeguard"
1963 +
version = "1.2.0"
1964 +
source = "registry+https://github.com/rust-lang/crates.io-index"
1965 +
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
1966 +
1967 +
[[package]]
1315 1968
name = "semver"
1316 1969
version = "1.0.28"
1317 1970
source = "registry+https://github.com/rust-lang/crates.io-index"
1318 1971
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
1972 +
dependencies = [
1973 +
 "serde",
1974 +
 "serde_core",
1975 +
]
1319 1976
1320 1977
[[package]]
1321 1978
name = "serde"
…
45 unchanged lines
1367 2024
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
1368 2025
dependencies = [
1369 2026
 "serde",
2027 +
]
2028 +
2029 +
[[package]]
2030 +
name = "sha2"
2031 +
version = "0.10.9"
2032 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2033 +
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
2034 +
dependencies = [
2035 +
 "cfg-if",
2036 +
 "cpufeatures 0.2.17",
2037 +
 "digest 0.10.7",
1370 2038
]
1371 2039
1372 2040
[[package]]
…
3 unchanged lines
1376 2044
checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
1377 2045
dependencies = [
1378 2046
 "cfg-if",
1379 -
 "cpufeatures",
1380 -
 "digest",
2047 +
 "cpufeatures 0.3.1",
2048 +
 "digest 0.11.3",
1381 2049
]
1382 2050
1383 2051
[[package]]
…
2 unchanged lines
1386 2054
source = "registry+https://github.com/rust-lang/crates.io-index"
1387 2055
checksum = "09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a"
1388 2056
dependencies = [
1389 -
 "digest",
2057 +
 "digest 0.11.3",
1390 2058
 "keccak",
1391 2059
 "sponge-cursor",
1392 2060
]
…
10 unchanged lines
1403 2071
source = "registry+https://github.com/rust-lang/crates.io-index"
1404 2072
checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5"
1405 2073
dependencies = [
1406 -
 "digest",
2074 +
 "digest 0.11.3",
1407 2075
 "rand_core 0.10.1",
1408 2076
]
1409 2077
…
2 unchanged lines
1412 2080
version = "0.3.10"
1413 2081
source = "registry+https://github.com/rust-lang/crates.io-index"
1414 2082
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
2083 +
2084 +
[[package]]
2085 +
name = "simdutf8"
2086 +
version = "0.1.5"
2087 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2088 +
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
1415 2089
1416 2090
[[package]]
1417 2091
name = "similar"
…
2 unchanged lines
1420 2094
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
1421 2095
1422 2096
[[package]]
2097 +
name = "slab"
2098 +
version = "0.4.12"
2099 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2100 +
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
2101 +
2102 +
[[package]]
1423 2103
name = "smallvec"
1424 2104
version = "1.16.2"
1425 2105
source = "registry+https://github.com/rust-lang/crates.io-index"
1426 2106
checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e"
2107 +
dependencies = [
2108 +
 "serde",
2109 +
]
1427 2110
1428 2111
[[package]]
2112 +
name = "socket2"
2113 +
version = "0.6.5"
2114 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2115 +
checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
2116 +
dependencies = [
2117 +
 "libc",
2118 +
 "windows-sys 0.61.2",
2119 +
]
2120 +
2121 +
[[package]]
1429 2122
name = "spki"
1430 2123
version = "0.8.0"
1431 2124
source = "registry+https://github.com/rust-lang/crates.io-index"
…
70 unchanged lines
1502 2195
 "quote",
1503 2196
 "syn 3.0.6",
1504 2197
]
2198 +
2199 +
[[package]]
2200 +
name = "target-lexicon"
2201 +
version = "0.13.5"
2202 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2203 +
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
1505 2204
1506 2205
[[package]]
1507 2206
name = "tempfile"
…
9 unchanged lines
1517 2216
]
1518 2217
1519 2218
[[package]]
2219 +
name = "termcolor"
2220 +
version = "1.4.1"
2221 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2222 +
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
2223 +
dependencies = [
2224 +
 "winapi-util",
2225 +
]
2226 +
2227 +
[[package]]
1520 2228
name = "thiserror"
1521 2229
version = "1.0.69"
1522 2230
source = "registry+https://github.com/rust-lang/crates.io-index"
…
74 unchanged lines
1597 2305
]
1598 2306
1599 2307
[[package]]
2308 +
name = "tokio"
2309 +
version = "1.54.1"
2310 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2311 +
checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3"
2312 +
dependencies = [
2313 +
 "bytes",
2314 +
 "libc",
2315 +
 "mio",
2316 +
 "pin-project-lite",
2317 +
 "socket2",
2318 +
 "windows-sys 0.61.2",
2319 +
]
2320 +
2321 +
[[package]]
1600 2322
name = "toml"
1601 2323
version = "0.8.23"
1602 2324
source = "registry+https://github.com/rust-lang/crates.io-index"
…
33 unchanged lines
1636 2358
version = "0.1.2"
1637 2359
source = "registry+https://github.com/rust-lang/crates.io-index"
1638 2360
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
2361 +
2362 +
[[package]]
2363 +
name = "tracing"
2364 +
version = "0.1.44"
2365 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2366 +
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
2367 +
dependencies = [
2368 +
 "pin-project-lite",
2369 +
 "tracing-attributes",
2370 +
 "tracing-core",
2371 +
]
1639 2372
1640 2373
[[package]]
2374 +
name = "tracing-attributes"
2375 +
version = "0.1.31"
2376 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2377 +
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
2378 +
dependencies = [
2379 +
 "proc-macro2",
2380 +
 "quote",
2381 +
 "syn 2.0.119",
2382 +
]
2383 +
2384 +
[[package]]
2385 +
name = "tracing-core"
2386 +
version = "0.1.36"
2387 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2388 +
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
2389 +
dependencies = [
2390 +
 "once_cell",
2391 +
]
2392 +
2393 +
[[package]]
1641 2394
name = "typenum"
1642 2395
version = "1.20.1"
1643 2396
source = "registry+https://github.com/rust-lang/crates.io-index"
…
12 unchanged lines
1656 2409
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
1657 2410
1658 2411
[[package]]
2412 +
name = "unicode-width"
2413 +
version = "0.2.2"
2414 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2415 +
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
2416 +
2417 +
[[package]]
1659 2418
name = "untrusted"
1660 2419
version = "0.9.0"
1661 2420
source = "registry+https://github.com/rust-lang/crates.io-index"
…
42 unchanged lines
1704 2463
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
1705 2464
1706 2465
[[package]]
2466 +
name = "version_check"
2467 +
version = "0.9.5"
2468 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2469 +
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
2470 +
2471 +
[[package]]
1707 2472
name = "walkdir"
1708 2473
version = "2.5.0"
1709 2474
source = "registry+https://github.com/rust-lang/crates.io-index"
…
10 unchanged lines
1720 2485
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
1721 2486
1722 2487
[[package]]
2488 +
name = "wasm-encoder"
2489 +
version = "0.258.3"
2490 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2491 +
checksum = "f64765e43c000fae008a48db8b288e175e237fc9ce20a26586836878c1bee89f"
2492 +
dependencies = [
2493 +
 "leb128fmt",
2494 +
 "wasmparser 0.258.3",
2495 +
]
2496 +
2497 +
[[package]]
2498 +
name = "wasm-encoder"
2499 +
version = "0.262.0"
2500 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2501 +
checksum = "4495a6f85dd94c411c749303efcbc5defade0b0cbdbc0541495241ab917a9b5a"
2502 +
dependencies = [
2503 +
 "leb128fmt",
2504 +
 "wasmparser 0.262.0",
2505 +
]
2506 +
2507 +
[[package]]
2508 +
name = "wasm-metadata"
2509 +
version = "0.258.3"
2510 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2511 +
checksum = "47e10808eb27efde692f1b1706089fe19296728bf872291f5b4e0d50fba88f2f"
2512 +
dependencies = [
2513 +
 "anyhow",
2514 +
 "indexmap",
2515 +
 "wasm-encoder 0.258.3",
2516 +
 "wasmparser 0.258.3",
2517 +
]
2518 +
2519 +
[[package]]
2520 +
name = "wasmparser"
2521 +
version = "0.258.3"
2522 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2523 +
checksum = "fe9269dd817e0e7021bf534ccd9761bc2d64778b6708e41228b8439d75eaa0b1"
2524 +
dependencies = [
2525 +
 "bitflags",
2526 +
 "hashbrown 0.17.1",
2527 +
 "indexmap",
2528 +
 "semver",
2529 +
 "serde",
2530 +
]
2531 +
2532 +
[[package]]
2533 +
name = "wasmparser"
2534 +
version = "0.262.0"
2535 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2536 +
checksum = "974d643b125b272607e2fff8012ea14a8328acd7621e4bafa7afb32500052b1b"
2537 +
dependencies = [
2538 +
 "bitflags",
2539 +
 "indexmap",
2540 +
 "semver",
2541 +
]
2542 +
2543 +
[[package]]
2544 +
name = "wasmprinter"
2545 +
version = "0.258.3"
2546 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2547 +
checksum = "14a457ba8670a3db3d357c1aeac3ed4fe378a76054a221789f0df0ea507e292b"
2548 +
dependencies = [
2549 +
 "anyhow",
2550 +
 "termcolor",
2551 +
 "wasmparser 0.258.3",
2552 +
]
2553 +
2554 +
[[package]]
2555 +
name = "wasmtime"
2556 +
version = "49.0.4"
2557 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2558 +
checksum = "36abb25de5518707e5ba96b586366b09db168d2d4976cb9dac57265a317497ea"
2559 +
dependencies = [
2560 +
 "addr2line",
2561 +
 "async-trait",
2562 +
 "bitflags",
2563 +
 "bumpalo",
2564 +
 "cc",
2565 +
 "encoding_rs",
2566 +
 "futures",
2567 +
 "libc",
2568 +
 "log",
2569 +
 "mach2",
2570 +
 "memfd",
2571 +
 "object",
2572 +
 "once_cell",
2573 +
 "postcard",
2574 +
 "pulley-interpreter",
2575 +
 "rayon",
2576 +
 "rustix",
2577 +
 "semver",
2578 +
 "serde",
2579 +
 "serde_derive",
2580 +
 "smallvec",
2581 +
 "target-lexicon",
2582 +
 "wasmparser 0.258.3",
2583 +
 "wasmtime-environ",
2584 +
 "wasmtime-internal-component-macro",
2585 +
 "wasmtime-internal-component-util",
2586 +
 "wasmtime-internal-core",
2587 +
 "wasmtime-internal-cranelift",
2588 +
 "wasmtime-internal-fiber",
2589 +
 "wasmtime-internal-jit-debug",
2590 +
 "wasmtime-internal-jit-icache-coherence",
2591 +
 "wasmtime-internal-unwinder",
2592 +
 "wasmtime-internal-versioned-export-macros",
2593 +
 "windows-sys 0.61.2",
2594 +
]
2595 +
2596 +
[[package]]
2597 +
name = "wasmtime-environ"
2598 +
version = "49.0.4"
2599 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2600 +
checksum = "92f16a4d09fb1fbf2dcfeddb9818e1517a258e13b505b3bfdadcf47a19bf31ca"
2601 +
dependencies = [
2602 +
 "anyhow",
2603 +
 "cpp_demangle",
2604 +
 "cranelift-bforest",
2605 +
 "cranelift-bitset",
2606 +
 "cranelift-entity",
2607 +
 "gimli",
2608 +
 "hashbrown 0.17.1",
2609 +
 "indexmap",
2610 +
 "log",
2611 +
 "object",
2612 +
 "postcard",
2613 +
 "rustc-demangle",
2614 +
 "semver",
2615 +
 "serde",
2616 +
 "serde_derive",
2617 +
 "sha2 0.10.9",
2618 +
 "smallvec",
2619 +
 "target-lexicon",
2620 +
 "wasm-encoder 0.258.3",
2621 +
 "wasmparser 0.258.3",
2622 +
 "wasmprinter",
2623 +
 "wasmtime-internal-component-util",
2624 +
 "wasmtime-internal-core",
2625 +
]
2626 +
2627 +
[[package]]
2628 +
name = "wasmtime-internal-component-macro"
2629 +
version = "49.0.4"
2630 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2631 +
checksum = "d4fca03bd4425856574c0807d1dee16fad43f947feaf4e9ae1d2129596ee4de4"
2632 +
dependencies = [
2633 +
 "anyhow",
2634 +
 "proc-macro2",
2635 +
 "quote",
2636 +
 "syn 2.0.119",
2637 +
 "wasmtime-internal-component-util",
2638 +
 "wasmtime-internal-wit-bindgen",
2639 +
 "wit-parser",
2640 +
]
2641 +
2642 +
[[package]]
2643 +
name = "wasmtime-internal-component-util"
2644 +
version = "49.0.4"
2645 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2646 +
checksum = "4006009fc3598af4e895ab18c6c33d2c6b7c657b1bd0a755ca7ee1abef6f0c16"
2647 +
2648 +
[[package]]
2649 +
name = "wasmtime-internal-core"
2650 +
version = "49.0.4"
2651 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2652 +
checksum = "947a732ad659f42c10ec639706fc8cb1f068dd9a55eebde8a1f24dfd06dfa525"
2653 +
dependencies = [
2654 +
 "hashbrown 0.17.1",
2655 +
 "libm",
2656 +
 "serde",
2657 +
]
2658 +
2659 +
[[package]]
2660 +
name = "wasmtime-internal-cranelift"
2661 +
version = "49.0.4"
2662 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2663 +
checksum = "fbfb8b455d524939e03df42e3e749f8e26e26ba2acd8b08fa00b3bda55686750"
2664 +
dependencies = [
2665 +
 "cranelift-codegen",
2666 +
 "cranelift-control",
2667 +
 "cranelift-entity",
2668 +
 "cranelift-frontend",
2669 +
 "cranelift-native",
2670 +
 "gimli",
2671 +
 "itertools",
2672 +
 "log",
2673 +
 "object",
2674 +
 "pulley-interpreter",
2675 +
 "smallvec",
2676 +
 "target-lexicon",
2677 +
 "thiserror 2.0.21",
2678 +
 "wasmparser 0.258.3",
2679 +
 "wasmtime-environ",
2680 +
 "wasmtime-internal-core",
2681 +
 "wasmtime-internal-unwinder",
2682 +
 "wasmtime-internal-versioned-export-macros",
2683 +
]
2684 +
2685 +
[[package]]
2686 +
name = "wasmtime-internal-fiber"
2687 +
version = "49.0.4"
2688 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2689 +
checksum = "bd8aa8711f68b2cdd94c2b85ba5c8317edaa1ac4ee0a0534b957123680239307"
2690 +
dependencies = [
2691 +
 "cc",
2692 +
 "libc",
2693 +
 "rustix",
2694 +
 "wasmtime-environ",
2695 +
 "wasmtime-internal-versioned-export-macros",
2696 +
 "windows-sys 0.61.2",
2697 +
]
2698 +
2699 +
[[package]]
2700 +
name = "wasmtime-internal-jit-debug"
2701 +
version = "49.0.4"
2702 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2703 +
checksum = "e873e4504faf50aa8ce255d6ea7210d87b39d5f379c2486782e2c5f179c70ca8"
2704 +
dependencies = [
2705 +
 "cc",
2706 +
 "wasmtime-internal-versioned-export-macros",
2707 +
]
2708 +
2709 +
[[package]]
2710 +
name = "wasmtime-internal-jit-icache-coherence"
2711 +
version = "49.0.4"
2712 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2713 +
checksum = "197ab1fda5da958a5c0b8a97eb241beafc48ac568b82ef4f12f38d6866c74173"
2714 +
dependencies = [
2715 +
 "libc",
2716 +
 "wasmtime-internal-core",
2717 +
 "windows-sys 0.61.2",
2718 +
]
2719 +
2720 +
[[package]]
2721 +
name = "wasmtime-internal-unwinder"
2722 +
version = "49.0.4"
2723 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2724 +
checksum = "5577f3a5a979a7c3b1b23c1e9f13e70a8583acc8828471ec56f282117fc4952b"
2725 +
dependencies = [
2726 +
 "cranelift-codegen",
2727 +
 "log",
2728 +
 "object",
2729 +
 "wasmtime-environ",
2730 +
]
2731 +
2732 +
[[package]]
2733 +
name = "wasmtime-internal-versioned-export-macros"
2734 +
version = "49.0.4"
2735 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2736 +
checksum = "f6399c9c4050ed431cf66e21c05fadd6f9731db44476f452f8c7142b4597b883"
2737 +
dependencies = [
2738 +
 "proc-macro2",
2739 +
 "quote",
2740 +
 "syn 2.0.119",
2741 +
]
2742 +
2743 +
[[package]]
2744 +
name = "wasmtime-internal-wit-bindgen"
2745 +
version = "49.0.4"
2746 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2747 +
checksum = "b4eaf45d4da7681d234bb6efd846b4a528b08a75384a7fc23f125d0145364b06"
2748 +
dependencies = [
2749 +
 "anyhow",
2750 +
 "bitflags",
2751 +
 "heck",
2752 +
 "indexmap",
2753 +
 "wit-component",
2754 +
 "wit-parser",
2755 +
]
2756 +
2757 +
[[package]]
2758 +
name = "wasmtime-wasi"
2759 +
version = "49.0.4"
2760 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2761 +
checksum = "821e45765c35555d3b0bdf9277cb99478f7d1f29a17b3315ba76e01220f02a38"
2762 +
dependencies = [
2763 +
 "async-trait",
2764 +
 "bitflags",
2765 +
 "bytes",
2766 +
 "cap-primitives",
2767 +
 "futures",
2768 +
 "rand 0.10.3",
2769 +
 "rustix",
2770 +
 "rustix-linux-procfs",
2771 +
 "thiserror 2.0.21",
2772 +
 "tokio",
2773 +
 "tracing",
2774 +
 "url",
2775 +
 "wasmtime",
2776 +
 "wasmtime-wasi-io",
2777 +
 "wiggle",
2778 +
 "windows-sys 0.61.2",
2779 +
 "winx",
2780 +
]
2781 +
2782 +
[[package]]
2783 +
name = "wasmtime-wasi-io"
2784 +
version = "49.0.4"
2785 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2786 +
checksum = "8cdff38d1c730bdaf4fcfbe0eedf3265fb9c7a4deb119deecbfc1c1778950716"
2787 +
dependencies = [
2788 +
 "async-trait",
2789 +
 "bytes",
2790 +
 "futures",
2791 +
 "tracing",
2792 +
 "wasmtime",
2793 +
]
2794 +
2795 +
[[package]]
2796 +
name = "wast"
2797 +
version = "35.0.2"
2798 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2799 +
checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68"
2800 +
dependencies = [
2801 +
 "leb128",
2802 +
]
2803 +
2804 +
[[package]]
2805 +
name = "wast"
2806 +
version = "262.0.0"
2807 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2808 +
checksum = "30612a0c29249b5f185888a107e8a519d920226b7d07f9d351fd094e9f75eb23"
2809 +
dependencies = [
2810 +
 "bumpalo",
2811 +
 "leb128fmt",
2812 +
 "memchr",
2813 +
 "unicode-width 0.2.2",
2814 +
 "wasm-encoder 0.262.0",
2815 +
]
2816 +
2817 +
[[package]]
2818 +
name = "wat"
2819 +
version = "1.262.0"
2820 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2821 +
checksum = "e228027f2b07bbaf946980ebbe2437fca73be6f54c40c2a8d4f42f277075f8d1"
2822 +
dependencies = [
2823 +
 "wast 262.0.0",
2824 +
]
2825 +
2826 +
[[package]]
1723 2827
name = "webpki-roots"
1724 2828
version = "0.26.11"
1725 2829
source = "registry+https://github.com/rust-lang/crates.io-index"
…
12 unchanged lines
1738 2842
]
1739 2843
1740 2844
[[package]]
2845 +
name = "wiggle"
2846 +
version = "49.0.4"
2847 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2848 +
checksum = "af3872869836d404f722e2361f869c09630e43a73fcc7060f7892a929b74b6a3"
2849 +
dependencies = [
2850 +
 "bitflags",
2851 +
 "thiserror 2.0.21",
2852 +
 "tracing",
2853 +
 "wasmtime",
2854 +
 "wasmtime-environ",
2855 +
 "wiggle-macro",
2856 +
]
2857 +
2858 +
[[package]]
2859 +
name = "wiggle-generate"
2860 +
version = "49.0.4"
2861 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2862 +
checksum = "cf7e31dec6de37e7e848aecbad54777dd246cd440a1a547ab1a1e31c27f55e49"
2863 +
dependencies = [
2864 +
 "heck",
2865 +
 "proc-macro2",
2866 +
 "quote",
2867 +
 "syn 2.0.119",
2868 +
 "wasmtime-environ",
2869 +
 "witx",
2870 +
]
2871 +
2872 +
[[package]]
2873 +
name = "wiggle-macro"
2874 +
version = "49.0.4"
2875 +
source = "registry+https://github.com/rust-lang/crates.io-index"
2876 +
checksum = "a2af323f33b28ea84b24e2bccef19e51c7a75aa1d2929280ad1a4865f2877dcc"
2877 +
dependencies = [
2878 +
 "proc-macro2",
2879 +
 "quote",
2880 +
 "syn 2.0.119",
2881 +
 "wiggle-generate",
2882 +
]
2883 +
2884 +
[[package]]
1741 2885
name = "winapi"
1742 2886
version = "0.3.9"
1743 2887
source = "registry+https://github.com/rust-lang/crates.io-index"
…
119 unchanged lines
1863 3007
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
1864 3008
dependencies = [
1865 3009
 "memchr",
3010 +
]
3011 +
3012 +
[[package]]
3013 +
name = "winx"
3014 +
version = "0.36.4"
3015 +
source = "registry+https://github.com/rust-lang/crates.io-index"
3016 +
checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d"
3017 +
dependencies = [
3018 +
 "bitflags",
3019 +
 "windows-sys 0.52.0",
3020 +
]
3021 +
3022 +
[[package]]
3023 +
name = "wit-component"
3024 +
version = "0.258.3"
3025 +
source = "registry+https://github.com/rust-lang/crates.io-index"
3026 +
checksum = "f0fca88950af0c1f42bc77e17315e48798b8d68340171b6d204f62bc19a878a6"
3027 +
dependencies = [
3028 +
 "anyhow",
3029 +
 "bitflags",
3030 +
 "indexmap",
3031 +
 "log",
3032 +
 "serde",
3033 +
 "serde_derive",
3034 +
 "serde_json",
3035 +
 "wasm-encoder 0.258.3",
3036 +
 "wasm-metadata",
3037 +
 "wasmparser 0.258.3",
3038 +
 "wit-parser",
3039 +
]
3040 +
3041 +
[[package]]
3042 +
name = "wit-parser"
3043 +
version = "0.258.3"
3044 +
source = "registry+https://github.com/rust-lang/crates.io-index"
3045 +
checksum = "72a2127663dcf3ee16614fb0e3c33d5c6c66fec9dad317a8b0fdd3869487a533"
3046 +
dependencies = [
3047 +
 "anyhow",
3048 +
 "hashbrown 0.17.1",
3049 +
 "id-arena",
3050 +
 "indexmap",
3051 +
 "log",
3052 +
 "semver",
3053 +
 "serde",
3054 +
 "serde_derive",
3055 +
 "serde_json",
3056 +
 "unicode-ident",
3057 +
 "wasmparser 0.258.3",
3058 +
]
3059 +
3060 +
[[package]]
3061 +
name = "witx"
3062 +
version = "0.9.1"
3063 +
source = "registry+https://github.com/rust-lang/crates.io-index"
3064 +
checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b"
3065 +
dependencies = [
3066 +
 "anyhow",
3067 +
 "log",
3068 +
 "thiserror 1.0.69",
3069 +
 "wast 35.0.2",
1866 3070
]
1867 3071
1868 3072
[[package]]
…
175 unchanged lines
modified crates/flow-core/src/pipeline.rs +15 −5
…
780 unchanged lines
781 781
                runtime = match ctx.one_string(c).as_deref() {
782 782
                    Some("microvm") => Some(Runtime::Microvm),
783 783
                    Some("syscall") | Some("gvisor") => Some(Runtime::Syscall),
784 -
                    Some("wasm") => {
785 -
                        ctx.err(c.span(), "runtime \"wasm\" is not in M0 yet; use \"microvm\" or \"syscall\"");
786 -
                        None
787 -
                    }
784 +
                    // A WASI module run by wasmtime (spec §4.1, oxygenflow#75).
785 +
                    Some("wasm") => Some(Runtime::Wasm),
788 786
                    Some(other) => {
789 787
                        ctx.err(c.span(), format!("runtime {other:?}: expected \"microvm\", \"syscall\" or \"wasm\""));
790 788
                        None
…
79 unchanged lines
870 868
            other => ctx.err(c.span(), format!("unknown sandbox setting `{other}`")),
871 869
        }
872 870
    }
873 -
    if rootfs.is_none() && !seen.contains("rootfs") {
871 +
    // A WASM sandbox has no image: its module is a file of the job (its
872 +
    // scope or an earlier job's artifact), and it reaches no network.
873 +
    let wasm = runtime == Some(Runtime::Wasm);
874 +
    if wasm {
875 +
        if seen.contains("rootfs") {
876 +
            ctx.err(node.span(), format!("sandbox {name:?}: runtime \"wasm\" takes no rootfs; its module is a file the job has"));
877 +
        }
878 +
        if network.is_some_and(|n| n != Network::Isolated) {
879 +
            ctx.err(node.span(), format!("sandbox {name:?}: runtime \"wasm\" has no network; leave out `network` or say \"isolated\""));
880 +
        }
881 +
        rootfs = Some(String::new());
882 +
        network = Some(Network::Isolated);
883 +
    } else if rootfs.is_none() && !seen.contains("rootfs") {
874 884
        ctx.err(node.span(), format!("sandbox {name:?} needs a rootfs"));
875 885
    }
876 886
    if network == Some(Network::Egress) {
…
712 unchanged lines
modified crates/flow-core/src/tests.rs +15 −1
…
96 unchanged lines
97 97
fn m0_refuses_what_it_cannot_honour() {
98 98
    let src = format!("schema-version 1\nsandbox \"s\" {{\n  runtime \"wasm\"\n  rootfs \"cas://blob/{ROOTFS}\"\n  network \"wifi\"\n}}\njob \"a\" {{ sandbox \"s\"; exec \"true\"; }}\n");
99 99
    let ps = problems(&src);
100 -
    assert!(ps.iter().any(|(l, m)| *l == 3 && m.contains("wasm")), "{ps:?}");
100 +
    // A WASM sandbox has no image (oxygenflow#75).
101 +
    assert!(ps.iter().any(|(l, m)| *l == 2 && m.contains("takes no rootfs")), "{ps:?}");
101 102
    assert!(ps.iter().any(|(l, m)| *l == 5 && m.contains("isolated")), "{ps:?}");
102 103
    assert!(problems("schema-version 2\n").iter().any(|(_, m)| m.contains("schema-version 2")));
103 104
    assert!(problems(&format!(
…
609 unchanged lines
713 714
    assert_ne!(p.hash(), Pipeline::parse(&job("")).unwrap().hash(), "part of the job");
714 715
    assert!(problems(&job("    environment \"Prod env\"\n")).iter().any(|(_, m)| m.contains("1 to 32 of a-z 0-9 -")));
715 716
}
717 +
718 +
/// oxygenflow#75: a WASM sandbox needs no rootfs and has no network; its
719 +
/// job's exec names the module.
720 +
#[test]
721 +
fn a_wasm_sandbox_runs_a_module() {
722 +
    let src = "schema-version 1\nsandbox \"w\" {\n  runtime \"wasm\"\n  memory-limit \"512MiB\"\n}\njob \"t\" {\n  sandbox \"w\"\n  exec \"target/wasm32-wasip1/debug/deps/*.wasm\" \"--quiet\"\n}\n";
723 +
    let p = Pipeline::parse(src).unwrap_or_else(|ps| panic!("{:?}", ps.0));
724 +
    let sb = &p.sandboxes["w"];
725 +
    assert_eq!((sb.runtime, sb.rootfs.as_str(), sb.network, sb.memory_mib), (Runtime::Wasm, "", Network::Isolated, 512));
726 +
    let networked =
727 +
        "schema-version 1\nsandbox \"w\" {\n  runtime \"wasm\"\n  network \"loopback\"\n}\njob \"t\" { sandbox \"w\"; exec \"a.wasm\"; }\n";
728 +
    assert!(problems(networked).iter().any(|(_, m)| m.contains("has no network")));
729 +
}
modified crates/flow/Cargo.toml +5 −0
…
25 unchanged lines
26 26
libc = "0.2"
27 27
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
28 28
rcgen = "0.14"
29 +
# The WASM tier (oxygenflow#75): Cranelift-compiled WASI preview 1 modules.
30 +
wasmtime = { version = "=49.0.4", default-features = false, features = ["cranelift", "runtime", "std", "parallel-compilation"] }
31 +
wasmtime-wasi = { version = "=49.0.4", default-features = false, features = ["p1"] }
29 32
30 33
[dev-dependencies]
31 34
tempfile.workspace = true
35 +
# Test modules written as text.
36 +
wat = "1"
modified crates/flow/src/main.rs +9 −4
…
17 unchanged lines
18 18
mod swarm;
19 19
mod syscall;
20 20
mod wait;
21 +
mod wasm;
21 22
mod workspace;
22 23
23 24
use anyhow::{bail, Context, Result};
…
99 unchanged lines
123 124
    /// Check that this machine can run the syscall tier
124 125
    #[command(name = "__sandbox-probe", hide = true)]
125 126
    SandboxProbe,
127 +
    /// The WASM tier's helper, started by the runner for each job
128 +
    #[command(name = "__wasm", hide = true)]
129 +
    Wasm { spec: PathBuf },
126 130
}
127 131
128 132
#[derive(Subcommand)]
…
43 unchanged lines
172 176
    match cli.cmd {
173 177
        Cmd::Sandbox { spec } => std::process::exit(syscall::sandbox_main(&spec)),
174 178
        Cmd::SandboxProbe => std::process::exit(syscall::probe_main()),
179 +
        Cmd::Wasm { spec } => std::process::exit(wasm::wasm_main(&spec)),
175 180
        Cmd::Check { file } => check(&file.unwrap_or_else(|| PathBuf::from(PIPELINE_PATH))),
176 181
        Cmd::Hash { file } => {
177 182
            println!("{}", home::hash_file(&file)?);
…
311 unchanged lines
489 494
            continue;
490 495
        }
491 496
        let sb = &p.sandboxes[&job.sandbox];
492 -
        if sb.runtime == Runtime::Wasm {
493 -
            bail!("job {}: runtime {} is not available in this build yet", job.name, sb.runtime.as_str());
494 -
        }
495 497
        println!("── {} ({})", job.name, job.exec.join(" "));
496 498
        let js = scratch.join(&job.name);
497 499
        std::fs::create_dir_all(&js)?;
…
17 unchanged lines
515 517
            })
516 518
            .collect::<Result<Vec<_>>>()?;
517 519
        // Each job starts from the same files: jobs do not share writes.
518 -
        let out = if sb.runtime == Runtime::Syscall {
520 +
        let out = if sb.runtime == Runtime::Wasm {
521 +
            workspace::copy_tree(&scratch.join("tree"), &js.join("tree"))?;
522 +
            wasm::run(sb, job, &js.join("tree"), &js, timeout, &mut |r: Record| print_record(&r))?
523 +
        } else if sb.runtime == Runtime::Syscall {
519 524
            workspace::copy_tree(&scratch.join("tree"), &js.join("tree"))?;
520 525
            let group = format!("local-{}-{}", std::process::id(), js.file_name().unwrap_or_default().to_string_lossy());
521 526
            syscall::run(home, sb, job, &inputs, &js.join("tree"), &js, timeout, &mut |r: Record| print_record(&r), &group)?
…
48 unchanged lines
modified crates/flow/src/runner.rs +34 −17
…
455 unchanged lines
456 456
        Ok(()) => have.push("syscall".to_string()),
457 457
        Err(e) => missing.push(format!("syscall: {e}")),
458 458
    }
459 +
    // wasmtime runs on every machine this binary does (oxygenflow#75).
460 +
    have.push("wasm".to_string());
459 461
    if have.is_empty() {
460 462
        return Err(format!("no isolation tier can run here: {}", missing.join("; ")));
461 463
    }
…
66 unchanged lines
528 530
                return Some(format!("the syscall tier cannot run here: {e}"));
529 531
            }
530 532
        }
531 -
        flow_core::Runtime::Wasm => return Some("this runner has no wasm tier".into()),
533 +
        // No image and no architecture: only the memory matters.
534 +
        flow_core::Runtime::Wasm => {
535 +
            return available_memory_mib()
536 +
                .filter(|free| *free < u64::from(sb.memory_mib))
537 +
                .map(|free| format!("only {free} MiB of memory is free here; the sandbox needs {} MiB", sb.memory_mib));
538 +
        }
532 539
    }
533 540
    sandbox_problem(home, sb, std::env::consts::ARCH, available_memory_mib())
534 541
}
…
446 unchanged lines
981 988
        }
982 989
        // The syscall tier runs on the tree itself; a microVM gets an image.
983 990
        let syscall_tier = claim.sandbox.runtime == flow_core::Runtime::Syscall;
991 +
        let wasm_tier = claim.sandbox.runtime == flow_core::Runtime::Wasm;
992 +
        // The syscall and WASM tiers see the job's files as a directory;
993 +
        // the MicroVM tier as an ext4 image.
994 +
        let dir_tier = syscall_tier || wasm_tier;
984 995
        let job = claim.job.in_sandbox(&claim.sandbox).with_flow_env(&claim.flow_env());
985 996
        // Disk mounts that name a cache start from a kept disk (#28): a
986 997
        // microVM takes an image already in place as it is, the syscall tier
…
6 unchanged lines
993 1004
            note(&mut sink, format!("waited {} for another job imaging its workspace", secs(asked.elapsed())));
994 1005
        }
995 1006
        let pool = crate::cache::Pool::new(&home.root, cfg.cache_gb);
996 -
        let form = if syscall_tier { crate::cache::Form::Dir } else { crate::cache::Form::Image };
1007 +
        let form = if dir_tier { crate::cache::Form::Dir } else { crate::cache::Form::Image };
997 1008
        let cache_ctx =
998 1009
            crate::cache::Ctx { repo: &claim.repo, bookmark: &claim.bookmark, job: &claim.job.name, image: &claim.sandbox.rootfs, form };
999 1010
        let mut cached: Vec<(usize, String, String)> = Vec::new();
…
29 unchanged lines
1029 1040
            }
1030 1041
            sources
1031 1042
        };
1032 -
        if !syscall_tier {
1043 +
        if !dir_tier {
1033 1044
            workspace::image(&scratch.join("tree"), &scratch.join("workspace.ext4"))?;
1034 1045
            std::fs::remove_dir_all(scratch.join("tree"))?;
1035 1046
        }
…
2 unchanged lines
1038 1049
        if microvm::Sink::cancelled(&mut sink) {
1039 1050
            return Ok(cancelled());
1040 1051
        }
1041 -
        note(
1042 -
            &mut sink,
1043 -
            format!(
1044 -
                "{}: {} {}, {} MiB, rootfs {}",
1045 -
                if syscall_tier { "starting a syscall sandbox" } else { "booting a microVM" },
1046 -
                claim.sandbox.cpus,
1047 -
                if syscall_tier { "CPU" } else { "vCPU" },
1048 -
                claim.sandbox.memory_mib,
1049 -
                &claim.sandbox.rootfs[..12]
1050 -
            ),
1051 -
        );
1052 +
        if wasm_tier {
1053 +
            note(&mut sink, format!("starting WASM (wasmtime {}): {} MiB", crate::wasm::WASMTIME, claim.sandbox.memory_mib));
1054 +
        } else {
1055 +
            note(
1056 +
                &mut sink,
1057 +
                format!(
1058 +
                    "{}: {} {}, {} MiB, rootfs {}",
1059 +
                    if syscall_tier { "starting a syscall sandbox" } else { "booting a microVM" },
1060 +
                    claim.sandbox.cpus,
1061 +
                    if syscall_tier { "CPU" } else { "vCPU" },
1062 +
                    claim.sandbox.memory_mib,
1063 +
                    &claim.sandbox.rootfs[..12]
1064 +
                ),
1065 +
            );
1066 +
        }
1052 1067
        let timeout = Duration::from_secs(claim.timeout_s);
1053 -
        let mut outcome = if syscall_tier {
1068 +
        let mut outcome = if wasm_tier {
1069 +
            crate::wasm::run(&claim.sandbox, &job, &scratch.join("tree"), &scratch, timeout, &mut sink)?
1070 +
        } else if syscall_tier {
1054 1071
            let group = format!("job-{}", claim.job_id);
1055 1072
            crate::syscall::run(home, &claim.sandbox, &job, &claim.secrets, &scratch.join("tree"), &scratch, timeout, &mut sink, &group)?
1056 1073
        } else {
…
18 unchanged lines
1075 1092
        let wanted = claim.job.outputs.iter().filter(|o| passed || o.always);
1076 1093
        for o in wanted {
1077 1094
            if o.kind == flow_core::OutputKind::Report {
1078 -
                let read = if syscall_tier {
1095 +
                let read = if dir_tier {
1079 1096
                    let (dir, inner) = crate::outputs::locate_dir(&claim.job, &scratch.join("tree"), &scratch, &o.path);
1080 1097
                    crate::outputs::read_report_dir(&dir, &inner)
1081 1098
                } else {
…
18 unchanged lines
1100 1117
                }
1101 1118
                continue;
1102 1119
            }
1103 -
            let read = if syscall_tier {
1120 +
            let read = if dir_tier {
1104 1121
                let (dir, inner) = crate::outputs::locate_dir(&claim.job, &scratch.join("tree"), &scratch, &o.path);
1105 1122
                crate::outputs::read_dir_file(&dir, &inner)
1106 1123
            } else {
…
658 unchanged lines
modified crates/flow/src/syscall.rs +3 −3
…
53 unchanged lines
54 54
    }
55 55
}
56 56
57 -
fn self_hash() -> &'static str {
57 +
pub(crate) fn self_hash() -> &'static str {
58 58
    static HASH: OnceLock<String> = OnceLock::new();
59 59
    HASH.get_or_init(|| crate::home::hash_file(Path::new("/proc/self/exe")).unwrap_or_else(|_| "unknown".into()))
60 60
}
…
235 unchanged lines
296 296
}
297 297
298 298
/// How the helper says the job never started, on its stderr.
299 -
const FAILED: &str = "\u{1e}F ";
299 +
pub(crate) const FAILED: &str = "\u{1e}F ";
300 300
301 -
fn lines(r: impl Read, stdout: bool, tx: mpsc::Sender<(bool, Vec<u8>)>) {
301 +
pub(crate) fn lines(r: impl Read, stdout: bool, tx: mpsc::Sender<(bool, Vec<u8>)>) {
302 302
    let mut r = BufReader::new(r);
303 303
    let mut buf = Vec::new();
304 304
    loop {
…
561 unchanged lines
replaced deps/oxygen +0 −0

No line changes.

modified docs/handover.md +1 −1
…
86 unchanged lines
87 87
88 88
## 5. The WASM tier (oxygenflow#75)
89 89
90 -
Spec §4.1 names it; it is not built (`runtime "wasm"` is refused today).
90 +
Spec §4.1 names it; built 2026-10-25 (wasmtime 49, WASI preview 1).
91 91
92 92
- wasmtime, WASI preview 1 first (preview 2 components later).
93 93
- A virtual file system holding the job's scope and inputs; outputs
…
178 unchanged lines
modified docs/spec.md +18 −4
…
190 unchanged lines
191 191
OxygenFlow implements three distinct isolation tiers depending on the workload:
192 192
193 193
### 4.1 Level 0: WASM Component Sandbox
194 -
- Intended for static linters, formatters, doc generators, and policy checks.
195 -
- Runs on a standard WebAssembly System Interface (WASI) runtime.
196 -
- Startup latency: < 5 ms.
197 -
- Zero host I/O; virtualized file system presented in-memory.
194 +
- Intended for static linters, formatters, doc generators, policy checks, and
195 +
  test suites built for `wasm32-wasip1`; the tier phones and browsers run
196 +
  (docs/handover.md).
197 +
- Built (oxygenflow#75): wasmtime 49 runs WASI preview 1 modules, each in a
198 +
  fresh instance, compiled by Cranelift (tens of milliseconds a module).
199 +
  Preview 2 components later.
200 +
- `runtime "wasm"`; no `rootfs` and no network (`network` absent or
201 +
  `"isolated"`); `memory-limit` holds the module's linear memory.
202 +
- `exec` names the module, a path among the job's files (its scope or an
203 +
  earlier job's artifact), optionally under `/src/`, or a glob with `*` in
204 +
  its file name: each match runs in turn, and the job's exit code is the
205 +
  first non-zero one after all have run. The rest of `exec` are the
206 +
  module's arguments. A module that traps exits 134.
207 +
- The job's files are the only host files it sees, preopened as `/src` (and
208 +
  as the current directory, for relative paths); each `mount` is preopened at
209 +
  its target. Secrets and identities are not offered yet.
210 +
- The receipt's environment names `wasmtime` and its version, the runner
211 +
  binary, the memory, and every module run with its BLAKE3.
198 212
199 213
### 4.2 Level 1: Intercepted Syscall Isolation (gVisor / Landlock + seccomp-bpf)
200 214
- Intended for standard compilation and hermetic test suites.
…
606 unchanged lines
modified images/rust/Dockerfile +7 −0
…
42 unchanged lines
43 43
 && ln -sf /opt/cargo-llvm-cov/bin/cargo-llvm-cov /usr/local/bin/cargo-llvm-cov \
44 44
 && rm -rf /usr/local/cargo/registry /usr/local/cargo/git
45 45
46 +
# Test reports (oxygenflow#81): cargo-nextest writes JUnit XML, which the
47 +
# hub reads as a job's `junit` artifact; `cargo llvm-cov nextest` gives the
48 +
# LCOV coverage and the JUnit report from one run of the tests.
49 +
RUN cargo install --locked --version 0.9.148 --root /opt/cargo-nextest cargo-nextest \
50 +
 && ln -sf /opt/cargo-nextest/bin/cargo-nextest /usr/local/bin/cargo-nextest \
51 +
 && rm -rf /usr/local/cargo/registry /usr/local/cargo/git
52 +
46 53
ARG NODE_VERSION
47 54
ARG NODE_SHA256
48 55
ADD https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz /tmp/node.tar.xz
…
31 unchanged lines
modified images/rust/README.md +1 −0
…
5 unchanged lines
6 6
- Node 24.21.0, checked against its published SHA-256.
7 7
- git, make and pkg-config.
8 8
- Coverage: llvm-tools and cargo-llvm-cov 0.9.1, so a job can write an LCOV report for the hub's Coverage tab.
9 +
- Test reports: cargo-nextest 0.9.148, so a job can write JUnit XML for the hub (with `cargo llvm-cov nextest`, both from one run).
9 10
- Release cross-building: the Windows, Linux arm64 and riscv64, and macOS targets, zig 0.16.0 (checked against its SHA-256), cargo-zigbuild and MinGW, with zip, so `scripts/dist.sh` runs in a job.
10 11
- Every crate that oxygen, oxygenhub and oxygenflow use, vendored in `/opt/vendor`.
11 12
…
42 unchanged lines