From aa838a8f7c6dc30abe32ac4f2d7a37c42f7d83dc Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 13:47:00 +0100 Subject: [PATCH 01/40] Wasm Runtime. Initial commit --- Cargo.lock | 1135 ++++++++++++++++- Makefile | 1 + modules/runtime/wasm-runtime/Cargo.toml | 29 + modules/runtime/wasm-runtime/src/main.rs | 64 + modules/runtime/wasm-runtime/src/mod_doc.yaml | 71 ++ 5 files changed, 1292 insertions(+), 8 deletions(-) create mode 100644 modules/runtime/wasm-runtime/Cargo.toml create mode 100644 modules/runtime/wasm-runtime/src/main.rs create mode 100644 modules/runtime/wasm-runtime/src/mod_doc.yaml diff --git a/Cargo.lock b/Cargo.lock index 1cd0b5d3..a5563071 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,15 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" @@ -262,6 +271,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -333,7 +348,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" dependencies = [ - "object", + "object 0.32.2", ] [[package]] @@ -705,6 +720,9 @@ name = "bumpalo" version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +dependencies = [ + "allocator-api2", +] [[package]] name = "byte-unit" @@ -776,6 +794,84 @@ dependencies = [ "libbz2-rs-sys", ] +[[package]] +name = "cap-fs-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.59.0", +] + +[[package]] +name = "cap-net-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix 1.1.3", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix 1.1.3", + "rustix-linux-procfs", + "windows-sys 0.59.0", + "winx", +] + +[[package]] +name = "cap-rand" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8144c22e24bbcf26ade86cb6501a0916c46b7e4787abdb0045a467eb1645a1d" +dependencies = [ + "ambient-authority", + "rand 0.8.5", +] + +[[package]] +name = "cap-std" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6dc3090992a735d23219de5c204927163d922f42f575a0189b005c62d37549a" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix 1.1.3", +] + +[[package]] +name = "cap-time-ext" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def102506ce40c11710a9b16e614af0cde8e76ae51b1f48c04b8d79f4b671a80" +dependencies = [ + "ambient-authority", + "cap-primitives", + "iana-time-zone", + "once_cell", + "rustix 1.1.3", + "winx", +] + [[package]] name = "caseless" version = "0.2.2" @@ -963,6 +1059,15 @@ dependencies = [ "cc", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "collection_literals" version = "1.0.3" @@ -1094,6 +1199,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpp_demangle" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1103,6 +1217,144 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-assembler-x64" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76779f01dcf5d1b0663f4268f9b3395a023026815f41fe152bae61b3c60f3f" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "032bb8ce6871b294308a93621aabb80e7315b5dbfba3a06ecaca41542a8abbfe" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "424289b574e612b6a048132492abff290f044052bbfe5460156f03f76c3271d1" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7aecdaa37cd169b4d92b0efb8ca81a40bebb5f588ea3310f5549652e4251e67" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c529540ae49bbdc84afc2f8d75ad8c9441f9d50a6e0ae1825d88ad5397085a4c" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.15.5", + "log", + "pulley-interpreter", + "regalloc2", + "rustc-hash 2.1.1", + "serde", + "smallvec", + "target-lexicon", + "wasmtime-internal-math", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef0e66d3093d57b4853aa1b751e706136e65012c76db7ddbf6e40c0c369fa516" +dependencies = [ + "cranelift-assembler-x64-meta", + "cranelift-codegen-shared", + "cranelift-srcgen", + "heck", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98fa7ddc3a113e5916b3af16e5b85037d4bf2dda39de27e42d2dc915e1141ad9" + +[[package]] +name = "cranelift-control" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9abf903ccdca830124ce24bdb3050fdfbb8730f70b46f6183226f569713afe" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25543bb984920680b614d4ff30756ec722a4257926356934609906de179e500" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8def0c7a84e1b4de15f4b5f514ae74c2e3acfbc9c7380c5cc74b17ee4f19bdc" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf9cace5d2c5faa6c273c19c6e116fab05be704f2f423d7a08f8ba5e15521728" + +[[package]] +name = "cranelift-native" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e5bda84f8b8580ce83679a1957c41464af102fc08065e34e55e31f990b61e7" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.123.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9ae0f07c362d514dbf9e91fe555700f00326026d0e65592ed4073e5427cd59e" + [[package]] name = "crc32fast" version = "1.5.0" @@ -1343,6 +1595,15 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + [[package]] name = "der" version = "0.7.10" @@ -1454,6 +1715,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -1565,6 +1836,18 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encode_unicode" version = "1.0.0" @@ -1775,6 +2058,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes", + "rustix 1.1.3", + "windows-sys 0.59.0", +] + [[package]] name = "fs2" version = "0.4.3" @@ -1923,6 +2217,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "fxprof-processed-profile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27d12c0aed7f1e24276a241aadc4cb8ea9f83000f34bc062b7cc2d51e3b0fabd" +dependencies = [ + "bitflags 2.10.0", + "debugid", + "fxhash", + "serde", + "serde_json", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2000,6 +2307,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +dependencies = [ + "fallible-iterator", + "indexmap 2.13.0", + "stable_deref_trait", +] + [[package]] name = "glob" version = "0.3.3" @@ -2117,6 +2435,7 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash 0.1.5", + "serde", ] [[package]] @@ -2482,6 +2801,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -2624,6 +2949,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "io-extras" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" +dependencies = [ + "io-lifetimes", + "windows-sys 0.59.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + [[package]] name = "ipc-channel" version = "0.19.0" @@ -2723,6 +3064,26 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "ittapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] + +[[package]] +name = "ittapi-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" +dependencies = [ + "cc", +] + [[package]] name = "jiff" version = "0.2.18" @@ -2853,6 +3214,18 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "lexical-parse-float" version = "1.0.6" @@ -3320,6 +3693,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + [[package]] name = "malachite-base" version = "0.9.0" @@ -3409,6 +3791,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + [[package]] name = "md-5" version = "0.10.6" @@ -3425,6 +3813,15 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memfd" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" +dependencies = [ + "rustix 1.1.3", +] + [[package]] name = "memmap2" version = "0.9.9" @@ -3796,6 +4193,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "crc32fast", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "memchr", +] + [[package]] name = "oid-registry" version = "0.8.1" @@ -4382,8 +4791,20 @@ dependencies = [ ] [[package]] -name = "potential_utf" -version = "0.1.4" +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ @@ -4462,7 +4883,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] @@ -4617,6 +5038,29 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulley-interpreter" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4c7fbfe494bf7b779aabe689e33d221f49121f1d6253c3ec4f62d2f9ff7019" +dependencies = [ + "cranelift-bitset", + "log", + "pulley-macros", + "wasmtime-internal-math", +] + +[[package]] +name = "pulley-macros" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40289747955f4ccf84a48ad1e5bc7753bf3e9378c3c8dabc6110cc38043a737" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "pure-rust-locales" version = "0.8.2" @@ -4903,6 +5347,20 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "regalloc2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.5", + "log", + "rustc-hash 2.1.1", + "smallvec", +] + [[package]] name = "regex" version = "1.12.2" @@ -5249,6 +5707,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -5305,6 +5769,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix 1.1.3", +] + [[package]] name = "rustls" version = "0.23.36" @@ -5909,6 +6383,10 @@ name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "serde" @@ -5975,6 +6453,15 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_spanned" version = "1.0.4" @@ -6210,6 +6697,9 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "smawk" @@ -6596,6 +7086,22 @@ dependencies = [ "libc", ] +[[package]] +name = "system-interface" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" +dependencies = [ + "bitflags 2.10.0", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes", + "rustix 0.38.44", + "windows-sys 0.59.0", + "winx", +] + [[package]] name = "syswebclient" version = "0.1.1" @@ -6614,6 +7120,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-lexicon" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" + [[package]] name = "tempfile" version = "3.24.0" @@ -6660,6 +7172,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.4.3" @@ -6919,6 +7440,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + [[package]] name = "toml" version = "0.9.11+spec-1.1.0" @@ -6927,13 +7460,22 @@ checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ "indexmap 2.13.0", "serde_core", - "serde_spanned", - "toml_datetime", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow", ] +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" @@ -6943,6 +7485,20 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.13.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" @@ -6950,7 +7506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap 2.13.0", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow", ] @@ -6964,6 +7520,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "toml_writer" version = "1.0.6+spec-1.1.0" @@ -7578,6 +8140,31 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi-common" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5efed76a0f40420549835c4e14bfc3e7a754985bbeca671b4e5adc2a648056" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "cap-fs-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "io-extras", + "io-lifetimes", + "log", + "rustix 1.1.3", + "system-interface", + "thiserror 2.0.18", + "tracing", + "wasmtime", + "wiggle", + "windows-sys 0.60.2", +] + [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" @@ -7646,6 +8233,437 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.236.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7" +dependencies = [ + "leb128fmt", + "wasmparser 0.236.1", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasm-runtime" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "colored", + "futures", + "libmodcore", + "libsysinspect", + "log", + "pin-utils", + "serde", + "serde_json", + "serde_yaml", + "thiserror 2.0.18", + "tokio", + "wasmruntime", +] + +[[package]] +name = "wasmparser" +version = "0.236.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", + "serde", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.10.0", + "indexmap 2.13.0", + "semver", +] + +[[package]] +name = "wasmprinter" +version = "0.236.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2df225df06a6df15b46e3f73ca066ff92c2e023670969f7d50ce7d5e695abbb1" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.236.1", +] + +[[package]] +name = "wasmruntime" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde_json", + "tokio", + "wasi-common", + "wasmtime", + "wasmtime-wasi", +] + +[[package]] +name = "wasmtime" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a269aaef6526f16091c0f3a5fe62631037cb3b9fb9cb1deb521c6ac7a5a6ee91" +dependencies = [ + "addr2line", + "anyhow", + "async-trait", + "bitflags 2.10.0", + "bumpalo", + "cc", + "cfg-if", + "encoding_rs", + "fxprof-processed-profile", + "gimli", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "ittapi", + "libc", + "log", + "mach2", + "memfd", + "object 0.37.3", + "once_cell", + "postcard", + "pulley-interpreter", + "rayon", + "rustix 1.1.3", + "semver", + "serde", + "serde_derive", + "serde_json", + "smallvec", + "target-lexicon", + "wasm-encoder 0.236.1", + "wasmparser 0.236.1", + "wasmtime-environ", + "wasmtime-internal-asm-macros", + "wasmtime-internal-cache", + "wasmtime-internal-component-macro", + "wasmtime-internal-component-util", + "wasmtime-internal-cranelift", + "wasmtime-internal-fiber", + "wasmtime-internal-jit-debug", + "wasmtime-internal-jit-icache-coherence", + "wasmtime-internal-math", + "wasmtime-internal-slab", + "wasmtime-internal-unwinder", + "wasmtime-internal-versioned-export-macros", + "wasmtime-internal-winch", + "wat", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-environ" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187f76529a8b2e36e87e48f1dcdc8c39340ff962359f653be7aa864bff9c9b7a" +dependencies = [ + "anyhow", + "cpp_demangle", + "cranelift-bitset", + "cranelift-entity", + "gimli", + "indexmap 2.13.0", + "log", + "object 0.37.3", + "postcard", + "rustc-demangle", + "semver", + "serde", + "serde_derive", + "smallvec", + "target-lexicon", + "wasm-encoder 0.236.1", + "wasmparser 0.236.1", + "wasmprinter", + "wasmtime-internal-component-util", +] + +[[package]] +name = "wasmtime-internal-asm-macros" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37edf8f7c7a23ab18d6bf5742e323c969571b8c35b990da48090b7b1ccacfca7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-internal-cache" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "009fffd3d90fe939de7b6f101633f465b6505d70b9a5f6d62746b7a52d2a9f99" +dependencies = [ + "anyhow", + "base64", + "directories-next", + "log", + "postcard", + "rustix 1.1.3", + "serde", + "serde_derive", + "sha2", + "toml 0.8.23", + "windows-sys 0.60.2", + "zstd", +] + +[[package]] +name = "wasmtime-internal-component-macro" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f752eede244eff36ed4ac5709d8bd94735f1f0db68e48e026d566589d1d914" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasmtime-internal-component-util", + "wasmtime-internal-wit-bindgen", + "wit-parser", +] + +[[package]] +name = "wasmtime-internal-component-util" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "077f5204aee8002178acc6ee4619b070bbfba0957cbcd0f968d92fb729be9229" + +[[package]] +name = "wasmtime-internal-cranelift" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa3a13862aa8d4c94a34260cfd0c309c1d2d04e2bd8e4d95b10e5a6481341d5" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "gimli", + "itertools 0.14.0", + "log", + "object 0.37.3", + "pulley-interpreter", + "smallvec", + "target-lexicon", + "thiserror 2.0.18", + "wasmparser 0.236.1", + "wasmtime-environ", + "wasmtime-internal-math", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-fiber" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ceb5817493b5b466f87a3da77ba0148d85ea29778d86546f070a31123f023e3" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "libc", + "rustix 1.1.3", + "wasmtime-internal-asm-macros", + "wasmtime-internal-versioned-export-macros", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-internal-jit-debug" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eac6f645873bc2a5961b4745cc5f07a0a7d53f970c806d8153fdf6941703e39" +dependencies = [ + "cc", + "object 0.37.3", + "rustix 1.1.3", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-jit-icache-coherence" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64ee722c4d42bc81559ddd0b1559645638bd84ba6439118e1a91eab88031b2e" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-internal-math" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de6fb4327b70b10c6b55352d19b279b2fb2bc74537ed7d5c20edc8ff0638dda7" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmtime-internal-slab" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afaa5d4c2db6fe47e07fef7f6d4030e8a5d6f6cb1c31bcfcbd9aff569a8b55a0" + +[[package]] +name = "wasmtime-internal-unwinder" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7282e8fbdc6d10f1e34feaac0c1694701f3c580880346e0cbbd4be49a1a901" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "log", + "object 0.37.3", +] + +[[package]] +name = "wasmtime-internal-versioned-export-macros" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4e078eb9916af6885193eca8ef6f0198aedf68db24ff8acc72bfaaef2c8b26" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "wasmtime-internal-winch" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f0c6532aeccecb2bb9f0f7abb34095ba54523080ff3f2c7a86347611096668" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object 0.37.3", + "target-lexicon", + "wasmparser 0.236.1", + "wasmtime-environ", + "wasmtime-internal-cranelift", + "winch-codegen", +] + +[[package]] +name = "wasmtime-internal-wit-bindgen" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6f1c3d410baf3b6f203efbc000444e60da4cbb9034c7d8706ed68aaa6ff936" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "heck", + "indexmap 2.13.0", + "wit-parser", +] + +[[package]] +name = "wasmtime-wasi" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760b9be6760a8121d9fbba587f5eaeff2e7188abdc4325d3ae78d9fb50974cb4" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.10.0", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "rustix 1.1.3", + "system-interface", + "thiserror 2.0.18", + "tokio", + "tracing", + "url", + "wasmtime", + "wasmtime-wasi-io", + "wiggle", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-wasi-io" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bb4c0fd892636a9fdc89f24ef8e678ba2f3c40e2dcf3e2317883b942de2c79" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "futures", + "wasmtime", +] + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + +[[package]] +name = "wast" +version = "244.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e7b9f9e23311275920e3d6b56d64137c160cf8af4f84a7283b36cfecbf4acb" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width 0.2.0", + "wasm-encoder 0.244.0", +] + +[[package]] +name = "wat" +version = "1.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf35b87ed352f9ab6cd0732abde5a67dd6153dfd02c493e61459218b19456fa" +dependencies = [ + "wast 244.0.0", +] + [[package]] name = "web-sys" version = "0.3.85" @@ -7701,6 +8719,47 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" +[[package]] +name = "wiggle" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55276f3072e422ecee4bc4141a004e76113d6fb5032fc75e3b7136fb60349bf9" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.10.0", + "thiserror 2.0.18", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a00f6046d9ed0cb65d84948335264610192fc27bc4141c684fc4c382dcca041" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8290efe5627229cd5fe5dfb90b4e201b214d353f55ca5ecaca82c273a45a7ad1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "wiggle-generate", +] + [[package]] name = "winapi" version = "0.3.9" @@ -7732,6 +8791,26 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "36.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf09d7c135f28b757699883820fd0aa41ef4a3916759aa12f32d850ced6a505" +dependencies = [ + "anyhow", + "cranelift-assembler-x64", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "thiserror 2.0.18", + "wasmparser 0.236.1", + "wasmtime-environ", + "wasmtime-internal-cranelift", + "wasmtime-internal-math", +] + [[package]] name = "windows" version = "0.57.0" @@ -8130,7 +9209,7 @@ version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cdfa8da4b111045a5e47c7c839e6c5e11c942de1309bc624393ed5d87f89c6" dependencies = [ - "toml", + "toml 0.9.11+spec-1.1.0", "version_check", ] @@ -8140,12 +9219,52 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags 2.10.0", + "windows-sys 0.59.0", +] + [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +[[package]] +name = "wit-parser" +version = "0.236.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e4833a20cd6e85d6abfea0e63a399472d6f88c6262957c17f546879a80ba15" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.236.1", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror 1.0.69", + "wast 35.0.2", +] + [[package]] name = "writeable" version = "0.6.2" diff --git a/Makefile b/Makefile index 5a047766..7a43b18a 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ define move_bin mv $$dir/ssrun $$dir/sys/; \ mv $$dir/file $$dir/fs/; \ mv $$dir/lua-runtime $$dir/runtime/; + mv $$dir/wasm-runtime $$dir/runtime/; endef setup: diff --git a/modules/runtime/wasm-runtime/Cargo.toml b/modules/runtime/wasm-runtime/Cargo.toml new file mode 100644 index 00000000..729c4397 --- /dev/null +++ b/modules/runtime/wasm-runtime/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "wasm-runtime" +version = "0.1.0" +edition = "2024" + +[dependencies] +libsysinspect = { path = "../../../libsysinspect" } +libmodcore = { path = "../../../libmodcore" } +wasmruntime = { path = "../../../../wasmruntime" } +# wasmruntime = {git = "https://github.com/isbm/wasmruntime.git"} +tokio = { version = "1.47.1", features = ["full"] } +serde = "1.0.228" +serde_json = "1.0.149" +serde_yaml = "0.9.34" +anyhow = "1.0.100" +thiserror = "2.0.18" +futures = "0.3.31" +pin-utils = "0.1.0" +clap = "4.5.54" +log = "0.4.29" +chrono = "0.4.43" +colored = "3.0.0" + +[profile.release] +strip = true +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs new file mode 100644 index 00000000..a2d91aab --- /dev/null +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -0,0 +1,64 @@ +use std::path::{Path, PathBuf}; + +use clap::Parser; +use libmodcore::{ + init_mod_doc, + manrndr::print_mod_manual, + modcli::ModuleCli, + modinit::ModInterface, + response::ModResponse, + runtime::{ModRequest, get_call_args, send_call_response}, +}; +use libsysinspect::SysinspectError; +use serde_json::{Value, json}; + +/// List available Wasm modules in the scripts directory +fn list_wasm_modules(_wasm_dir: &Path) -> Vec { + Vec::new() +} + +/// Get module documentation from Wasm runtime +fn module_doc_help(_cli: &ModuleCli, _modname: &str) -> Result { + Ok(json!({})) +} + +/// Run the Wasm runtime with the provided request. +fn call_runtime(_cli: &ModuleCli, _rq: &ModRequest) -> ModResponse { + ModResponse::default() +} + +fn main() { + let mod_doc = init_mod_doc!(ModInterface); + let cli = ModuleCli::parse(); + + // CLI calls from the terminal directly + if cli.is_manual() { + print!("{}", mod_doc.help()); + return; + } else if !cli.get_help_on().is_empty() { + match module_doc_help(&cli, &cli.get_help_on()) { + Ok(doc) => { + print_mod_manual(doc); + } + Err(err) => { + eprintln!("Failed to get module documentation: {}", err); + } + } + return; + } else if cli.is_list_modules() { + println!("Available Wasm runtime modules:"); + for module in list_wasm_modules(PathBuf::from(cli.get_sharelib()).as_path()) { + println!(" - {}", module); + } + return; + } + + // Runtime call (integrated via JSON protocol) + match get_call_args() { + Ok(rq) => match send_call_response(&call_runtime(&cli, &rq)) { + Ok(_) => {} + Err(err) => println!("Runtime error: {err}"), + }, + Err(err) => println!("Arguments error: {err}"), + } +} diff --git a/modules/runtime/wasm-runtime/src/mod_doc.yaml b/modules/runtime/wasm-runtime/src/mod_doc.yaml new file mode 100644 index 00000000..441b6987 --- /dev/null +++ b/modules/runtime/wasm-runtime/src/mod_doc.yaml @@ -0,0 +1,71 @@ +name: "runtime.lua" +version: "0.2.0" +author: "Bo Maryniuk" +description: Lua runtime module. + +# Options, flags, switches +options: + - name: rt.list + description: "List of available Lua scripts, ready to be called as modules." + + - name: rt.logs + description: "Enable logging from Lua scripts to SysInspect logs." + + - name: rt.native + description: "Enable native Lua libraries loading. Use with caution." + +# Keyword arguments +arguments: + - name: rt.mod + type: string + required: true + description: "The name of a Lua script to be executed. This script will be looked up in the predefined configured scripts directory." + + - name: "[ANY]" + type: string + required: false + description: | + Additional arguments that will be passed to the Lua script being executed. These arguments will be available within the Lua script + as global variables. + +examples: + - description: "Call a Lua script named 'hello_world.lua' so it will greet Germany" + code: | + { + "opts": [], + "arguments": { + "rt.mod": "hello_world", + "name": "Germany" + } + } + +# Description of additional data format +returns: + # Output data structure as a sample + # Happens by default + fill: + :description: | + Returns just a regular text of the command STDOUT. + retcode: 0 + message: "Called Lua script successfully." + data: + changed: false + +manpage: | + This module allows executing Lua scripts as modules within + the SysInspect framework. Lua scripts should be placed + in the configured scripts directory and can be called by + specifying their name. + + The module supports passing additional arguments to the Lua + script, which will be available as global variables within + the script. + + Important to keep the following directory structure for your + Lua scripts and their dependencies: + + 1. The [W::b]main Lua scripts[N] (modules) for this runtime must be installed + in [y::]${SYSINSPECT_SHARELIB_ROOT}[Y::]/lib/runtime/lua54/[N] directory, + + 2. The [W::b]dependency libraries[N] for these scripts should be placed in the + [y::]${SYSINSPECT_SHARELIB_ROOT}[Y::]/lib/runtime/lua54/site-lua/[N] directory. \ No newline at end of file From 071ad8006337c859dcdf4077dfed0e0c5a76c348 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 13:57:16 +0100 Subject: [PATCH 02/40] Update mod doc for the initial scaffold --- modules/runtime/wasm-runtime/src/mod_doc.yaml | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/modules/runtime/wasm-runtime/src/mod_doc.yaml b/modules/runtime/wasm-runtime/src/mod_doc.yaml index 441b6987..c7da6af1 100644 --- a/modules/runtime/wasm-runtime/src/mod_doc.yaml +++ b/modules/runtime/wasm-runtime/src/mod_doc.yaml @@ -1,35 +1,43 @@ -name: "runtime.lua" -version: "0.2.0" +name: "runtime.wasm" +version: "0.1.0" author: "Bo Maryniuk" -description: Lua runtime module. +description: Wasm runtime module. # Options, flags, switches options: - name: rt.list - description: "List of available Lua scripts, ready to be called as modules." + description: "List of available Wasm scripts, ready to be called as modules." - name: rt.logs - description: "Enable logging from Lua scripts to SysInspect logs." + description: "Enable logging from Wasm scripts to SysInspect logs." - - name: rt.native - description: "Enable native Lua libraries loading. Use with caution." + - name: rt.sandbox + description: "Run Wasm binaries in sandboxed environment." # Keyword arguments arguments: - name: rt.mod type: string required: true - description: "The name of a Lua script to be executed. This script will be looked up in the predefined configured scripts directory." + description: "The name of a Wasm binary to be executed. This binary will be looked up in the predefined configured scripts directory." + + - name: rt.rootfs + type: string + required: false + description: | + Path to the root filesystem directory that will be mounted + inside the Wasm runtime environment. This allows the Wasm binary + to access files and directories within the specified rootfs. - name: "[ANY]" type: string required: false description: | - Additional arguments that will be passed to the Lua script being executed. These arguments will be available within the Lua script + Additional arguments that will be passed to the Wasm binary being executed. These arguments will be available within the Wasm binary as global variables. examples: - - description: "Call a Lua script named 'hello_world.lua' so it will greet Germany" + - description: "Call a Wasm binary named 'hello_world.wasm' so it will greet Germany" code: | { "opts": [], @@ -47,25 +55,18 @@ returns: :description: | Returns just a regular text of the command STDOUT. retcode: 0 - message: "Called Lua script successfully." + message: "Called Wasm binary successfully." data: changed: false manpage: | - This module allows executing Lua scripts as modules within - the SysInspect framework. Lua scripts should be placed - in the configured scripts directory and can be called by - specifying their name. - - The module supports passing additional arguments to the Lua - script, which will be available as global variables within - the script. + This module allows executing Wasm binaries as modules within + the SysInspect framework. The module supports passing additional + arguments to the Wasm binary, which will be available as global + variables within the binary. Important to keep the following directory structure for your - Lua scripts and their dependencies: - - 1. The [W::b]main Lua scripts[N] (modules) for this runtime must be installed - in [y::]${SYSINSPECT_SHARELIB_ROOT}[Y::]/lib/runtime/lua54/[N] directory, + Wasm binaries and their dependencies. The [W::b]main Wasm binaries[N] + (modules) for this runtime must be installed in the following directory: + [y::]${SYSINSPECT_SHARELIB_ROOT}[Y::]/lib/runtime/wasm/[N] - 2. The [W::b]dependency libraries[N] for these scripts should be placed in the - [y::]${SYSINSPECT_SHARELIB_ROOT}[Y::]/lib/runtime/lua54/site-lua/[N] directory. \ No newline at end of file From 2e667f9edcf3c7ff2e5b9d5ff9cd4bb88f3e3926 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 14:01:01 +0100 Subject: [PATCH 03/40] Update rust-toolchain.toml to Rust 1.93.0 --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f19782d3..075062e5 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.92.0" +channel = "1.93.0" From a1be0c5ff778f2f583c0dee19656ee560f81be52 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 20:57:44 +0100 Subject: [PATCH 04/40] Update dependencies --- Cargo.lock | 198 ++++++++++++++---------- modules/runtime/wasm-runtime/Cargo.toml | 4 +- 2 files changed, 119 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5563071..97c76979 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,7 +167,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.6.1", + "socket2 0.6.2", "time", "tracing", "url", @@ -344,11 +344,11 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "ar_archive_writer" -version = "0.2.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c269894b6fe5e9d7ada0cf69b5bf847ff35bc25fc271f08e1d080fce80339a" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" dependencies = [ - "object 0.32.2", + "object", ] [[package]] @@ -497,9 +497,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.15.3" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e84ce723ab67259cfeb9877c6a639ee9eb7a27b28123abd71db7f0d5d0cc9d86" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" dependencies = [ "aws-lc-sys", "untrusted 0.7.1", @@ -508,9 +508,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a442ece363113bd4bd4c8b18977a7798dd4d3c3383f34fb61936960e8f4ad8" +checksum = "5c34dda4df7017c8db52132f0f8a2e0f8161649d15723ed63fc00c82d0f2081a" dependencies = [ "cc", "cmake", @@ -907,9 +907,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.53" +version = "1.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" dependencies = [ "find-msvc-tools", "jobserver", @@ -1765,7 +1765,7 @@ checksum = "6e39034cee21a2f5bbb66ba0e3689819c4bb5d00382a282006e802a7ffa6c41d" dependencies = [ "cfg-if", "libc", - "socket2 0.6.1", + "socket2 0.6.2", "windows-sys 0.60.2", ] @@ -2260,6 +2260,7 @@ dependencies = [ "compact_str 0.9.0", "get-size-derive2", "hashbrown 0.16.1", + "ordermap", "smallvec", ] @@ -2665,7 +2666,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2 0.6.2", "system-configuration 0.6.1", "tokio", "tower-service", @@ -2708,7 +2709,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.58.0", + "windows-core 0.62.2", ] [[package]] @@ -3328,9 +3329,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libmodcore" @@ -3655,9 +3656,9 @@ dependencies = [ [[package]] name = "luajit-src" -version = "210.6.4+e17ee83" +version = "210.6.6+707c12b" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a0ceb2a395ffa403a863adcf365e82cc8d8338ac7f5f949b9df5ca3de251e1" +checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" dependencies = [ "cc", "which", @@ -3930,9 +3931,9 @@ dependencies = [ [[package]] name = "mt19937" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7151a832e54d2d6b2c827a20e5bcdd80359281cd2c354e725d4b82e7c471de" +checksum = "56bc7ea7924ea1a79a9e817d0483e39295424cf2b1276cf2b968f9a6c9b63b54" dependencies = [ "rand_core 0.9.5", ] @@ -4101,9 +4102,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -4184,15 +4185,6 @@ dependencies = [ "bitflags 2.10.0", ] -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "object" version = "0.37.3" @@ -4260,9 +4252,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" @@ -4391,6 +4383,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordermap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa78c92071bbd3628c22b1a964f7e0eb201dc1456555db072beb1662ecd6715" +dependencies = [ + "indexmap 2.13.0", +] + [[package]] name = "page_size" version = "0.6.0" @@ -4899,9 +4900,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -5010,9 +5011,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11f2fedc3b7dafdc2851bc52f277377c5473d378859be234bc7ebb593144d01" +checksum = "1fa96cb91275ed31d6da3e983447320c4eb219ac180fa1679a0889ff32861e2d" dependencies = [ "ar_archive_writer", "cc", @@ -5083,9 +5084,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -5567,14 +5568,13 @@ dependencies = [ [[package]] name = "ruff_python_ast" version = "0.0.0" -source = "git+https://github.com/astral-sh/ruff.git?rev=45bbb4cbffe73cf925d4579c2e3eb413e0539390#45bbb4cbffe73cf925d4579c2e3eb413e0539390" +source = "git+https://github.com/astral-sh/ruff.git?rev=8b2e7b36f246b990fe473a84eef25ff429e59ecf#8b2e7b36f246b990fe473a84eef25ff429e59ecf" dependencies = [ "aho-corasick", "bitflags 2.10.0", "compact_str 0.9.0", "get-size2", "is-macro", - "itertools 0.14.0", "memchr", "ruff_python_trivia", "ruff_source_file", @@ -5586,7 +5586,7 @@ dependencies = [ [[package]] name = "ruff_python_parser" version = "0.0.0" -source = "git+https://github.com/astral-sh/ruff.git?rev=45bbb4cbffe73cf925d4579c2e3eb413e0539390#45bbb4cbffe73cf925d4579c2e3eb413e0539390" +source = "git+https://github.com/astral-sh/ruff.git?rev=8b2e7b36f246b990fe473a84eef25ff429e59ecf#8b2e7b36f246b990fe473a84eef25ff429e59ecf" dependencies = [ "bitflags 2.10.0", "bstr", @@ -5606,7 +5606,7 @@ dependencies = [ [[package]] name = "ruff_python_trivia" version = "0.0.0" -source = "git+https://github.com/astral-sh/ruff.git?rev=45bbb4cbffe73cf925d4579c2e3eb413e0539390#45bbb4cbffe73cf925d4579c2e3eb413e0539390" +source = "git+https://github.com/astral-sh/ruff.git?rev=8b2e7b36f246b990fe473a84eef25ff429e59ecf#8b2e7b36f246b990fe473a84eef25ff429e59ecf" dependencies = [ "itertools 0.14.0", "ruff_source_file", @@ -5617,7 +5617,7 @@ dependencies = [ [[package]] name = "ruff_source_file" version = "0.0.0" -source = "git+https://github.com/astral-sh/ruff.git?rev=45bbb4cbffe73cf925d4579c2e3eb413e0539390#45bbb4cbffe73cf925d4579c2e3eb413e0539390" +source = "git+https://github.com/astral-sh/ruff.git?rev=8b2e7b36f246b990fe473a84eef25ff429e59ecf#8b2e7b36f246b990fe473a84eef25ff429e59ecf" dependencies = [ "memchr", "ruff_text_size", @@ -5626,7 +5626,7 @@ dependencies = [ [[package]] name = "ruff_text_size" version = "0.0.0" -source = "git+https://github.com/astral-sh/ruff.git?rev=45bbb4cbffe73cf925d4579c2e3eb413e0539390#45bbb4cbffe73cf925d4579c2e3eb413e0539390" +source = "git+https://github.com/astral-sh/ruff.git?rev=8b2e7b36f246b990fe473a84eef25ff429e59ecf#8b2e7b36f246b990fe473a84eef25ff429e59ecf" dependencies = [ "get-size2", ] @@ -5800,7 +5800,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe 0.2.0", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", "security-framework 3.5.1", @@ -5866,7 +5866,7 @@ dependencies = [ [[package]] name = "rustpython" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "cfg-if", "dirs-next", @@ -5886,7 +5886,7 @@ dependencies = [ [[package]] name = "rustpython-codegen" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "ahash 0.8.12", "bitflags 2.10.0", @@ -5909,7 +5909,7 @@ dependencies = [ [[package]] name = "rustpython-common" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "ascii", "bitflags 2.10.0", @@ -5938,7 +5938,7 @@ dependencies = [ [[package]] name = "rustpython-compiler" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "ruff_python_ast", "ruff_python_parser", @@ -5952,7 +5952,7 @@ dependencies = [ [[package]] name = "rustpython-compiler-core" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "bitflags 2.10.0", "itertools 0.14.0", @@ -5966,7 +5966,7 @@ dependencies = [ [[package]] name = "rustpython-derive" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "rustpython-compiler", "rustpython-derive-impl", @@ -5976,7 +5976,7 @@ dependencies = [ [[package]] name = "rustpython-derive-impl" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "itertools 0.14.0", "maplit", @@ -5992,7 +5992,7 @@ dependencies = [ [[package]] name = "rustpython-doc" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "phf 0.13.1", ] @@ -6000,7 +6000,7 @@ dependencies = [ [[package]] name = "rustpython-literal" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "hexf-parse", "is-macro", @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "rustpython-pylib" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "glob", "rustpython-compiler-core", @@ -6023,7 +6023,7 @@ dependencies = [ [[package]] name = "rustpython-sre_engine" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "bitflags 2.10.0", "num_enum", @@ -6034,7 +6034,7 @@ dependencies = [ [[package]] name = "rustpython-stdlib" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "adler32", "ahash 0.8.12", @@ -6092,7 +6092,7 @@ dependencies = [ "sha-1", "sha2", "sha3", - "socket2 0.6.1", + "socket2 0.6.2", "system-configuration 0.7.0", "termios", "ucd", @@ -6118,7 +6118,7 @@ dependencies = [ [[package]] name = "rustpython-vm" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "ahash 0.8.12", "ascii", @@ -6191,7 +6191,7 @@ dependencies = [ [[package]] name = "rustpython-wtf8" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#d7a885cea82b39be21b0f847e83cb78e117ff6ca" +source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" dependencies = [ "ascii", "bstr", @@ -6719,9 +6719,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -7264,9 +7264,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -7281,15 +7281,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -7359,7 +7359,7 @@ dependencies = [ "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.2", "tokio-macros", "windows-sys 0.61.2", ] @@ -8086,9 +8086,9 @@ checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d" [[package]] name = "uuid" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" dependencies = [ "atomic", "getrandom 0.3.4", @@ -8312,6 +8312,7 @@ dependencies = [ [[package]] name = "wasmruntime" version = "0.1.0" +source = "git+https://github.com/isbm/wasmruntime.git#6c69fb4e9be45f909d7c9c5ae5652d88af463a53" dependencies = [ "anyhow", "serde_json", @@ -8344,7 +8345,7 @@ dependencies = [ "log", "mach2", "memfd", - "object 0.37.3", + "object", "once_cell", "postcard", "pulley-interpreter", @@ -8389,7 +8390,7 @@ dependencies = [ "gimli", "indexmap 2.13.0", "log", - "object 0.37.3", + "object", "postcard", "rustc-demangle", "semver", @@ -8469,7 +8470,7 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object 0.37.3", + "object", "pulley-interpreter", "smallvec", "target-lexicon", @@ -8503,7 +8504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eac6f645873bc2a5961b4745cc5f07a0a7d53f970c806d8153fdf6941703e39" dependencies = [ "cc", - "object 0.37.3", + "object", "rustix 1.1.3", "wasmtime-internal-versioned-export-macros", ] @@ -8545,7 +8546,7 @@ dependencies = [ "cfg-if", "cranelift-codegen", "log", - "object 0.37.3", + "object", ] [[package]] @@ -8568,7 +8569,7 @@ dependencies = [ "anyhow", "cranelift-codegen", "gimli", - "object 0.37.3", + "object", "target-lexicon", "wasmparser 0.236.1", "wasmtime-environ", @@ -8856,6 +8857,19 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -8878,6 +8892,17 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "windows-interface" version = "0.57.0" @@ -8900,6 +8925,17 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "windows-link" version = "0.2.1" @@ -9205,9 +9241,9 @@ dependencies = [ [[package]] name = "winresource" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cdfa8da4b111045a5e47c7c839e6c5e11c942de1309bc624393ed5d87f89c6" +checksum = "e287ced0f21cd11f4035fe946fd3af145f068d1acb708afd248100f89ec7432d" dependencies = [ "toml 0.9.11+spec-1.1.0", "version_check", @@ -9465,9 +9501,9 @@ checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" [[package]] name = "zmij" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" [[package]] name = "zopfli" diff --git a/modules/runtime/wasm-runtime/Cargo.toml b/modules/runtime/wasm-runtime/Cargo.toml index 729c4397..137263a8 100644 --- a/modules/runtime/wasm-runtime/Cargo.toml +++ b/modules/runtime/wasm-runtime/Cargo.toml @@ -6,8 +6,8 @@ edition = "2024" [dependencies] libsysinspect = { path = "../../../libsysinspect" } libmodcore = { path = "../../../libmodcore" } -wasmruntime = { path = "../../../../wasmruntime" } -# wasmruntime = {git = "https://github.com/isbm/wasmruntime.git"} +# wasmruntime = { path = "../../../../wasmruntime" } +wasmruntime = {git = "https://github.com/isbm/wasmruntime.git"} tokio = { version = "1.47.1", features = ["full"] } serde = "1.0.228" serde_json = "1.0.149" From 5ee7fd7116d462250620906477a758ec33160262 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 21:03:56 +0100 Subject: [PATCH 05/40] Fix python init. --- libsysinspect/src/pylang/pvm.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/libsysinspect/src/pylang/pvm.rs b/libsysinspect/src/pylang/pvm.rs index 37e8321c..34c54ea6 100644 --- a/libsysinspect/src/pylang/pvm.rs +++ b/libsysinspect/src/pylang/pvm.rs @@ -5,6 +5,7 @@ Python virtual machine use crate::{SysinspectError, pylang::PY_MAIN_FUNC}; use colored::Colorize; use indexmap::IndexMap; +use rustpython::InterpreterBuilderExt; use rustpython_vm::{ AsObject, PyResult, compiler::Mode::Exec, @@ -30,18 +31,14 @@ pub struct PyVm { impl PyVm { pub fn new(libpath: PathBuf, modpath: PathBuf) -> Self { let mut cfg = Settings::default(); - let libpath = libpath.to_str().unwrap_or_default(); - cfg.path_list.push(libpath.to_string()); - - let itp = rustpython::InterpreterConfig::new() - .init_stdlib() - .settings(cfg) - .init_hook(Box::new(|vm| { - vm.add_native_module("syscore".to_owned(), Box::new(syscore::make_module)); - })) - .interpreter(); - - Self { itp, libpath: libpath.to_string(), modpath: modpath.to_str().unwrap_or_default().to_string() } + + let libpath_str = libpath.to_str().unwrap_or_default().to_string(); + cfg.path_list.push(libpath_str.clone()); + let builder = rustpython::Interpreter::builder(cfg); + + let syscore_def = syscore::module_def(&builder.ctx); + let itp = builder.init_stdlib().add_native_module(syscore_def).build(); + Self { itp, libpath: libpath_str, modpath: modpath.to_str().unwrap_or_default().to_string() } } /// Load main script of a module by a regular namespace From 26b2d75073213258ccf20e16afdb20340fcd0b4d Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 21:08:40 +0100 Subject: [PATCH 06/40] Get rid of direct unwrap() --- modules/sys/ssrun/src/main.rs | 37 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/modules/sys/ssrun/src/main.rs b/modules/sys/ssrun/src/main.rs index ba9213e5..d4a5a3e7 100644 --- a/modules/sys/ssrun/src/main.rs +++ b/modules/sys/ssrun/src/main.rs @@ -53,26 +53,31 @@ fn call(mrg: ModArgs) -> ModResponse { return resp; } - if mrg.rsa_prk.is_none() { - if let Some(password) = mrg.password { - // Mad Idea ™, but the user still wants that... ¯\_(ツ)_/¯ - if let Err(err) = sess.userauth_password(&mrg.user, &password).context("SSH password authentication failed") { - resp.set_message(&format!("Authentication error: {err}")); + match mrg.rsa_prk.as_deref() { + None => { + if let Some(password) = mrg.password.as_deref() { + // Mad Idea ™, but the user still wants that... ¯\_(ツ)_/¯ + if let Err(err) = sess.userauth_password(&mrg.user, password).context("SSH password authentication failed") { + resp.set_message(&format!("Authentication error: {err}")); + return resp; + } + } else { + resp.set_message("RSA key or a password must be supplied"); return resp; } - } else { - resp.set_message("RSA key or a password must be supplied"); - return resp; } - } else if let Err(err) = sess.userauth_pubkey_file(&mrg.user, None, mrg.rsa_prk.unwrap().as_path(), mrg.password.as_deref()).with_context(|| { - if mrg.password.is_some() { - "SSH key authentication failed: Incorrect passphrase or key." - } else { - "SSH key authentication failed: Incorrect key or permissions." + Some(prk_path) => { + if let Err(err) = sess.userauth_pubkey_file(&mrg.user, None, prk_path, mrg.password.as_deref()).with_context(|| { + if mrg.password.is_some() { + "SSH key authentication failed: Incorrect passphrase or key." + } else { + "SSH key authentication failed: Incorrect key or permissions." + } + }) { + resp.set_message(&format!("Authentication error: {err}")); + return resp; + } } - }) { - resp.set_message(&format!("Authentication error: {err}")); - return resp; } if !sess.authenticated() { From 2f6dbee3ed80eeaa923e8b3c4ece8c81ae053a48 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Sun, 25 Jan 2026 21:29:03 +0100 Subject: [PATCH 07/40] Fix broken Makefile so the actions stop failing --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7a43b18a..bf528c1b 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ define move_bin mv $$dir/run $$dir/sys/; \ mv $$dir/ssrun $$dir/sys/; \ mv $$dir/file $$dir/fs/; \ - mv $$dir/lua-runtime $$dir/runtime/; + mv $$dir/lua-runtime $$dir/runtime/; \ mv $$dir/wasm-runtime $$dir/runtime/; endef From a1fc346364707a64be74b294c2b26e4488ca1e49 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 14:12:47 +0100 Subject: [PATCH 08/40] Allow ModRequest to be cloned --- libmodcore/src/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmodcore/src/runtime.rs b/libmodcore/src/runtime.rs index 8c581808..e5109dd0 100644 --- a/libmodcore/src/runtime.rs +++ b/libmodcore/src/runtime.rs @@ -40,7 +40,7 @@ impl ArgValue { } /// Struct to call plugin parameters -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct ModRequest { /// Timeout of the module running. /// If timeout is exceeded, module quits. From ae3fbb93de204ea653e97bf1632a13304f9a2c45 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 14:13:18 +0100 Subject: [PATCH 09/40] Update/upgrade dependencies --- Cargo.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97c76979..80536ec0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2242,9 +2242,9 @@ dependencies = [ [[package]] name = "get-size-derive2" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab21d7bd2c625f2064f04ce54bcb88bc57c45724cde45cba326d784e22d3f71a" +checksum = "f2b6d1e2f75c16bfbcd0f95d84f99858a6e2f885c2287d1f5c3a96e8444a34b4" dependencies = [ "attribute-derive", "quote", @@ -2253,9 +2253,9 @@ dependencies = [ [[package]] name = "get-size2" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879272b0de109e2b67b39fcfe3d25fdbba96ac07e44a254f5a0b4d7ff55340cb" +checksum = "49cf31a6d70300cf81461098f7797571362387ef4bf85d32ac47eaa59b3a5a1a" dependencies = [ "compact_str 0.9.0", "get-size-derive2", @@ -5866,7 +5866,7 @@ dependencies = [ [[package]] name = "rustpython" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "cfg-if", "dirs-next", @@ -5886,7 +5886,7 @@ dependencies = [ [[package]] name = "rustpython-codegen" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "ahash 0.8.12", "bitflags 2.10.0", @@ -5909,7 +5909,7 @@ dependencies = [ [[package]] name = "rustpython-common" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "ascii", "bitflags 2.10.0", @@ -5938,7 +5938,7 @@ dependencies = [ [[package]] name = "rustpython-compiler" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "ruff_python_ast", "ruff_python_parser", @@ -5952,7 +5952,7 @@ dependencies = [ [[package]] name = "rustpython-compiler-core" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "bitflags 2.10.0", "itertools 0.14.0", @@ -5966,7 +5966,7 @@ dependencies = [ [[package]] name = "rustpython-derive" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "rustpython-compiler", "rustpython-derive-impl", @@ -5976,7 +5976,7 @@ dependencies = [ [[package]] name = "rustpython-derive-impl" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "itertools 0.14.0", "maplit", @@ -5992,7 +5992,7 @@ dependencies = [ [[package]] name = "rustpython-doc" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "phf 0.13.1", ] @@ -6000,7 +6000,7 @@ dependencies = [ [[package]] name = "rustpython-literal" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "hexf-parse", "is-macro", @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "rustpython-pylib" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "glob", "rustpython-compiler-core", @@ -6023,7 +6023,7 @@ dependencies = [ [[package]] name = "rustpython-sre_engine" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "bitflags 2.10.0", "num_enum", @@ -6034,7 +6034,7 @@ dependencies = [ [[package]] name = "rustpython-stdlib" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "adler32", "ahash 0.8.12", @@ -6118,7 +6118,7 @@ dependencies = [ [[package]] name = "rustpython-vm" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "ahash 0.8.12", "ascii", @@ -6191,7 +6191,7 @@ dependencies = [ [[package]] name = "rustpython-wtf8" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#7eceb145b1d7d445fada3333737e3b08d576d863" +source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" dependencies = [ "ascii", "bstr", @@ -9387,18 +9387,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d" dependencies = [ "proc-macro2", "quote", @@ -9501,9 +9501,9 @@ checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" [[package]] name = "zmij" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" [[package]] name = "zopfli" From 9e50ece78df2666db034b80f41aa56eb23aabe30 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 14:13:57 +0100 Subject: [PATCH 10/40] Implement a basic WASM runtime module --- modules/runtime/wasm-runtime/src/main.rs | 18 +++- modules/runtime/wasm-runtime/src/wart.rs | 128 +++++++++++++++++++++++ 2 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 modules/runtime/wasm-runtime/src/wart.rs diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs index a2d91aab..0c421ea1 100644 --- a/modules/runtime/wasm-runtime/src/main.rs +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +mod wart; use clap::Parser; use libmodcore::{ @@ -11,6 +11,7 @@ use libmodcore::{ }; use libsysinspect::SysinspectError; use serde_json::{Value, json}; +use std::path::{Path, PathBuf}; /// List available Wasm modules in the scripts directory fn list_wasm_modules(_wasm_dir: &Path) -> Vec { @@ -23,8 +24,19 @@ fn module_doc_help(_cli: &ModuleCli, _modname: &str) -> Result ModResponse { - ModResponse::default() +fn call_runtime(cli: &ModuleCli, rq: &ModRequest) -> ModResponse { + let mut r = ModResponse::new_cm(); + let rt = match wart::WasmRuntime::new(rq) { + Err(err) => { + r.set_message(&format!("Failed to initialize Wasm runtime: {err}")); + r.set_retcode(4); + return r; + } + Ok(rt) => rt, + }; + let out = rt.run(); + + out } fn main() { diff --git a/modules/runtime/wasm-runtime/src/wart.rs b/modules/runtime/wasm-runtime/src/wart.rs new file mode 100644 index 00000000..dc33eace --- /dev/null +++ b/modules/runtime/wasm-runtime/src/wart.rs @@ -0,0 +1,128 @@ +use futures::executor; +use libmodcore::{response::ModResponse, runtime::ModRequest}; +use libsysinspect::SysinspectError; +use std::collections::HashMap; +use wasmruntime::cfg::WasmConfig; + +/// Config entry for path to shared library +const PATH_SHARELIB: &str = "path.sharelib"; // Root +const PATH_USERLETS: &str = "lib/runtime/wasm"; + +pub struct WasmRuntime { + rq: ModRequest, + rt: wasmruntime::WasmRuntime, +} + +impl WasmRuntime { + pub fn new(rq: &ModRequest) -> Result { + let wcfg = Self::get_wcfg(rq)?; + let rt = match wasmruntime::WasmRuntime::new(wcfg.clone()) { + Err(err) => { + return Err(SysinspectError::ConfigError(format!("Failed to initialize Wasm runtime: {err}"))); + } + Ok(rt) => rt, + }; + + Ok(WasmRuntime { rq: rq.clone(), rt }) + } + + /// Get sharelib path + fn get_sharelib(rq: &ModRequest) -> String { + let sharelib = rq.config().get(PATH_SHARELIB).and_then(|v| v.as_string()).unwrap_or_default().trim_end_matches('/').to_string(); + if !sharelib.is_empty() { format!("{sharelib}/{PATH_USERLETS}") } else { String::new() } + } + + /// Get Wasm config + fn get_wcfg(rq: &ModRequest) -> Result { + let mut wcfg = WasmConfig::default(); + + // Go modules require guest path to be explicitly "/" + // TinyGo is permissive and "." is enough, but native Go is not. + wcfg.set_guest_path("/"); + match wcfg.set_host_path("/") { + Err(err) => { + return Err(SysinspectError::ConfigError(format!("Failed to set default host path: {err}"))); + } + Ok(_) => {} + } + + let sharelib = Self::get_sharelib(rq); + if sharelib.is_empty() { + return Err(SysinspectError::ConfigError(format!("Config entry \"{PATH_SHARELIB}\" is missing or empty"))); + } + wcfg.set_rootdir(sharelib); + + rq.args().get("write-dir").and_then(|v| v.as_string()).map(|p| p.trim_end_matches('/').to_string()).filter(|p| !p.is_empty()).map_or( + Ok(()), + |p| { + if !p.starts_with('/') { + return Err(SysinspectError::ConfigError("Argument \"write-dir\" must be an absolute path".to_string())); + } + + if let Err(err) = wcfg.set_host_path(p) { + return Err(SysinspectError::ConfigError(format!("Failed to set host path: {err}"))); + } + + Ok(()) + }, + )?; + + wcfg.set_allow_write(true); + Ok(wcfg) + } + + fn get_wasm_modules(&self) -> Result, SysinspectError> { + let mods: Vec = match self.rt.objects() { + Err(err) => { + return Err(SysinspectError::ConfigError(format!("Failed to list userlets: {err}"))); + } + Ok(uls) => uls, + }; + Ok(mods) + } + + pub fn run(&self) -> ModResponse { + let mut r = ModResponse::new_cm(); + + // Get Wasm modules + let wmod = match self.get_wasm_modules() { + Err(err) => { + r.set_message(&format!("Failed to get WASM modules: {err}")); + r.set_retcode(3); + return r; + } + Ok(uls) => uls, + }; + + // Calling + let mod_id = self.rq.args_all().get("rt.mod").and_then(|v| v.as_string()).unwrap_or_default(); + if !wmod.contains(&mod_id.to_string()) { + r.set_message(&format!("Module \"{mod_id}\" was not found")); + r.set_retcode(4); + return r; + } + + // `run` is async and returns a Future; we must drive it to completion. + let out = match executor::block_on(self.rt.run(&mod_id, vec![], HashMap::new(), vec![])) { + Err(err) => { + r.set_message(&format!("Failed to run module \"{mod_id}\": {err}")); + r.set_retcode(5); + return r; + } + Ok(val) => val, + }; + + r.set_message("Wasm runtime executed successfully"); + r.set_retcode(0); + match r.set_data(out) { + Err(err) => { + r.set_message(&format!("Failed to set response data: {err}")); + r.set_retcode(6); + return r; + } + Ok(_) => {} + } + + r + } +} From c0b2ffc10d1a416ab54b00c44840e7890e929aca Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 15:20:29 +0100 Subject: [PATCH 11/40] Add an example of WASM module --- .../wasm-runtime/examples/hello/Makefile | 78 +++++++++ .../wasm-runtime/examples/hello/go.mod | 3 + .../wasm-runtime/examples/hello/main.go | 149 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 modules/runtime/wasm-runtime/examples/hello/Makefile create mode 100644 modules/runtime/wasm-runtime/examples/hello/go.mod create mode 100644 modules/runtime/wasm-runtime/examples/hello/main.go diff --git a/modules/runtime/wasm-runtime/examples/hello/Makefile b/modules/runtime/wasm-runtime/examples/hello/Makefile new file mode 100644 index 00000000..d4e5ca93 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/hello/Makefile @@ -0,0 +1,78 @@ +MODULE := hellodude +SRC := main.go +OUTDIR := build + +# You MUST set this: WASM_COMPILER=go or WASM_COMPILER=tinygo +WASM_COMPILER ?= + +GO ?= go +TINYGO ?= tinygo +WASM_OPT ?= wasm-opt # optional (Binaryen). If missing, we skip it. + +DEBUG_WASM := $(OUTDIR)/$(MODULE)_debug.wasm +RELEASE_WASM := $(OUTDIR)/$(MODULE).wasm + +.PHONY: help debug release clean check + +help: + @echo "Usage:" + @echo " WASM_COMPILER=go make debug|release" + @echo " WASM_COMPILER=tinygo make debug|release" + @echo + @echo "Targets:" + @echo " debug - build debuggable WASI wasm" + @echo " release - build smallest WASI wasm we can reasonably squeeze" + @echo " check - show tool availability" + @echo " clean - remove build artifacts" + +check: + @echo "WASM_COMPILER=$(WASM_COMPILER)" + @echo "go: $$(command -v $(GO) >/dev/null 2>&1 && $(GO) version || echo MISSING)" + @echo "tinygo: $$(command -v $(TINYGO) >/dev/null 2>&1 && $(TINYGO) version || echo MISSING)" + @echo "wasm-opt (optional): $$(command -v $(WASM_OPT) >/dev/null 2>&1 && $(WASM_OPT) --version || echo MISSING)" + +# --- guardrails (cry if unset / invalid) --- +define REQUIRE_COMPILER + @if [ -z "$(WASM_COMPILER)" ]; then \ + echo "ERROR: WASM_COMPILER is not set. Use WASM_COMPILER=go or WASM_COMPILER=tinygo"; \ + exit 2; \ + fi + @if [ "$(WASM_COMPILER)" != "go" ] && [ "$(WASM_COMPILER)" != "tinygo" ]; then \ + echo "ERROR: WASM_COMPILER must be 'go' or 'tinygo' (got: $(WASM_COMPILER))"; \ + exit 2; \ + fi +endef + +debug: + @mkdir -p $(OUTDIR) + @$(REQUIRE_COMPILER) + @if [ "$(WASM_COMPILER)" = "tinygo" ]; then \ + command -v $(TINYGO) >/dev/null 2>&1 || (echo "ERROR: tinygo missing"; exit 2); \ + $(TINYGO) build -target=wasi -o $(DEBUG_WASM) -debug -opt=1 $(SRC); \ + else \ + command -v $(GO) >/dev/null 2>&1 || (echo "ERROR: go missing"; exit 2); \ + GOOS=wasip1 GOARCH=wasm $(GO) build -o $(DEBUG_WASM) $(SRC); \ + fi + @echo "Built debug: $(DEBUG_WASM)" + +release: + @mkdir -p $(OUTDIR) + @$(REQUIRE_COMPILER) + @if [ "$(WASM_COMPILER)" = "tinygo" ]; then \ + command -v $(TINYGO) >/dev/null 2>&1 || (echo "ERROR: tinygo missing"; exit 2); \ + $(TINYGO) build -target=wasi -o $(RELEASE_WASM) -no-debug -opt=z -panic=trap $(SRC); \ + else \ + command -v $(GO) >/dev/null 2>&1 || (echo "ERROR: go missing"; exit 2); \ + GOOS=wasip1 GOARCH=wasm $(GO) build -o $(RELEASE_WASM) -trimpath -ldflags="-s -w" $(SRC); \ + fi + @# Optional: squeeze harder with wasm-opt if available + @if command -v $(WASM_OPT) >/dev/null 2>&1; then \ + echo "Running wasm-opt for extra shrink..."; \ + $(WASM_OPT) -Oz --strip-debug --strip-producers $(RELEASE_WASM) -o $(RELEASE_WASM); \ + else \ + echo "wasm-opt not found; skipping extra squeezing."; \ + fi + @echo "Built release: $(RELEASE_WASM)" + +clean: + rm -rf $(OUTDIR) diff --git a/modules/runtime/wasm-runtime/examples/hello/go.mod b/modules/runtime/wasm-runtime/examples/hello/go.mod new file mode 100644 index 00000000..ffde94a2 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/hello/go.mod @@ -0,0 +1,3 @@ +module hallochen + +go 1.23.0 diff --git a/modules/runtime/wasm-runtime/examples/hello/main.go b/modules/runtime/wasm-runtime/examples/hello/main.go new file mode 100644 index 00000000..75683f12 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/hello/main.go @@ -0,0 +1,149 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + "strings" +) + +type Header struct { + Opts []string `json:"opts"` + Args map[string]interface{} `json:"args"` +} + +func scalar2bool(v interface{}) bool { + switch t := v.(type) { + case bool: + return t + case string: + s := strings.ToLower(strings.TrimSpace(t)) + return s != "" && s != "0" && s != "false" && s != "no" + case float64: + return t != 0 + default: + return false + } +} + +func readHeader() (Header, error) { + in := bufio.NewScanner(os.Stdin) + in.Buffer(make([]byte, 0, 64*1024), 10*1024*1024) + + var hdr Header + if !in.Scan() { + if err := in.Err(); err != nil { + return hdr, fmt.Errorf("stdin scan: %w", err) + } + return hdr, fmt.Errorf("missing header JSON on stdin") + } + if err := json.Unmarshal(in.Bytes(), &hdr); err != nil { + return hdr, fmt.Errorf("failed to parse header JSON: %w", err) + } + return hdr, nil +} + +// Small parser for /etc/os-release file +func readOSRelease() (map[string]string, error) { + b, err := os.ReadFile("/etc/os-release") + if err != nil { + return nil, err + } + out := map[string]string{} + for _, line := range strings.Split(string(b), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + k, v, ok := strings.Cut(line, "=") + if !ok { + continue + } + k = strings.TrimSpace(k) + v = strings.TrimSpace(v) + v = strings.Trim(v, `"'`) + out[k] = v + } + return out, nil +} + +// Module documentation +func doc() map[string]any { + // SAME SHAPE as your Lua docs: arguments/options/examples arrays, returns object. + return map[string]any{ + "name": "hellodude", + "version": "0.1.0", + "author": "Gru", + "description": "Says hello and returns OS version from /etc/os-release.", + + "arguments": []any{ + // none required; keep it empty array, not null, not map. + }, + + "options": []any{ + // none + }, + + "examples": []any{ + map[string]any{ + "description": "Get module output", + "code": `{ "args": { "mod": "hellodude" } }`, + }, + map[string]any{ + "description": "Get module documentation", + "code": `{ "args": { "mod": "hellodude", "rt.man": true } }`, + }, + }, + + "returns": map[string]any{ + "description": "Returns a greeting and OS release info (if accessible).", + "sample": map[string]any{ + "output": "hello, dude", + "os": map[string]any{ + "NAME": "Debian GNU/Linux", + "VERSION_ID": "12", + "PRETTY_NAME": "Debian GNU/Linux 12 (bookworm)", + }, + }, + }, + } +} + +// Run the module logic +func run(hdr Header) map[string]any { + _ = hdr // args/opts currently unused, but kept for future “CfgMgmt shit”. + + osr, err := readOSRelease() + if err != nil { + return map[string]any{ + "error": "failed to read /etc/os-release", + "detail": err.Error(), + } + } + + // Return the module data + return map[string]any{ + "output": "Hello, world!", + "VERSION": osr["VERSION"], + } +} + +// WASI entry function +func main() { + hdr, err := readHeader() + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + // doc-mode: args["rt.man"] == true + if hdr.Args != nil && scalar2bool(hdr.Args["rt.man"]) { + b, _ := json.Marshal(doc()) + fmt.Println(string(b)) + return + } + + b, _ := json.Marshal(run(hdr)) + fmt.Println(string(b)) +} From 7067101cab3a18f75c47e89dafe505bb15a42589 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 15:20:43 +0100 Subject: [PATCH 12/40] Update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d5a37b9f..57c69857 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ package/ /*/.bin/ /*/html-docs .gitignore +**/build/ From b184a636ee20a84f830fd5365420ba17d3e65902 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 15:21:09 +0100 Subject: [PATCH 13/40] Add example runner --- modules/runtime/wasm-runtime/examples/hello/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/runtime/wasm-runtime/examples/hello/Makefile b/modules/runtime/wasm-runtime/examples/hello/Makefile index d4e5ca93..49fa255f 100644 --- a/modules/runtime/wasm-runtime/examples/hello/Makefile +++ b/modules/runtime/wasm-runtime/examples/hello/Makefile @@ -1,6 +1,6 @@ MODULE := hellodude SRC := main.go -OUTDIR := build +OUTDIR := build/lib/runtime/wasm # You MUST set this: WASM_COMPILER=go or WASM_COMPILER=tinygo WASM_COMPILER ?= @@ -74,5 +74,11 @@ release: fi @echo "Built release: $(RELEASE_WASM)" +run: + @echo "Running module (test preview)..." + @echo '{"config": {"path.sharelib": "${PWD}/build"}, "args": {"rt.mod": "hellodude"}}' | ../../../../../target/debug/runtime/wasm-runtime | jq + + clean: rm -rf $(OUTDIR) + rm -rf build From 9f68ae70bf131857d6707aaa1737a72bb8958562 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 17:20:21 +0100 Subject: [PATCH 14/40] Lintfixes --- libmodcore/src/manrndr.rs | 4 ++-- modules/runtime/lua-runtime/src/main.rs | 2 +- modules/runtime/wasm-runtime/src/main.rs | 19 +++++++++-------- modules/runtime/wasm-runtime/src/wart.rs | 26 +++++++++++------------- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/libmodcore/src/manrndr.rs b/libmodcore/src/manrndr.rs index b6f2f48b..f1ec0f89 100644 --- a/libmodcore/src/manrndr.rs +++ b/libmodcore/src/manrndr.rs @@ -95,8 +95,8 @@ where } } -pub fn print_mod_manual(doc_val: Value) { - let doc: ModuleDoc = match serde_json::from_value(doc_val) { +pub fn print_mod_manual(doc_val: &Value) { + let doc: ModuleDoc = match serde_json::from_value(doc_val.clone()) { Ok(d) => d, Err(err) => { eprintln!("Failed to parse module doc: {err}"); diff --git a/modules/runtime/lua-runtime/src/main.rs b/modules/runtime/lua-runtime/src/main.rs index a988d644..d6e04f5e 100644 --- a/modules/runtime/lua-runtime/src/main.rs +++ b/modules/runtime/lua-runtime/src/main.rs @@ -135,7 +135,7 @@ fn main() { } else if !cli.get_help_on().is_empty() { match module_doc_help(&cli, &cli.get_help_on()) { Ok(doc) => { - print_mod_manual(doc); + print_mod_manual(&doc); } Err(err) => { eprintln!("Failed to get module documentation: {}", err); diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs index 0c421ea1..3fe1b87b 100644 --- a/modules/runtime/wasm-runtime/src/main.rs +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -24,7 +24,7 @@ fn module_doc_help(_cli: &ModuleCli, _modname: &str) -> Result ModResponse { +fn call_runtime(_cli: &ModuleCli, rq: &ModRequest) -> ModResponse { let mut r = ModResponse::new_cm(); let rt = match wart::WasmRuntime::new(rq) { Err(err) => { @@ -34,9 +34,9 @@ fn call_runtime(cli: &ModuleCli, rq: &ModRequest) -> ModResponse { } Ok(rt) => rt, }; - let out = rt.run(); + - out + rt.run() } fn main() { @@ -48,13 +48,14 @@ fn main() { print!("{}", mod_doc.help()); return; } else if !cli.get_help_on().is_empty() { - match module_doc_help(&cli, &cli.get_help_on()) { - Ok(doc) => { - print_mod_manual(doc); - } - Err(err) => { - eprintln!("Failed to get module documentation: {}", err); + match get_call_args() { + Ok(mut rq) => { + rq.add_opt("man"); + rq.add_arg("man", Value::Bool(true)); + let mr = &call_runtime(&cli, &rq); + print_mod_manual(mr.get_data()); } + Err(err) => println!("Arguments error: {err}"), } return; } else if cli.is_list_modules() { diff --git a/modules/runtime/wasm-runtime/src/wart.rs b/modules/runtime/wasm-runtime/src/wart.rs index dc33eace..404c436c 100644 --- a/modules/runtime/wasm-runtime/src/wart.rs +++ b/modules/runtime/wasm-runtime/src/wart.rs @@ -1,7 +1,6 @@ use futures::executor; use libmodcore::{response::ModResponse, runtime::ModRequest}; use libsysinspect::SysinspectError; -use std::collections::HashMap; use wasmruntime::cfg::WasmConfig; /// Config entry for path to shared library @@ -39,11 +38,8 @@ impl WasmRuntime { // Go modules require guest path to be explicitly "/" // TinyGo is permissive and "." is enough, but native Go is not. wcfg.set_guest_path("/"); - match wcfg.set_host_path("/") { - Err(err) => { - return Err(SysinspectError::ConfigError(format!("Failed to set default host path: {err}"))); - } - Ok(_) => {} + if let Err(err) = wcfg.set_host_path("/") { + return Err(SysinspectError::ConfigError(format!("Failed to set default host path: {err}"))); } let sharelib = Self::get_sharelib(rq); @@ -103,7 +99,12 @@ impl WasmRuntime { } // `run` is async and returns a Future; we must drive it to completion. - let out = match executor::block_on(self.rt.run(&mod_id, vec![], HashMap::new(), vec![])) { + let out = match executor::block_on(self.rt.run( + &mod_id, + self.rq.options().iter().map(|v| v.as_string().unwrap_or_default()).filter(|s| !s.is_empty()).collect(), + self.rq.args().into_iter().map(|(k, v)| (k, v.into())).collect(), + vec![], // This is incoming NDJSON (usually for databases). Unused in this scenario. + )) { Err(err) => { r.set_message(&format!("Failed to run module \"{mod_id}\": {err}")); r.set_retcode(5); @@ -114,13 +115,10 @@ impl WasmRuntime { r.set_message("Wasm runtime executed successfully"); r.set_retcode(0); - match r.set_data(out) { - Err(err) => { - r.set_message(&format!("Failed to set response data: {err}")); - r.set_retcode(6); - return r; - } - Ok(_) => {} + if let Err(err) = r.set_data(out) { + r.set_message(&format!("Failed to set response data: {err}")); + r.set_retcode(6); + return r; } r From 15e767cc50becaef8fd4eb4c36d70d6e1b5f33cd Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 17:20:55 +0100 Subject: [PATCH 15/40] Add request in-place modification --- libmodcore/src/response.rs | 7 ++++++- libmodcore/src/runtime.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/libmodcore/src/response.rs b/libmodcore/src/response.rs index 5648c41e..b59fd75a 100644 --- a/libmodcore/src/response.rs +++ b/libmodcore/src/response.rs @@ -1,6 +1,6 @@ use indexmap::IndexMap; use serde::{Deserialize, Serialize}; -use serde_json::{json, to_value, Value}; +use serde_json::{Value, json, to_value}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ModResponse { @@ -32,6 +32,11 @@ impl ModResponse { ModResponse::default() } + /// Get data + pub fn get_data(&self) -> &Value { + &self.data + } + /// New response with default negative/unsuccessful data for CM. /// These params needs to be reset. pub fn new_cm() -> Self { diff --git a/libmodcore/src/runtime.rs b/libmodcore/src/runtime.rs index e5109dd0..72b56a0d 100644 --- a/libmodcore/src/runtime.rs +++ b/libmodcore/src/runtime.rs @@ -5,6 +5,7 @@ use indexmap::IndexMap; use libsysinspect::cfg::mmconf::DEFAULT_MODULES_SHARELIB; use libsysinspect::util; use serde::{Deserialize, Serialize}; +use serde_json::Value; use std::io::Error; use std::io::{self, Read}; @@ -39,6 +40,12 @@ impl ArgValue { } } +impl From for serde_json::Value { + fn from(val: ArgValue) -> Self { + val.0 + } +} + /// Struct to call plugin parameters #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ModRequest { @@ -152,6 +159,27 @@ impl ModRequest { pub fn ext(&self) -> &IndexMap { &self.ext } + + /// Add an option + /// + /// This method typically used to alter a ModRequest by runtimes and + /// not supposed to be used within modules realm. + pub fn add_opt(&mut self, arg: &str) { + let arg = ArgValue(serde_json::Value::String(arg.to_string())); + let mut opts = self.options.clone().unwrap_or_default(); + opts.push(arg); + self.options = Some(opts); + } + + /// Add an argument + /// + /// This method typically used to alter a ModRequest by runtimes and + /// not supposed to be used within modules realm. + pub fn add_arg(&mut self, key: &str, val: Value) { + let mut args = self.arguments.clone().unwrap_or_default(); + args.insert(key.to_string(), ArgValue(val)); + self.arguments = Some(args); + } } /// Read JSON from STDIN From 7b5eaf47f041f68b477b2bb5330ec46d656b8e73 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 17:21:15 +0100 Subject: [PATCH 16/40] Fix WASM stripping for a regular Go --- modules/runtime/wasm-runtime/examples/hello/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/runtime/wasm-runtime/examples/hello/Makefile b/modules/runtime/wasm-runtime/examples/hello/Makefile index 49fa255f..5cc6c89f 100644 --- a/modules/runtime/wasm-runtime/examples/hello/Makefile +++ b/modules/runtime/wasm-runtime/examples/hello/Makefile @@ -68,7 +68,7 @@ release: @# Optional: squeeze harder with wasm-opt if available @if command -v $(WASM_OPT) >/dev/null 2>&1; then \ echo "Running wasm-opt for extra shrink..."; \ - $(WASM_OPT) -Oz --strip-debug --strip-producers $(RELEASE_WASM) -o $(RELEASE_WASM); \ + $(WASM_OPT) --all-features -Oz --strip-debug --strip-producers $(RELEASE_WASM) -o $(RELEASE_WASM); \ else \ echo "wasm-opt not found; skipping extra squeezing."; \ fi From 2ac9c4929969e07c0c779fff29722a7b1c94cfe5 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 17:21:32 +0100 Subject: [PATCH 17/40] Fix JSON output --- .../wasm-runtime/examples/hello/main.go | 73 ++++++++++++------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/modules/runtime/wasm-runtime/examples/hello/main.go b/modules/runtime/wasm-runtime/examples/hello/main.go index 75683f12..281cda2b 100644 --- a/modules/runtime/wasm-runtime/examples/hello/main.go +++ b/modules/runtime/wasm-runtime/examples/hello/main.go @@ -27,6 +27,15 @@ func scalar2bool(v interface{}) bool { } } +func hasOpt(opts []string, want string) bool { + for _, o := range opts { + if o == want { + return true + } + } + return false +} + func readHeader() (Header, error) { in := bufio.NewScanner(os.Stdin) in.Buffer(make([]byte, 0, 64*1024), 10*1024*1024) @@ -44,7 +53,6 @@ func readHeader() (Header, error) { return hdr, nil } -// Small parser for /etc/os-release file func readOSRelease() (map[string]string, error) { b, err := os.ReadFile("/etc/os-release") if err != nil { @@ -68,9 +76,13 @@ func readOSRelease() (map[string]string, error) { return out, nil } -// Module documentation +// Documentation of the module +// +// This is an example how to document your module so that sysinspect can +// generate manual pages and help texts automatically. +// +// Important is to keep the structure and the field names as they are here. func doc() map[string]any { - // SAME SHAPE as your Lua docs: arguments/options/examples arrays, returns object. return map[string]any{ "name": "hellodude", "version": "0.1.0", @@ -78,58 +90,66 @@ func doc() map[string]any { "description": "Says hello and returns OS version from /etc/os-release.", "arguments": []any{ - // none required; keep it empty array, not null, not map. + map[string]any{ + "name": "key", + "type": "string", + "description": "A key inside the /etc/os-release file to retrieve (not used in this example). Default: VERSION", + "required": true, + }, }, - "options": []any{ - // none + map[string]any{ + "name": "nohello", + "description": "Do not say hello", + }, }, "examples": []any{ map[string]any{ "description": "Get module output", - "code": `{ "args": { "mod": "hellodude" } }`, + "code": `{ "args": { "key": "VERSION" } }`, }, map[string]any{ "description": "Get module documentation", - "code": `{ "args": { "mod": "hellodude", "rt.man": true } }`, + "code": `{ "args": { "key": "VERSION" }, "opts": ["man"] }`, }, }, "returns": map[string]any{ - "description": "Returns a greeting and OS release info (if accessible).", + "description": "Returns greeting and OS release info (if accessible).", "sample": map[string]any{ "output": "hello, dude", "os": map[string]any{ - "NAME": "Debian GNU/Linux", - "VERSION_ID": "12", "PRETTY_NAME": "Debian GNU/Linux 12 (bookworm)", + "VERSION_ID": "12", }, }, }, } } -// Run the module logic -func run(hdr Header) map[string]any { - _ = hdr // args/opts currently unused, but kept for future “CfgMgmt shit”. - +func run(_hdr Header) map[string]any { osr, err := readOSRelease() if err != nil { return map[string]any{ "error": "failed to read /etc/os-release", "detail": err.Error(), + "output": "hello, dude", + "os": nil, } } - // Return the module data return map[string]any{ - "output": "Hello, world!", - "VERSION": osr["VERSION"], + "output": "hello, dude", + "os": map[string]any{ + "NAME": osr["NAME"], + "ID": osr["ID"], + "VERSION_ID": osr["VERSION_ID"], + "PRETTY_NAME": osr["PRETTY_NAME"], + }, } } -// WASI entry function func main() { hdr, err := readHeader() if err != nil { @@ -137,13 +157,12 @@ func main() { os.Exit(1) } - // doc-mode: args["rt.man"] == true - if hdr.Args != nil && scalar2bool(hdr.Args["rt.man"]) { - b, _ := json.Marshal(doc()) - fmt.Println(string(b)) - return - } + enc := json.NewEncoder(os.Stdout) + enc.SetEscapeHTML(false) - b, _ := json.Marshal(run(hdr)) - fmt.Println(string(b)) + if hasOpt(hdr.Opts, "man") { + _ = enc.Encode(doc()) + } else { + _ = enc.Encode(run(hdr)) + } } From 5cb2bd52e593b8c0e4323914fa02f77133b73180 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 18:54:05 +0100 Subject: [PATCH 18/40] Update hello example: take care of a specific key --- Cargo.lock | 31 ++++++++-------- .../wasm-runtime/examples/hello/Makefile | 4 +-- .../wasm-runtime/examples/hello/main.go | 36 +++++++++++++------ 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80536ec0..15ac0c6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5866,7 +5866,7 @@ dependencies = [ [[package]] name = "rustpython" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "cfg-if", "dirs-next", @@ -5886,7 +5886,7 @@ dependencies = [ [[package]] name = "rustpython-codegen" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ahash 0.8.12", "bitflags 2.10.0", @@ -5909,7 +5909,7 @@ dependencies = [ [[package]] name = "rustpython-common" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ascii", "bitflags 2.10.0", @@ -5938,7 +5938,7 @@ dependencies = [ [[package]] name = "rustpython-compiler" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ruff_python_ast", "ruff_python_parser", @@ -5952,7 +5952,7 @@ dependencies = [ [[package]] name = "rustpython-compiler-core" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "bitflags 2.10.0", "itertools 0.14.0", @@ -5966,7 +5966,7 @@ dependencies = [ [[package]] name = "rustpython-derive" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "rustpython-compiler", "rustpython-derive-impl", @@ -5976,7 +5976,7 @@ dependencies = [ [[package]] name = "rustpython-derive-impl" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "itertools 0.14.0", "maplit", @@ -5992,7 +5992,7 @@ dependencies = [ [[package]] name = "rustpython-doc" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "phf 0.13.1", ] @@ -6000,7 +6000,7 @@ dependencies = [ [[package]] name = "rustpython-literal" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "hexf-parse", "is-macro", @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "rustpython-pylib" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "glob", "rustpython-compiler-core", @@ -6023,7 +6023,7 @@ dependencies = [ [[package]] name = "rustpython-sre_engine" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "bitflags 2.10.0", "num_enum", @@ -6034,7 +6034,7 @@ dependencies = [ [[package]] name = "rustpython-stdlib" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "adler32", "ahash 0.8.12", @@ -6118,7 +6118,7 @@ dependencies = [ [[package]] name = "rustpython-vm" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ahash 0.8.12", "ascii", @@ -6191,7 +6191,7 @@ dependencies = [ [[package]] name = "rustpython-wtf8" version = "0.4.0" -source = "git+https://github.com/RustPython/RustPython.git#6a3643cdde634f1096df370b83bb5807a0f4ab45" +source = "git+https://github.com/RustPython/RustPython.git#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ascii", "bstr", @@ -8312,9 +8312,10 @@ dependencies = [ [[package]] name = "wasmruntime" version = "0.1.0" -source = "git+https://github.com/isbm/wasmruntime.git#6c69fb4e9be45f909d7c9c5ae5652d88af463a53" +source = "git+https://github.com/isbm/wasmruntime.git#e33aeb53f72a0bca066d7e2af08ef8562eae724c" dependencies = [ "anyhow", + "serde", "serde_json", "tokio", "wasi-common", diff --git a/modules/runtime/wasm-runtime/examples/hello/Makefile b/modules/runtime/wasm-runtime/examples/hello/Makefile index 5cc6c89f..4527672c 100644 --- a/modules/runtime/wasm-runtime/examples/hello/Makefile +++ b/modules/runtime/wasm-runtime/examples/hello/Makefile @@ -43,7 +43,7 @@ define REQUIRE_COMPILER fi endef -debug: +debug: clean @mkdir -p $(OUTDIR) @$(REQUIRE_COMPILER) @if [ "$(WASM_COMPILER)" = "tinygo" ]; then \ @@ -55,7 +55,7 @@ debug: fi @echo "Built debug: $(DEBUG_WASM)" -release: +release: clean @mkdir -p $(OUTDIR) @$(REQUIRE_COMPILER) @if [ "$(WASM_COMPILER)" = "tinygo" ]; then \ diff --git a/modules/runtime/wasm-runtime/examples/hello/main.go b/modules/runtime/wasm-runtime/examples/hello/main.go index 281cda2b..d7b795f7 100644 --- a/modules/runtime/wasm-runtime/examples/hello/main.go +++ b/modules/runtime/wasm-runtime/examples/hello/main.go @@ -128,26 +128,40 @@ func doc() map[string]any { } } -func run(_hdr Header) map[string]any { +func run(hdr Header) map[string]any { osr, err := readOSRelease() if err != nil { return map[string]any{ "error": "failed to read /etc/os-release", "detail": err.Error(), - "output": "hello, dude", - "os": nil, } } - return map[string]any{ - "output": "hello, dude", - "os": map[string]any{ - "NAME": osr["NAME"], - "ID": osr["ID"], - "VERSION_ID": osr["VERSION_ID"], - "PRETTY_NAME": osr["PRETTY_NAME"], - }, + key := "VERSION" // Default key + if hdr.Args != nil { + if v, ok := hdr.Args["key"]; ok { + if s, ok := v.(string); ok && strings.TrimSpace(s) != "" { + key = strings.TrimSpace(s) + } + } } + + val, ok := osr[key] + if !ok { + return map[string]any{ + "error": "unknown os-release key", + "key": key, + } + } + + out := map[string]any{ + key: val, + } + if !hasOpt(hdr.Opts, "nohello") { + out["output"] = "hello, dude" + } + + return out } func main() { From 06bd1afec18271abff86b851a76fb16e4f585459 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Mon, 26 Jan 2026 18:55:53 +0100 Subject: [PATCH 19/40] Add a caller example: how to make system calls from within the WASM sandbox, using sysinspect API. --- .../wasm-runtime/examples/caller/Makefile | 84 +++++++++++++++++++ .../wasm-runtime/examples/caller/go.mod | 3 + .../wasm-runtime/examples/caller/main.go | 68 +++++++++++++++ .../examples/caller/sysinspect/sysinspect.go | 65 ++++++++++++++ 4 files changed, 220 insertions(+) create mode 100644 modules/runtime/wasm-runtime/examples/caller/Makefile create mode 100644 modules/runtime/wasm-runtime/examples/caller/go.mod create mode 100644 modules/runtime/wasm-runtime/examples/caller/main.go create mode 100644 modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go diff --git a/modules/runtime/wasm-runtime/examples/caller/Makefile b/modules/runtime/wasm-runtime/examples/caller/Makefile new file mode 100644 index 00000000..7b610620 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/caller/Makefile @@ -0,0 +1,84 @@ +MODULE := caller +SRC := main.go +OUTDIR := build/lib/runtime/wasm + +# You MUST set this: WASM_COMPILER=go or WASM_COMPILER=tinygo +WASM_COMPILER ?= + +GO ?= go +TINYGO ?= tinygo +WASM_OPT ?= wasm-opt # optional (Binaryen). If missing, we skip it. + +DEBUG_WASM := $(OUTDIR)/$(MODULE)_debug.wasm +RELEASE_WASM := $(OUTDIR)/$(MODULE).wasm + +.PHONY: help debug release clean check + +help: + @echo "Usage:" + @echo " WASM_COMPILER=go make debug|release" + @echo " WASM_COMPILER=tinygo make debug|release" + @echo + @echo "Targets:" + @echo " debug - build debuggable WASI wasm" + @echo " release - build smallest WASI wasm we can reasonably squeeze" + @echo " check - show tool availability" + @echo " clean - remove build artifacts" + +check: + @echo "WASM_COMPILER=$(WASM_COMPILER)" + @echo "go: $$(command -v $(GO) >/dev/null 2>&1 && $(GO) version || echo MISSING)" + @echo "tinygo: $$(command -v $(TINYGO) >/dev/null 2>&1 && $(TINYGO) version || echo MISSING)" + @echo "wasm-opt (optional): $$(command -v $(WASM_OPT) >/dev/null 2>&1 && $(WASM_OPT) --version || echo MISSING)" + +# --- guardrails (cry if unset / invalid) --- +define REQUIRE_COMPILER + @if [ -z "$(WASM_COMPILER)" ]; then \ + echo "ERROR: WASM_COMPILER is not set. Use WASM_COMPILER=go or WASM_COMPILER=tinygo"; \ + exit 2; \ + fi + @if [ "$(WASM_COMPILER)" != "go" ] && [ "$(WASM_COMPILER)" != "tinygo" ]; then \ + echo "ERROR: WASM_COMPILER must be 'go' or 'tinygo' (got: $(WASM_COMPILER))"; \ + exit 2; \ + fi +endef + +debug: clean + @mkdir -p $(OUTDIR) + @$(REQUIRE_COMPILER) + @if [ "$(WASM_COMPILER)" = "tinygo" ]; then \ + command -v $(TINYGO) >/dev/null 2>&1 || (echo "ERROR: tinygo missing"; exit 2); \ + $(TINYGO) build -target=wasi -o $(DEBUG_WASM) -debug -opt=1 $(SRC); \ + else \ + command -v $(GO) >/dev/null 2>&1 || (echo "ERROR: go missing"; exit 2); \ + GOOS=wasip1 GOARCH=wasm $(GO) build -o $(DEBUG_WASM) $(SRC); \ + fi + @echo "Built debug: $(DEBUG_WASM)" + +release: clean + @mkdir -p $(OUTDIR) + @$(REQUIRE_COMPILER) + @if [ "$(WASM_COMPILER)" = "tinygo" ]; then \ + command -v $(TINYGO) >/dev/null 2>&1 || (echo "ERROR: tinygo missing"; exit 2); \ + $(TINYGO) build -target=wasi -o $(RELEASE_WASM) -no-debug -opt=z -panic=trap $(SRC); \ + else \ + command -v $(GO) >/dev/null 2>&1 || (echo "ERROR: go missing"; exit 2); \ + GOOS=wasip1 GOARCH=wasm $(GO) build -o $(RELEASE_WASM) -trimpath -ldflags="-s -w" $(SRC); \ + fi + @# Optional: squeeze harder with wasm-opt if available + @if command -v $(WASM_OPT) >/dev/null 2>&1; then \ + echo "Running wasm-opt for extra shrink..."; \ + $(WASM_OPT) --all-features -Oz --strip-debug --strip-producers $(RELEASE_WASM) -o $(RELEASE_WASM); \ + else \ + echo "wasm-opt not found; skipping extra squeezing."; \ + fi + @echo "Built release: $(RELEASE_WASM)" + +run: + @echo "Running module (test preview)..." + @echo '{"config": {"path.sharelib": "${PWD}/build"}, "args": {"rt.mod": "hellodude"}}' | ../../../../../target/debug/runtime/wasm-runtime | jq + + +clean: + rm -rf $(OUTDIR) + rm -rf build diff --git a/modules/runtime/wasm-runtime/examples/caller/go.mod b/modules/runtime/wasm-runtime/examples/caller/go.mod new file mode 100644 index 00000000..2dafd962 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/caller/go.mod @@ -0,0 +1,3 @@ +module stuffspawner + +go 1.23.0 diff --git a/modules/runtime/wasm-runtime/examples/caller/main.go b/modules/runtime/wasm-runtime/examples/caller/main.go new file mode 100644 index 00000000..6cf7aa91 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/caller/main.go @@ -0,0 +1,68 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + + "stuffspawner/sysinspect" +) + +type Header struct { + Opts []string `json:"opts"` + Args map[string]interface{} `json:"args"` +} + +func readHeader() (Header, error) { + in := bufio.NewScanner(os.Stdin) + var hdr Header + if !in.Scan() { + return hdr, fmt.Errorf("missing header JSON") + } + if err := json.Unmarshal(in.Bytes(), &hdr); err != nil { + return hdr, err + } + return hdr, nil +} + +func doc() map[string]any { + return map[string]any{ + "name": "caller", "version": "0.1.0", "author": "Gru", + "description": "Executes `uname -a` via host syscall and returns stdout.", + "arguments": []any{}, "options": []any{}, + "examples": []any{ + map[string]any{"description": "Run uname", "code": `{ "args": {} }`}, + map[string]any{"description": "Show docs", "code": `{ "args": {}, "opts": ["man"] }`}, + }, + "returns": map[string]any{ + "description": "Returns stdout of uname -a", + "sample": map[string]any{"output": "Linux host ..."}, + }, + } +} + +func main() { + hdr, err := readHeader() + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetEscapeHTML(false) + + for _, o := range hdr.Opts { + if o == "man" { + _ = enc.Encode(doc()) + return + } + } + + out, err := sysinspect.Command("/usr/bin/uname", "-a").Output() + if err != nil { + _ = enc.Encode(map[string]any{"error": err.Error()}) + return + } + _ = enc.Encode(map[string]any{"output": out}) +} diff --git a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go new file mode 100644 index 00000000..c2575403 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go @@ -0,0 +1,65 @@ +// Package sysinspect provides a way to run system inspection commands +// on the host system from within a WebAssembly module. +package sysinspect + +import ( + "encoding/json" + "fmt" + "unsafe" +) + +//go:wasmimport api exec +func execJSON(reqPtr, reqLen, outPtr, outCap uint32) int32 + +type Cmd struct { + Argv []string + Cwd string +} + +func Command(name string, args ...string) *Cmd { + argv := make([]string, 0, 1+len(args)) + argv = append(argv, name) + argv = append(argv, args...) + return &Cmd{Argv: argv} +} + +func (c *Cmd) SetDir(dir string) *Cmd { c.Cwd = dir; return c } + +// Output returns stdout; stderr is returned as error if exit_code != 0 +func (c *Cmd) Output() (string, error) { + req := map[string]any{"argv": c.Argv} + if c.Cwd != "" { + req["cwd"] = c.Cwd + } + + reqb, err := json.Marshal(req) + if err != nil { + return "", err + } + + out := make([]byte, 256*1024) // a buffer for host response + + n := execJSON( + uint32(uintptr(unsafe.Pointer(&reqb[0]))), + uint32(len(reqb)), + uint32(uintptr(unsafe.Pointer(&out[0]))), + uint32(len(out)), + ) + if n < 0 { + return "", fmt.Errorf("host exec failed (%d)", n) + } + + var resp struct { + ExitCode int `json:"exit_code"` + Stdout string `json:"stdout"` + Stderr string `json:"stderr"` + } + if err := json.Unmarshal(out[:n], &resp); err != nil { + return "", fmt.Errorf("bad host response json: %w", err) + } + + if resp.ExitCode != 0 { + return resp.Stdout, fmt.Errorf("exit %d: %s", resp.ExitCode, resp.Stderr) + } + return resp.Stdout, nil +} From 9a1aec067f9314341e772cf29688d997069b7d4f Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 01:13:34 +0100 Subject: [PATCH 20/40] Update dependencies --- Cargo.lock | 155 +++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15ac0c6c..65c62d98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1219,36 +1219,36 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76779f01dcf5d1b0663f4268f9b3395a023026815f41fe152bae61b3c60f3f" +checksum = "57cc4ac031157d0206cf6a8faa48284034721cd367a45e004c4e06329f51e106" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "032bb8ce6871b294308a93621aabb80e7315b5dbfba3a06ecaca41542a8abbfe" +checksum = "5a121c08faeeca04c85280dbddb19521e3ed7169430fd6abc34496e656c18b20" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424289b574e612b6a048132492abff290f044052bbfe5460156f03f76c3271d1" +checksum = "39f2b2cd8224147b4e193c2de68cf0085b693b242bb766c594828db3907151cb" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7aecdaa37cd169b4d92b0efb8ca81a40bebb5f588ea3310f5549652e4251e67" +checksum = "0f7468865d7cf72637a30d5fb97c4fc38b6ea82ab54ca913c81e7403274802be" dependencies = [ "serde", "serde_derive", @@ -1256,9 +1256,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c529540ae49bbdc84afc2f8d75ad8c9441f9d50a6e0ae1825d88ad5397085a4c" +checksum = "e96c94a373ec1a35fb889730525f3fd220e66b1cf222b3426f5eb6e0404718e5" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -1283,9 +1283,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0e66d3093d57b4853aa1b751e706136e65012c76db7ddbf6e40c0c369fa516" +checksum = "e5904cbc4e8d4f8a69129a365da30d6f9f0e6ca024c4e0728d5da615e8db3c44" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -1296,24 +1296,24 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98fa7ddc3a113e5916b3af16e5b85037d4bf2dda39de27e42d2dc915e1141ad9" +checksum = "b1009f9e206d5fba4add039539f3e16378815a53b8477bd2d1fc8e3bde6ea93a" [[package]] name = "cranelift-control" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f9abf903ccdca830124ce24bdb3050fdfbb8730f70b46f6183226f569713afe" +checksum = "a0c5e3cc40402febecdba0a9e45999b1ab9aef8b120833182b08830b7be292fb" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c25543bb984920680b614d4ff30756ec722a4257926356934609906de179e500" +checksum = "d58a1de9bdab836734c42902ce948a5cdcc923ae8ce30b29a24dbe76098df659" dependencies = [ "cranelift-bitset", "serde", @@ -1322,9 +1322,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8def0c7a84e1b4de15f4b5f514ae74c2e3acfbc9c7380c5cc74b17ee4f19bdc" +checksum = "fd3423b326097e627a378c106eb57d5ddb3f303d4deb87d29bf8b982dd1d6afc" dependencies = [ "cranelift-codegen", "log", @@ -1334,15 +1334,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9cace5d2c5faa6c273c19c6e116fab05be704f2f423d7a08f8ba5e15521728" +checksum = "f56f0e7abec391b94314ab2e9a1002c5a0aed6e29e4709318a7e33315767bed7" [[package]] name = "cranelift-native" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e5bda84f8b8580ce83679a1957c41464af102fc08065e34e55e31f990b61e7" +checksum = "e528d9c791306c55c3bef6c70a77cc9712ca9a32b12bae86924224e65604cb69" dependencies = [ "cranelift-codegen", "libc", @@ -1351,9 +1351,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.123.4" +version = "0.123.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9ae0f07c362d514dbf9e91fe555700f00326026d0e65592ed4073e5427cd59e" +checksum = "8558dda6bd86b48c7b31b46555b5eed24b55c839e554a42765c23bf98de62997" [[package]] name = "crc32fast" @@ -5041,9 +5041,9 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4c7fbfe494bf7b779aabe689e33d221f49121f1d6253c3ec4f62d2f9ff7019" +checksum = "d56a1abe1fcec21c32b62000af24b8b6db11b87609b64fd1c9a9e17c42422225" dependencies = [ "cranelift-bitset", "log", @@ -5053,9 +5053,9 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40289747955f4ccf84a48ad1e5bc7753bf3e9378c3c8dabc6110cc38043a737" +checksum = "b0d56dac306fbee0e990d4bac359c86d58f60f058e1e2d1aee1b7928689f08d3" dependencies = [ "proc-macro2", "quote", @@ -8142,9 +8142,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi-common" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5efed76a0f40420549835c4e14bfc3e7a754985bbeca671b4e5adc2a648056" +checksum = "a0ffc257572bd9d2dc138726c96504100b04b33ddf226dfbf3b7f90c2fca835c" dependencies = [ "anyhow", "bitflags 2.10.0", @@ -8312,9 +8312,10 @@ dependencies = [ [[package]] name = "wasmruntime" version = "0.1.0" -source = "git+https://github.com/isbm/wasmruntime.git#e33aeb53f72a0bca066d7e2af08ef8562eae724c" +source = "git+https://github.com/isbm/wasmruntime.git#9723eefb6dc256b82815c1c2420c747929ade4b7" dependencies = [ "anyhow", + "chrono", "serde", "serde_json", "tokio", @@ -8325,9 +8326,9 @@ dependencies = [ [[package]] name = "wasmtime" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a269aaef6526f16091c0f3a5fe62631037cb3b9fb9cb1deb521c6ac7a5a6ee91" +checksum = "901adbcfe03e3ad9db86f5665d6e00d54c904d4b81235c375635991596dfef3b" dependencies = [ "addr2line", "anyhow", @@ -8380,9 +8381,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187f76529a8b2e36e87e48f1dcdc8c39340ff962359f653be7aa864bff9c9b7a" +checksum = "00984333e84fa259b72b5bc113e1699d04f20c3ac191bf3e268e32bd93e493fd" dependencies = [ "anyhow", "cpp_demangle", @@ -8407,18 +8408,18 @@ dependencies = [ [[package]] name = "wasmtime-internal-asm-macros" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37edf8f7c7a23ab18d6bf5742e323c969571b8c35b990da48090b7b1ccacfca7" +checksum = "a8f42078a2603132bb5d7f2d5114ce57992e0fa344a9521385dc159c63472a9a" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-internal-cache" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009fffd3d90fe939de7b6f101633f465b6505d70b9a5f6d62746b7a52d2a9f99" +checksum = "19ae7355594563bec11af97afb429ea8576f497960a78d59684ffabd11a862b8" dependencies = [ "anyhow", "base64", @@ -8436,9 +8437,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f752eede244eff36ed4ac5709d8bd94735f1f0db68e48e026d566589d1d914" +checksum = "8c271bbe00cf374564ee37bee4fe298f8ad10e267aba07b2ec598d376677f062" dependencies = [ "anyhow", "proc-macro2", @@ -8451,15 +8452,15 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-util" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077f5204aee8002178acc6ee4619b070bbfba0957cbcd0f968d92fb729be9229" +checksum = "a61fa3310d28256440f4bad63bd9462f364ee9faca7c3dcfccc7c2a48db46005" [[package]] name = "wasmtime-internal-cranelift" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa3a13862aa8d4c94a34260cfd0c309c1d2d04e2bd8e4d95b10e5a6481341d5" +checksum = "6401e096bfbb50e75a00bd83162fee68b1800d65937364463a4ad43da3f140f8" dependencies = [ "anyhow", "cfg-if", @@ -8484,9 +8485,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-fiber" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ceb5817493b5b466f87a3da77ba0148d85ea29778d86546f070a31123f023e3" +checksum = "8dd592465c4fffd866fc6f50db2cc7ae0c73d2742699e351b3680b5f84f21ede" dependencies = [ "anyhow", "cc", @@ -8500,9 +8501,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eac6f645873bc2a5961b4745cc5f07a0a7d53f970c806d8153fdf6941703e39" +checksum = "3d6c60a180c90eea53266a6627c353a8101090f1e084f59e1bd4666f5c55e405" dependencies = [ "cc", "object", @@ -8512,9 +8513,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64ee722c4d42bc81559ddd0b1559645638bd84ba6439118e1a91eab88031b2e" +checksum = "efe8de0903b246b59b112f2a7116f3d2315c41a9252ab78de90dae93b9cab50e" dependencies = [ "anyhow", "cfg-if", @@ -8524,24 +8525,24 @@ dependencies = [ [[package]] name = "wasmtime-internal-math" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de6fb4327b70b10c6b55352d19b279b2fb2bc74537ed7d5c20edc8ff0638dda7" +checksum = "8e1d143a7388e4adfae7c1d6c6ceb44325b4b45b2e393e39b25ddaf563e7e587" dependencies = [ "libm", ] [[package]] name = "wasmtime-internal-slab" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afaa5d4c2db6fe47e07fef7f6d4030e8a5d6f6cb1c31bcfcbd9aff569a8b55a0" +checksum = "de954a96e144df5b22805367f91a1754237f6bf99918f087d0ea1970be3b6365" [[package]] name = "wasmtime-internal-unwinder" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7282e8fbdc6d10f1e34feaac0c1694701f3c580880346e0cbbd4be49a1a901" +checksum = "9923ac3d2b967e8ecbfefddaf19909b6a9a03b5b969b2a71af52300e3e404419" dependencies = [ "anyhow", "cfg-if", @@ -8552,9 +8553,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4e078eb9916af6885193eca8ef6f0198aedf68db24ff8acc72bfaaef2c8b26" +checksum = "ef2c0062b75377b8d0a20239436b06df2e01a3521e9f14af6ea9b438c60fc030" dependencies = [ "proc-macro2", "quote", @@ -8563,9 +8564,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-winch" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33f0c6532aeccecb2bb9f0f7abb34095ba54523080ff3f2c7a86347611096668" +checksum = "8542e7cfd5b77ad33ac4cab866cb2b2eca350c7c34ac73e13fe78e83871ad3d7" dependencies = [ "anyhow", "cranelift-codegen", @@ -8580,9 +8581,9 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6f1c3d410baf3b6f203efbc000444e60da4cbb9034c7d8706ed68aaa6ff936" +checksum = "04c8be7f99d674c7af47ceba83ee4dc4e36132798c920a7bfd7ca44ce7733f99" dependencies = [ "anyhow", "bitflags 2.10.0", @@ -8593,9 +8594,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760b9be6760a8121d9fbba587f5eaeff2e7188abdc4325d3ae78d9fb50974cb4" +checksum = "001ee40c4a289579b0ef3c72cad1396a372dfb535b7b542ca4f7cb68d0566009" dependencies = [ "anyhow", "async-trait", @@ -8624,9 +8625,9 @@ dependencies = [ [[package]] name = "wasmtime-wasi-io" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bb4c0fd892636a9fdc89f24ef8e678ba2f3c40e2dcf3e2317883b942de2c79" +checksum = "b69017e34b0285e3bce3add58b2895aded308400e5ad37ad4f670b0f9127d88f" dependencies = [ "anyhow", "async-trait", @@ -8723,9 +8724,9 @@ checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" [[package]] name = "wiggle" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55276f3072e422ecee4bc4141a004e76113d6fb5032fc75e3b7136fb60349bf9" +checksum = "7d63a4f105596bfd9378d1f80659d01045f3ac803c4a1fab13ffe10e8d63227d" dependencies = [ "anyhow", "async-trait", @@ -8738,9 +8739,9 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a00f6046d9ed0cb65d84948335264610192fc27bc4141c684fc4c382dcca041" +checksum = "c686a505d73cfd3508be4c92a51b7b3fac2268879c3bbb6bc98e37885fca8eb3" dependencies = [ "anyhow", "heck", @@ -8752,9 +8753,9 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8290efe5627229cd5fe5dfb90b4e201b214d353f55ca5ecaca82c273a45a7ad1" +checksum = "efd3ac0e3ab2375cd9f439a4653fa714ca66798b1c8a3138db6ac752c600c77b" dependencies = [ "proc-macro2", "quote", @@ -8795,9 +8796,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "36.0.4" +version = "36.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf09d7c135f28b757699883820fd0aa41ef4a3916759aa12f32d850ced6a505" +checksum = "3ce0c15cfd084585ed8f5519d4f405de98ff530f6afe31b88a5560688879c85e" dependencies = [ "anyhow", "cranelift-assembler-x64", From 44187d4a524fc34d398fb21c480d05c077ecf0ea Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 01:13:54 +0100 Subject: [PATCH 21/40] Drop a few log examples --- modules/runtime/wasm-runtime/examples/caller/main.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/runtime/wasm-runtime/examples/caller/main.go b/modules/runtime/wasm-runtime/examples/caller/main.go index 6cf7aa91..ac3246e9 100644 --- a/modules/runtime/wasm-runtime/examples/caller/main.go +++ b/modules/runtime/wasm-runtime/examples/caller/main.go @@ -6,7 +6,7 @@ import ( "fmt" "os" - "stuffspawner/sysinspect" + api "stuffspawner/sysinspect" ) type Header struct { @@ -59,10 +59,15 @@ func main() { } } - out, err := sysinspect.Command("/usr/bin/uname", "-a").Output() + out, err := api.Command("/usr/bin/uname", "-a").Output() + api.Log(api.Info, "Executed: \"uname -a\", output length: %d", len(out)) if err != nil { _ = enc.Encode(map[string]any{"error": err.Error()}) return } _ = enc.Encode(map[string]any{"output": out}) + + api.Log(api.Error, "This is an error log example") + api.Log(api.Warn, "This is a warning log example") + api.Log(api.Info, "Finished successfully") } From d0385dd5fa1e57c974f2831c282b661fc8a7243e Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 01:14:27 +0100 Subject: [PATCH 22/40] Extend a Sysinspect ergonomics wrapper for Go language for logger --- .../examples/caller/sysinspect/sysinspect.go | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go index c2575403..c0bd27b3 100644 --- a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go +++ b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go @@ -1,6 +1,6 @@ -// Package sysinspect provides a way to run system inspection commands +// Package log provides a way to run system inspection commands // on the host system from within a WebAssembly module. -package sysinspect +package api import ( "encoding/json" @@ -9,7 +9,10 @@ import ( ) //go:wasmimport api exec -func execJSON(reqPtr, reqLen, outPtr, outCap uint32) int32 +func __execJSON(reqPtr, reqLen, outPtr, outCap uint32) int32 + +//go:wasmimport api log +func __hostLog(level int32, msgPtr, msgLen uint32) type Cmd struct { Argv []string @@ -39,7 +42,7 @@ func (c *Cmd) Output() (string, error) { out := make([]byte, 256*1024) // a buffer for host response - n := execJSON( + n := __execJSON( uint32(uintptr(unsafe.Pointer(&reqb[0]))), uint32(len(reqb)), uint32(uintptr(unsafe.Pointer(&out[0]))), @@ -63,3 +66,24 @@ func (c *Cmd) Output() (string, error) { } return resp.Stdout, nil } + +const ( + Debug = 0 + Info = 1 + Warn = 2 + Error = 3 +) + +// Log sends a formatted log line to the host runtime. +func Log(level int32, format string, args ...any) { + msg := fmt.Sprintf(format, args...) + if msg == "" { + return + } + b := []byte(msg) + __hostLog( + level, + uint32(uintptr(unsafe.Pointer(&b[0]))), + uint32(len(b)), + ) +} From 412fc4d2d6a5938de0f42ca0158e88ad4f7e8e57 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 01:14:54 +0100 Subject: [PATCH 23/40] Forward logs from the Wasi lib --- modules/runtime/wasm-runtime/src/wart.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/runtime/wasm-runtime/src/wart.rs b/modules/runtime/wasm-runtime/src/wart.rs index 404c436c..d2c231da 100644 --- a/modules/runtime/wasm-runtime/src/wart.rs +++ b/modules/runtime/wasm-runtime/src/wart.rs @@ -1,6 +1,11 @@ use futures::executor; -use libmodcore::{response::ModResponse, runtime::ModRequest}; +use libmodcore::{ + response::ModResponse, + rtspec::RuntimeSpec, + runtime::ModRequest, +}; use libsysinspect::SysinspectError; +use serde_json::Value; use wasmruntime::cfg::WasmConfig; /// Config entry for path to shared library @@ -99,7 +104,7 @@ impl WasmRuntime { } // `run` is async and returns a Future; we must drive it to completion. - let out = match executor::block_on(self.rt.run( + let mut out = match executor::block_on(self.rt.run( &mod_id, self.rq.options().iter().map(|v| v.as_string().unwrap_or_default()).filter(|s| !s.is_empty()).collect(), self.rq.args().into_iter().map(|(k, v)| (k, v.into())).collect(), @@ -113,6 +118,11 @@ impl WasmRuntime { Ok(val) => val, }; + if let Value::Object(ref mut map) = out + && let Some(v) = map.remove("__module-logs") { + map.insert(RuntimeSpec::LogsSectionField.to_string(), v); + } + r.set_message("Wasm runtime executed successfully"); r.set_retcode(0); if let Err(err) = r.set_data(out) { From 907c25bd819f94a260f25e09550743dfce39a84f Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 17:18:50 +0100 Subject: [PATCH 24/40] Add Wasm/WASI tutorial --- docs/index.rst | 1 + docs/tutorial/wasm_modules_tutor.rst | 311 +++++++++++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 docs/tutorial/wasm_modules_tutor.rst diff --git a/docs/index.rst b/docs/index.rst index 6c63ff2e..86c28be2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -45,6 +45,7 @@ welcome—see the section on contributing for how to get involved. tutorial/cfgmgmt_tutor tutorial/action_chain_tutor tutorial/module_management + tutorial/wasm_modules_tutor tutorial/lua_modules_tutor diff --git a/docs/tutorial/wasm_modules_tutor.rst b/docs/tutorial/wasm_modules_tutor.rst new file mode 100644 index 00000000..3f41a328 --- /dev/null +++ b/docs/tutorial/wasm_modules_tutor.rst @@ -0,0 +1,311 @@ +.. _wasm_tutorial: + +Using Wasm Modules +=================== + +.. note:: + This tutorial shows how to run WebAssembly (Wasm) modules in Sysinspect and explains + how the Wasm runtime behaves internally. + +Reasoning +--------- + +WebAssembly in Sysinspect is **not about browsers**. + +Here, Wasm is used as a *portable execution format*, comparable to a Java ``.jar``: +a single, architecture-independent artifact that can be distributed and executed +consistently across heterogeneous systems. + +Traditional configuration management systems (Ansible, Salt, Puppet, etc.) primarily execute +scripts or, in some cases, native binaries directly on the target system. As soon as compiled binaries +are involved, this approach becomes fragile: + +- CPU architecture differences +- libc and ABI mismatches +- platform-specific packaging +- manual dependency logistics +- inconsistent runtime behavior + +Sysinspect already solves binary logistics by distributing architecture-specific packages +automatically. However, Wasm enables a different and often simpler model: + +- one **noarch** artifact +- sandboxed execution +- explicit host interaction +- predictable behavior across platforms + +In Sysinspect, a Wasm module behaves operationally like a script, even though it is +compiled. You build it once, publish it once, and run it everywhere. + +.. hint:: + + Surely, one can compile native binaries for each architecture and develop binary modules directly. + + Yes, but this quickly becomes tedious and complex, as your module must also take care + of direct integration with Sysinspect itself. Wasm offers a more elegant solution and isolates all + the integration bits away from the module logic, allowing you to focus on the core functionality. + +Prerequisites +------------- + +Before you begin, ensure you have: + +- A working installation of Sysinspect. +- Basic understanding of WebAssembly and WASI. +- Access to the SysMaster node. +- Permission to register modules and sync the cluster. +- A compiler capable of targeting WASI (for example: `TinyGo`_, `Zig`_, `Grain`_, `Swift`_, `Rust`_, and many more). + +.. _TinyGo: https://tinygo.org +.. _Zig: https://ziglang.org +.. _Grain: https://grain-lang.org +.. _Rust: https://www.rust-lang.org +.. _Swift: https://swift.org + +Installing Wasm Runtime +----------------------- + +Sysinspect executes Wasm modules through a *runtime module*. +A runtime module is a standard Sysinspect module that embeds a Wasm engine and defines +how Wasm code interacts with the host system. + +To execute Wasm binaries, a Wasm runtime must be present in the package repository. + +Build the runtime +^^^^^^^^^^^^^^^^^ + +If building Sysinspect from source: + +.. code-block:: bash + + make + +The Wasm runtime binary is typically located at: + +.. code-block:: bash + + $SRC/target/release/runtime/wasm-runtime + +Register the runtime +^^^^^^^^^^^^^^^^^^^^ + +Register the runtime on the SysMaster: + +.. code-block:: bash + + sysinspect module -A \ + --path /path/to/target/release/runtime/wasm-runtime \ + --name "runtime.wasm-runtime" \ + --descr "Wasm runtime" + +Verify registration: + +.. code-block:: bash + + sysinspect module -L + +Then sync the cluster: + +.. code-block:: bash + + sysinspect --sync + +Installing Wasm Modules +----------------------- + +Wasm user modules are distributed as compiled ``.wasm`` files. From Sysinspect’s +perspective, these are **noarch executable artifacts** handled by the Wasm runtime. + +Directory layout +^^^^^^^^^^^^^^^^ + +Wasm modules are installed as a library tree, similar to Lua scripts: + +.. code-block:: text + + lib/ + runtime/ + wasm/ + hellodude.wasm + caller.wasm + reader.wasm + +The important rule is consistency: upload the directory tree, not individual files, +so all nodes observe identical paths. + +Publish the modules +^^^^^^^^^^^^^^^^^^^ + +Upload the directory containing the Wasm modules: + +.. code-block:: bash + + sysinspect module -A --path ./lib -l + +Then sync the cluster: + +.. code-block:: bash + + sysinspect --sync + +Verify: + +.. code-block:: bash + + sysinspect module -Ll + +Execution Model and JIT Compilation +----------------------------------- + +When a Wasm module is executed **for the first time** on a node, the runtime performs +a one-time compilation step: + +- The ``.wasm`` file is translated into a cached native representation + (``.cwasm`` internally). +- The cached artifact is an **ELF relocatable object**, specific to the host architecture. +- Subsequent executions reuse the cached artifact and are significantly faster. + +This is conceptually similar to Python’s ``.pyc`` or ``.pyo`` files. + +.. important:: + + Cached ``.cwasm`` artifacts are **not** tracked by the Sysinspect package manager, because they are: + + - architecture-dependent + - node-local + - runtime-managed + + They must never be uploaded or distributed. They appear automatically and are removed automatically on the next sync. + Shipping a cached artifact to a different architecture will result in undefined behavior. + +Language Support +---------------- + +Any language capable of compiling to **WASI** can theoretically be used. + +In practice: + +1. **TinyGo** is the recommended choice. It offers: + + - small binaries + - predictable output + - good WASI support + + You can also use standard Go with ``GOOS=js GOARCH=wasm``, but TinyGo produces much smaller + and faster binaries. + +2. Rust or C/C++ are also very well supported. But practically you most likely want +to be productive and make your module as fast as possible with as minimal overhead. +From this perspective TinyGo/Go is still a better choice. + +3. Other languages do work well, but then you should be prepared for one or more side effects: + + - larger binaries + - poor(-er) performance + - unstable toolchains + - other surprises + +While experimentation is encouraged, production modules should prioritise simplicity +and predictability. + +SDKs and Helper Libraries +------------------------- + +Language-specific helper libraries and SDKs are expected to evolve as community +contributions. + +At present, the Wasm runtime operates in **spartan mode**: + +- minimal host API +- no language-specific abstractions +- explicit behavior over convenience + +This reduces maintenance cost and keeps runtime behavior transparent. + +Calling a Wasm module from a model +---------------------------------- + +Runtime-bound modules are not invoked directly at this moment. Instead, you reference the runtime module and +specify which submodule it should execute. + +Example action: + +.. code-block:: yaml + + call-hello: + descr: Call WASM/WASI module + module: runtime.wasm-runtime + bind: + - wasm + state: + $: + args: + rt.mod: hellodude + key: PRIVACY_POLICY_URL + +Here: + +- ``runtime.wasm-runtime`` selects the runtime. +- ``rt.mod`` identifies the Wasm module. +- Arguments with the ``rt.*`` prefix are reserved for runtime configuration. You can always get runtime manual with + directly calling the runtime module using ``--man`` argument. +- Arguments without the ``rt.*`` prefix are passed to the submodule "as is". + +.. note:: + + The exact syntax for runtime invocation may evolve in the future. A more + unified namespace (for example ``runtime.wasm.``) is planned, but + requires additional module typing and namespace changes. For now, the + explicit ``rt.mod`` approach is used. + +Mixed Runtime Example +--------------------- + +A single model can freely combine Wasm, Lua, and native Sysinspect modules. + +Example: + +.. code-block:: yaml + + entities: + - example + + actions: + call-spawner: + descr: Try spawner + module: runtime.wasm-runtime + bind: [example] + state: + $: + args: + rt.mod: caller + + get-os-version: + descr: Return OS version + module: runtime.lua-runtime + bind: [example] + state: + $: + opts: [rt.logs] + args: + rt.mod: reader + + ping: + descr: Information module + module: sys.run + bind: [example] + state: + $: + args: + cmd: "cat /etc/machine-id" + +This demonstrates that runtimes are **orthogonal**: each runtime handles its own +execution model, while Sysinspect orchestrates them uniformly when you call one ``example`` entity. + +Troubleshooting +--------------- + +- Confirm the runtime appears in ``sysinspect module -L``. +- Ensure the Wasm module was compiled for WASI. +- Verify the library directory was uploaded and synced. +- Do not distribute cached runtime artifacts. From 3c8a7594d7b43072838e6645d3d11f6f5a4ca99b Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:23:41 +0100 Subject: [PATCH 25/40] Update gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 57c69857..9cfced7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target +**/target/ docs/_build man/*8 package/ From 2dbf9de93c007b5ef560a6bd1fd7a5921c2d3808 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:23:54 +0100 Subject: [PATCH 26/40] Update WASI tutor --- docs/tutorial/wasm_modules_tutor.rst | 56 ++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/docs/tutorial/wasm_modules_tutor.rst b/docs/tutorial/wasm_modules_tutor.rst index 3f41a328..3da1aa1f 100644 --- a/docs/tutorial/wasm_modules_tutor.rst +++ b/docs/tutorial/wasm_modules_tutor.rst @@ -183,30 +183,54 @@ Language Support Any language capable of compiling to **WASI** can theoretically be used. -In practice: +In practice, Ssysinspect focuses on languages that produce **small**, **fast**, and +**predictable** Wasm binaries. There are two primary recommendations: -1. **TinyGo** is the recommended choice. It offers: +1. **TinyGo** is the recommended choice if you want it "in 10 minutes", **Rust** otherwise. TinyGo offers: - - small binaries - - predictable output - - good WASI support + - Relatively small binaries + - Predictable output + - Excellent WASI support + - One can learn Go in a few hours + - "Tons" of ready to use libraries - You can also use standard Go with ``GOOS=js GOARCH=wasm``, but TinyGo produces much smaller - and faster binaries. + .. important:: -2. Rust or C/C++ are also very well supported. But practically you most likely want -to be productive and make your module as fast as possible with as minimal overhead. -From this perspective TinyGo/Go is still a better choice. + You can also use standard Go with ``GOOS=js GOARCH=wasm``, but TinyGo produces much smaller + and faster binaries. -3. Other languages do work well, but then you should be prepared for one or more side effects: +2. **Rust** is your primary choice if you want maximum performance and control, but don't want it "in 10 minutes". **Rust** offers: - - larger binaries - - poor(-er) performance - - unstable toolchains - - other surprises + - **Smallest/fastest binaries** + - Excellent WASI support + - Very mature toolchain + - Excellent performance + - Memory safety + - Rich ecosystem + + .. note:: + + Although Rust makes many things "right", yet it has a way much steeper learning curve. Even if you've + mastered it enough, the development speed is not necessarily faster than with Go. + + At last, Configuration Management does not require systems programming skills and usually any + CM module code is typically a "glue boilerplate", that can be done with higher-level languages. + + But it is still fun. :-) + +C/C++ is also a solid choice, but you must take care of memory management and other low-level details yourself. +Other languages do *technically* work as well (Grain, Swift etc), but they aren't supported +in SysInspect realm. If you want to try them out, you should be prepared for one or more side effects: + + - Significantly larger binaries + - Poor(-er) performance + - Unstable toolchains + - Randomly missing WASI features + - Other bad surprises While experimentation is encouraged, production modules should prioritise simplicity -and predictability. +and predictability. In any case, if you find a language that works well, please share your experience +with the community. SDKs and Helper Libraries ------------------------- From 10ab539d9438dc5f2fcb3b3e27e95684981cf0ef Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:24:38 +0100 Subject: [PATCH 27/40] Add an example module in Rust --- .../examples/rs-reader/Cargo.lock | 106 ++++++++++++++++++ .../examples/rs-reader/Cargo.toml | 20 ++++ .../wasm-runtime/examples/rs-reader/Makefile | 63 +++++++++++ .../examples/rs-reader/README.txt | 23 ++++ .../examples/rs-reader/src/main.rs | 15 +++ 5 files changed, 227 insertions(+) create mode 100644 modules/runtime/wasm-runtime/examples/rs-reader/Cargo.lock create mode 100644 modules/runtime/wasm-runtime/examples/rs-reader/Cargo.toml create mode 100644 modules/runtime/wasm-runtime/examples/rs-reader/Makefile create mode 100644 modules/runtime/wasm-runtime/examples/rs-reader/README.txt create mode 100644 modules/runtime/wasm-runtime/examples/rs-reader/src/main.rs diff --git a/modules/runtime/wasm-runtime/examples/rs-reader/Cargo.lock b/modules/runtime/wasm-runtime/examples/rs-reader/Cargo.lock new file mode 100644 index 00000000..34d02f7a --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/rs-reader/Cargo.lock @@ -0,0 +1,106 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rs-reader" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "zmij" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" diff --git a/modules/runtime/wasm-runtime/examples/rs-reader/Cargo.toml b/modules/runtime/wasm-runtime/examples/rs-reader/Cargo.toml new file mode 100644 index 00000000..0a469e28 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/rs-reader/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "rs-reader" +version = "0.1.0" +edition = "2024" + +[dependencies] +serde = "1.0.228" +serde_json = "1.0.149" + +[workspace] + +[profile.release] +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" +strip = true +overflow-checks = false +debug = false +incremental = false diff --git a/modules/runtime/wasm-runtime/examples/rs-reader/Makefile b/modules/runtime/wasm-runtime/examples/rs-reader/Makefile new file mode 100644 index 00000000..ae23db64 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/rs-reader/Makefile @@ -0,0 +1,63 @@ +# Rust -> WASI Makefile +# Targets: +# make -> release +# make devel -> debug +# +# Result: +# target//lib/runtime/wasm/.wasm +# +# Install note: +# Add target//lib to sysinspect module path. + +BIN ?= rs-reader +WASI ?= wasm32-wasip1 +CARGO ?= cargo +WASM_OPT ?= wasm-opt + +PROFILE ?= release + +OUT_DIR := target/$(WASI)/$(PROFILE) +WASM_IN := $(OUT_DIR)/$(BIN).wasm +DEST_DIR := target/$(PROFILE)/lib/runtime/wasm +WASM_OUT := $(DEST_DIR)/$(BIN).wasm + +HAVE_WASM_OPT := $(shell command -v $(WASM_OPT) >/dev/null 2>&1 && echo yes) + +.PHONY: all devel build optimize copy info clean + +all: + @$(MAKE) PROFILE=release build optimize copy info + +devel: + @$(MAKE) PROFILE=debug build optimize copy info + +build: + @echo "==> Building $(BIN) ($(PROFILE))" + @$(CARGO) build $(if $(filter release,$(PROFILE)),--release,) --target $(WASI) + +optimize: +ifeq ($(HAVE_WASM_OPT),yes) + @echo "==> Optimizing with wasm-opt" + @$(WASM_OPT) -Oz --all-features $(WASM_IN) -o $(WASM_IN).opt + @mv $(WASM_IN).opt $(WASM_IN) +else + @echo "==> wasm-opt not found, skipping optimisation" +endif + +copy: + @echo "==> Installing WASM to $(DEST_DIR)" + @mkdir -p $(DEST_DIR) + @cp $(WASM_IN) $(WASM_OUT) + +info: + @echo "" + @echo "WASM ready:" + @echo " $(WASM_OUT)" + @echo "" + @echo "To use with SysInspect:" + @echo " add './lib' from:" + @echo " target/$(PROFILE)/lib" + @echo "" + +clean: + @$(CARGO) clean diff --git a/modules/runtime/wasm-runtime/examples/rs-reader/README.txt b/modules/runtime/wasm-runtime/examples/rs-reader/README.txt new file mode 100644 index 00000000..234bcb89 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/rs-reader/README.txt @@ -0,0 +1,23 @@ +0. Ensure you have "wasm-opt" from Binaryen: + + apt install binaryen + + +1. Build it: + + make + + +2. From here, go to target/release and add "./lib" with the sysinspect: + + cd target/release + sysinspect module -Alp ./lib + + +3. Refresh your cluster: + + sysinspect --sync + + + +Done. diff --git a/modules/runtime/wasm-runtime/examples/rs-reader/src/main.rs b/modules/runtime/wasm-runtime/examples/rs-reader/src/main.rs new file mode 100644 index 00000000..32894f25 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/rs-reader/src/main.rs @@ -0,0 +1,15 @@ +use serde_json::json; +use std::fs; + +fn main() { + let path = "/etc/machine-id"; + match fs::read_to_string(path) { + Ok(contents) => { + let id = contents.trim().to_string(); + println!("{}", json!({ "minion_id": id }).to_string()); + } + Err(_) => { + println!("{}", json!({ "error": "Could not read machine-id file" }).to_string()); + } + } +} From a120f8436237ea574a93fed9d91c0367fcc25b9d Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:26:20 +0100 Subject: [PATCH 28/40] Add reader example in Go --- .../wasm-runtime/examples/reader/README.txt | 1 + .../wasm-runtime/examples/reader/reader.go | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 modules/runtime/wasm-runtime/examples/reader/README.txt create mode 100644 modules/runtime/wasm-runtime/examples/reader/reader.go diff --git a/modules/runtime/wasm-runtime/examples/reader/README.txt b/modules/runtime/wasm-runtime/examples/reader/README.txt new file mode 100644 index 00000000..c39f1750 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/reader/README.txt @@ -0,0 +1 @@ +Compile this just like "caller" example. diff --git a/modules/runtime/wasm-runtime/examples/reader/reader.go b/modules/runtime/wasm-runtime/examples/reader/reader.go new file mode 100644 index 00000000..35af7c8b --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/reader/reader.go @@ -0,0 +1,26 @@ +// main.go +package main + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +func main() { + b, err := os.ReadFile("/etc/machine-id") + if err != nil { + out, _ := json.Marshal(map[string]string{ + "error": "failed to read /etc/machine-id", + }) + fmt.Println(string(out)) + return + } + + id := strings.TrimSpace(string(b)) + out, _ := json.Marshal(map[string]string{ + "machine_id": id, + }) + fmt.Println(string(out)) +} From 0b9b48270a4250ec51602f33dcbac358f0e2844d Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:53:50 +0100 Subject: [PATCH 29/40] Update docs/tutorial/wasm_modules_tutor.rst Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/tutorial/wasm_modules_tutor.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/wasm_modules_tutor.rst b/docs/tutorial/wasm_modules_tutor.rst index 3da1aa1f..b532daec 100644 --- a/docs/tutorial/wasm_modules_tutor.rst +++ b/docs/tutorial/wasm_modules_tutor.rst @@ -183,7 +183,7 @@ Language Support Any language capable of compiling to **WASI** can theoretically be used. -In practice, Ssysinspect focuses on languages that produce **small**, **fast**, and +In practice, Sysinspect focuses on languages that produce **small**, **fast**, and **predictable** Wasm binaries. There are two primary recommendations: 1. **TinyGo** is the recommended choice if you want it "in 10 minutes", **Rust** otherwise. TinyGo offers: From 43fc86921a34947e04d0999b60d93bb4ba099627 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:54:13 +0100 Subject: [PATCH 30/40] Update modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../wasm-runtime/examples/caller/sysinspect/sysinspect.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go index c0bd27b3..8b7930d2 100644 --- a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go +++ b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go @@ -1,4 +1,4 @@ -// Package log provides a way to run system inspection commands +// Package api provides a way to run system inspection commands // on the host system from within a WebAssembly module. package api From ec6122f40c9d2deedd635583803aea73e7350a68 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 20:54:36 +0100 Subject: [PATCH 31/40] Update modules/runtime/wasm-runtime/examples/caller/Makefile Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- modules/runtime/wasm-runtime/examples/caller/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/runtime/wasm-runtime/examples/caller/Makefile b/modules/runtime/wasm-runtime/examples/caller/Makefile index 7b610620..72a30fbb 100644 --- a/modules/runtime/wasm-runtime/examples/caller/Makefile +++ b/modules/runtime/wasm-runtime/examples/caller/Makefile @@ -76,7 +76,7 @@ release: clean run: @echo "Running module (test preview)..." - @echo '{"config": {"path.sharelib": "${PWD}/build"}, "args": {"rt.mod": "hellodude"}}' | ../../../../../target/debug/runtime/wasm-runtime | jq + @echo '{"config": {"path.sharelib": "${PWD}/build"}, "args": {"rt.mod": "caller"}}' | ../../../../../target/debug/runtime/wasm-runtime | jq clean: From 6df1b86e781a41daa5856d94e18bc9d32929f843 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 21:30:42 +0100 Subject: [PATCH 32/40] Implement mod lister --- libmodcore/src/runtime.rs | 2 +- modules/runtime/wasm-runtime/src/main.rs | 30 ++++++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/libmodcore/src/runtime.rs b/libmodcore/src/runtime.rs index 72b56a0d..f0799759 100644 --- a/libmodcore/src/runtime.rs +++ b/libmodcore/src/runtime.rs @@ -47,7 +47,7 @@ impl From for serde_json::Value { } /// Struct to call plugin parameters -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct ModRequest { /// Timeout of the module running. /// If timeout is exceeded, module quits. diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs index 3fe1b87b..874047e6 100644 --- a/modules/runtime/wasm-runtime/src/main.rs +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -1,6 +1,7 @@ mod wart; use clap::Parser; +use colored::Colorize; use libmodcore::{ init_mod_doc, manrndr::print_mod_manual, @@ -14,8 +15,27 @@ use serde_json::{Value, json}; use std::path::{Path, PathBuf}; /// List available Wasm modules in the scripts directory -fn list_wasm_modules(_wasm_dir: &Path) -> Vec { - Vec::new() +fn list_wasm_modules(wasm_dir: &Path) { + let rt = match wart::WasmRuntime::new(&ModRequest::default()) { + Err(err) => { + println!("Failed to initialize Wasm runtime: {err}"); + return; + } + Ok(rt) => rt, + }; + let mut mods = match rt.get_wasm_modules() { + Ok(mods) => mods, + Err(_) => { + println!("Failed to list Wasm modules in {}", wasm_dir.display()); + return; + } + }; + mods.sort(); + + println!("Available Wasm/WASI modules:"); + for (i, m) in mods.iter().enumerate() { + println!(" {}. {}", i + 1, m.bright_green()); + } } /// Get module documentation from Wasm runtime @@ -34,7 +54,6 @@ fn call_runtime(_cli: &ModuleCli, rq: &ModRequest) -> ModResponse { } Ok(rt) => rt, }; - rt.run() } @@ -59,10 +78,7 @@ fn main() { } return; } else if cli.is_list_modules() { - println!("Available Wasm runtime modules:"); - for module in list_wasm_modules(PathBuf::from(cli.get_sharelib()).as_path()) { - println!(" - {}", module); - } + list_wasm_modules(PathBuf::from(cli.get_sharelib()).as_path()); return; } From c7f8d3e9e0453b1ddab689e1f7ea4c0fc9837f40 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 21:30:53 +0100 Subject: [PATCH 33/40] Enable log forwarding --- modules/runtime/wasm-runtime/src/wart.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/runtime/wasm-runtime/src/wart.rs b/modules/runtime/wasm-runtime/src/wart.rs index d2c231da..8e75094e 100644 --- a/modules/runtime/wasm-runtime/src/wart.rs +++ b/modules/runtime/wasm-runtime/src/wart.rs @@ -1,9 +1,5 @@ use futures::executor; -use libmodcore::{ - response::ModResponse, - rtspec::RuntimeSpec, - runtime::ModRequest, -}; +use libmodcore::{response::ModResponse, rtspec::RuntimeSpec, runtime::ModRequest}; use libsysinspect::SysinspectError; use serde_json::Value; use wasmruntime::cfg::WasmConfig; @@ -72,7 +68,7 @@ impl WasmRuntime { Ok(wcfg) } - fn get_wasm_modules(&self) -> Result, SysinspectError> { + pub fn get_wasm_modules(&self) -> Result, SysinspectError> { let mods: Vec = match self.rt.objects() { Err(err) => { return Err(SysinspectError::ConfigError(format!("Failed to list userlets: {err}"))); @@ -119,9 +115,10 @@ impl WasmRuntime { }; if let Value::Object(ref mut map) = out - && let Some(v) = map.remove("__module-logs") { - map.insert(RuntimeSpec::LogsSectionField.to_string(), v); - } + && let Some(v) = map.remove("__module-logs") + { + map.insert(RuntimeSpec::LogsSectionField.to_string(), v); + } r.set_message("Wasm runtime executed successfully"); r.set_retcode(0); From bfe2c674b3476f8059dfe173fff12fe069641f35 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Tue, 27 Jan 2026 22:04:02 +0100 Subject: [PATCH 34/40] Cleanup, add module help render --- modules/runtime/wasm-runtime/src/main.rs | 21 +++++---------------- modules/runtime/wasm-runtime/src/wart.rs | 1 - 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs index 874047e6..68b092b3 100644 --- a/modules/runtime/wasm-runtime/src/main.rs +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -10,8 +10,7 @@ use libmodcore::{ response::ModResponse, runtime::{ModRequest, get_call_args, send_call_response}, }; -use libsysinspect::SysinspectError; -use serde_json::{Value, json}; +use serde_json::Value; use std::path::{Path, PathBuf}; /// List available Wasm modules in the scripts directory @@ -38,11 +37,6 @@ fn list_wasm_modules(wasm_dir: &Path) { } } -/// Get module documentation from Wasm runtime -fn module_doc_help(_cli: &ModuleCli, _modname: &str) -> Result { - Ok(json!({})) -} - /// Run the Wasm runtime with the provided request. fn call_runtime(_cli: &ModuleCli, rq: &ModRequest) -> ModResponse { let mut r = ModResponse::new_cm(); @@ -67,15 +61,10 @@ fn main() { print!("{}", mod_doc.help()); return; } else if !cli.get_help_on().is_empty() { - match get_call_args() { - Ok(mut rq) => { - rq.add_opt("man"); - rq.add_arg("man", Value::Bool(true)); - let mr = &call_runtime(&cli, &rq); - print_mod_manual(mr.get_data()); - } - Err(err) => println!("Arguments error: {err}"), - } + let mut rq = ModRequest::default(); + rq.add_opt("man"); + rq.add_arg("rt.mod", Value::String(cli.get_help_on())); + print_mod_manual(call_runtime(&cli, &rq).get_data()); return; } else if cli.is_list_modules() { list_wasm_modules(PathBuf::from(cli.get_sharelib()).as_path()); diff --git a/modules/runtime/wasm-runtime/src/wart.rs b/modules/runtime/wasm-runtime/src/wart.rs index 8e75094e..fd03e6c8 100644 --- a/modules/runtime/wasm-runtime/src/wart.rs +++ b/modules/runtime/wasm-runtime/src/wart.rs @@ -80,7 +80,6 @@ impl WasmRuntime { pub fn run(&self) -> ModResponse { let mut r = ModResponse::new_cm(); - // Get Wasm modules let wmod = match self.get_wasm_modules() { Err(err) => { From 74a2c87717c33b30435898c1230d6ac4b5f8209e Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 28 Jan 2026 00:15:35 +0100 Subject: [PATCH 35/40] Update modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../wasm-runtime/examples/caller/sysinspect/sysinspect.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go index 8b7930d2..3cc375f4 100644 --- a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go +++ b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go @@ -42,8 +42,13 @@ func (c *Cmd) Output() (string, error) { out := make([]byte, 256*1024) // a buffer for host response + var reqPtr uint32 + if len(reqb) > 0 { + reqPtr = uint32(uintptr(unsafe.Pointer(&reqb[0]))) + } + n := __execJSON( - uint32(uintptr(unsafe.Pointer(&reqb[0]))), + reqPtr, uint32(len(reqb)), uint32(uintptr(unsafe.Pointer(&out[0]))), uint32(len(out)), From 55a37b278116ab64dd7fa3459e08e86f4adf9132 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 28 Jan 2026 00:15:57 +0100 Subject: [PATCH 36/40] Update modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../wasm-runtime/examples/caller/sysinspect/sysinspect.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go index 3cc375f4..b92f7f6d 100644 --- a/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go +++ b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go @@ -86,6 +86,9 @@ func Log(level int32, format string, args ...any) { return } b := []byte(msg) + if len(b) == 0 { + return + } __hostLog( level, uint32(uintptr(unsafe.Pointer(&b[0]))), From 47c0c5f94696e537b01bc0c74d4018cb255938e6 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 28 Jan 2026 00:17:01 +0100 Subject: [PATCH 37/40] Update docs/tutorial/wasm_modules_tutor.rst Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/tutorial/wasm_modules_tutor.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/wasm_modules_tutor.rst b/docs/tutorial/wasm_modules_tutor.rst index b532daec..7eeea1fd 100644 --- a/docs/tutorial/wasm_modules_tutor.rst +++ b/docs/tutorial/wasm_modules_tutor.rst @@ -196,7 +196,7 @@ In practice, Sysinspect focuses on languages that produce **small**, **fast**, a .. important:: - You can also use standard Go with ``GOOS=js GOARCH=wasm``, but TinyGo produces much smaller + You can also use standard Go with ``GOOS=wasip1 GOARCH=wasm``, but TinyGo produces much smaller and faster binaries. 2. **Rust** is your primary choice if you want maximum performance and control, but don't want it "in 10 minutes". **Rust** offers: From e97dae2e5e1896795133653192fa51806ca97fd1 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 28 Jan 2026 00:18:11 +0100 Subject: [PATCH 38/40] Use error reason for better info --- modules/runtime/wasm-runtime/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs index 68b092b3..a75f1945 100644 --- a/modules/runtime/wasm-runtime/src/main.rs +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -24,8 +24,8 @@ fn list_wasm_modules(wasm_dir: &Path) { }; let mut mods = match rt.get_wasm_modules() { Ok(mods) => mods, - Err(_) => { - println!("Failed to list Wasm modules in {}", wasm_dir.display()); + Err(err) => { + println!("Failed to list Wasm modules in {}: {err}", wasm_dir.display()); return; } }; From 0ed4511c25e94a47bc50274d200e89577c393c90 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 28 Jan 2026 00:19:29 +0100 Subject: [PATCH 39/40] Mute params that aren't yet implemented --- modules/runtime/wasm-runtime/src/mod_doc.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/runtime/wasm-runtime/src/mod_doc.yaml b/modules/runtime/wasm-runtime/src/mod_doc.yaml index c7da6af1..2c14ff80 100644 --- a/modules/runtime/wasm-runtime/src/mod_doc.yaml +++ b/modules/runtime/wasm-runtime/src/mod_doc.yaml @@ -4,15 +4,15 @@ author: "Bo Maryniuk" description: Wasm runtime module. # Options, flags, switches -options: - - name: rt.list - description: "List of available Wasm scripts, ready to be called as modules." - - - name: rt.logs - description: "Enable logging from Wasm scripts to SysInspect logs." - - - name: rt.sandbox - description: "Run Wasm binaries in sandboxed environment." +# options: +# - name: rt.list +# description: "List of available Wasm scripts, ready to be called as modules." +# +# - name: rt.logs +# description: "Enable logging from Wasm scripts to SysInspect logs." +# +# - name: rt.sandbox +# description: "Run Wasm binaries in sandboxed environment." # Keyword arguments arguments: From 2704dfea0352bb996f1463fd43a9e2394f2afa78 Mon Sep 17 00:00:00 2001 From: Bo Maryniuk Date: Wed, 28 Jan 2026 00:42:41 +0100 Subject: [PATCH 40/40] Return accidentally forgotten "options" which renders the whole RT broken --- modules/runtime/wasm-runtime/src/mod_doc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/runtime/wasm-runtime/src/mod_doc.yaml b/modules/runtime/wasm-runtime/src/mod_doc.yaml index 2c14ff80..e3ce34fc 100644 --- a/modules/runtime/wasm-runtime/src/mod_doc.yaml +++ b/modules/runtime/wasm-runtime/src/mod_doc.yaml @@ -4,7 +4,7 @@ author: "Bo Maryniuk" description: Wasm runtime module. # Options, flags, switches -# options: +options: # - name: rt.list # description: "List of available Wasm scripts, ready to be called as modules." #