diff --git a/.gitignore b/.gitignore index d5a37b9f..9cfced7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/target +**/target/ docs/_build man/*8 package/ @@ -10,3 +10,4 @@ package/ /*/.bin/ /*/html-docs .gitignore +**/build/ diff --git a/Cargo.lock b/Cargo.lock index 1cd0b5d3..65c62d98 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", @@ -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" @@ -329,9 +344,9 @@ 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", ] @@ -482,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", @@ -493,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", @@ -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" @@ -811,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", @@ -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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57cc4ac031157d0206cf6a8faa48284034721cd367a45e004c4e06329f51e106" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a121c08faeeca04c85280dbddb19521e3ed7169430fd6abc34496e656c18b20" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39f2b2cd8224147b4e193c2de68cf0085b693b242bb766c594828db3907151cb" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7468865d7cf72637a30d5fb97c4fc38b6ea82ab54ca913c81e7403274802be" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96c94a373ec1a35fb889730525f3fd220e66b1cf222b3426f5eb6e0404718e5" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5904cbc4e8d4f8a69129a365da30d6f9f0e6ca024c4e0728d5da615e8db3c44" +dependencies = [ + "cranelift-assembler-x64-meta", + "cranelift-codegen-shared", + "cranelift-srcgen", + "heck", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1009f9e206d5fba4add039539f3e16378815a53b8477bd2d1fc8e3bde6ea93a" + +[[package]] +name = "cranelift-control" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c5e3cc40402febecdba0a9e45999b1ab9aef8b120833182b08830b7be292fb" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58a1de9bdab836734c42902ce948a5cdcc923ae8ce30b29a24dbe76098df659" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3423b326097e627a378c106eb57d5ddb3f303d4deb87d29bf8b982dd1d6afc" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56f0e7abec391b94314ab2e9a1002c5a0aed6e29e4709318a7e33315767bed7" + +[[package]] +name = "cranelift-native" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e528d9c791306c55c3bef6c70a77cc9712ca9a32b12bae86924224e65604cb69" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.123.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8558dda6bd86b48c7b31b46555b5eed24b55c839e554a42765c23bf98de62997" + [[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" @@ -1494,7 +1765,7 @@ checksum = "6e39034cee21a2f5bbb66ba0e3689819c4bb5d00382a282006e802a7ffa6c41d" dependencies = [ "cfg-if", "libc", - "socket2 0.6.1", + "socket2 0.6.2", "windows-sys 0.60.2", ] @@ -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" @@ -1935,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", @@ -1946,13 +2253,14 @@ 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", "hashbrown 0.16.1", + "ordermap", "smallvec", ] @@ -2000,6 +2308,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 +2436,7 @@ dependencies = [ "allocator-api2", "equivalent", "foldhash 0.1.5", + "serde", ] [[package]] @@ -2346,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", @@ -2389,7 +2709,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.58.0", + "windows-core 0.62.2", ] [[package]] @@ -2482,6 +2802,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 +2950,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 +3065,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 +3215,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" @@ -2955,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" @@ -3282,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", @@ -3320,6 +3694,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 +3792,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 +3814,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" @@ -3533,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", ] @@ -3704,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" @@ -3789,10 +4187,13 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ + "crc32fast", + "hashbrown 0.15.5", + "indexmap 2.13.0", "memchr", ] @@ -3851,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" @@ -3982,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" @@ -4381,6 +4791,18 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.4" @@ -4462,7 +4884,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]] @@ -4478,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", ] @@ -4589,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", @@ -4617,6 +5039,29 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulley-interpreter" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56a1abe1fcec21c32b62000af24b8b6db11b87609b64fd1c9a9e17c42422225" +dependencies = [ + "cranelift-bitset", + "log", + "pulley-macros", + "wasmtime-internal-math", +] + +[[package]] +name = "pulley-macros" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d56dac306fbee0e990d4bac359c86d58f60f058e1e2d1aee1b7928689f08d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "pure-rust-locales" version = "0.8.2" @@ -4639,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", ] @@ -4903,6 +5348,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" @@ -5109,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", @@ -5128,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", @@ -5148,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", @@ -5159,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", @@ -5168,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", ] @@ -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" @@ -5326,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", @@ -5392,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "cfg-if", "dirs-next", @@ -5412,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ahash 0.8.12", "bitflags 2.10.0", @@ -5435,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ascii", "bitflags 2.10.0", @@ -5464,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ruff_python_ast", "ruff_python_parser", @@ -5478,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "bitflags 2.10.0", "itertools 0.14.0", @@ -5492,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "rustpython-compiler", "rustpython-derive-impl", @@ -5502,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "itertools 0.14.0", "maplit", @@ -5518,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "phf 0.13.1", ] @@ -5526,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "hexf-parse", "is-macro", @@ -5539,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "glob", "rustpython-compiler-core", @@ -5549,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "bitflags 2.10.0", "num_enum", @@ -5560,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "adler32", "ahash 0.8.12", @@ -5618,7 +6092,7 @@ dependencies = [ "sha-1", "sha2", "sha3", - "socket2 0.6.1", + "socket2 0.6.2", "system-configuration 0.7.0", "termios", "ucd", @@ -5644,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ahash 0.8.12", "ascii", @@ -5717,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#edca32a194619b5872602d7afc91d6fc3f14232f" dependencies = [ "ascii", "bstr", @@ -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" @@ -6229,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", @@ -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" @@ -6743,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", @@ -6760,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", @@ -6838,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", ] @@ -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" @@ -7524,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", @@ -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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0ffc257572bd9d2dc138726c96504100b04b33ddf226dfbf3b7f90c2fca835c" +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,440 @@ 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" +source = "git+https://github.com/isbm/wasmruntime.git#9723eefb6dc256b82815c1c2420c747929ade4b7" +dependencies = [ + "anyhow", + "chrono", + "serde", + "serde_json", + "tokio", + "wasi-common", + "wasmtime", + "wasmtime-wasi", +] + +[[package]] +name = "wasmtime" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901adbcfe03e3ad9db86f5665d6e00d54c904d4b81235c375635991596dfef3b" +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", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00984333e84fa259b72b5bc113e1699d04f20c3ac191bf3e268e32bd93e493fd" +dependencies = [ + "anyhow", + "cpp_demangle", + "cranelift-bitset", + "cranelift-entity", + "gimli", + "indexmap 2.13.0", + "log", + "object", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f42078a2603132bb5d7f2d5114ce57992e0fa344a9521385dc159c63472a9a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-internal-cache" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ae7355594563bec11af97afb429ea8576f497960a78d59684ffabd11a862b8" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c271bbe00cf374564ee37bee4fe298f8ad10e267aba07b2ec598d376677f062" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61fa3310d28256440f4bad63bd9462f364ee9faca7c3dcfccc7c2a48db46005" + +[[package]] +name = "wasmtime-internal-cranelift" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6401e096bfbb50e75a00bd83162fee68b1800d65937364463a4ad43da3f140f8" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "gimli", + "itertools 0.14.0", + "log", + "object", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd592465c4fffd866fc6f50db2cc7ae0c73d2742699e351b3680b5f84f21ede" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6c60a180c90eea53266a6627c353a8101090f1e084f59e1bd4666f5c55e405" +dependencies = [ + "cc", + "object", + "rustix 1.1.3", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-jit-icache-coherence" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe8de0903b246b59b112f2a7116f3d2315c41a9252ab78de90dae93b9cab50e" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-internal-math" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d143a7388e4adfae7c1d6c6ceb44325b4b45b2e393e39b25ddaf563e7e587" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmtime-internal-slab" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de954a96e144df5b22805367f91a1754237f6bf99918f087d0ea1970be3b6365" + +[[package]] +name = "wasmtime-internal-unwinder" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9923ac3d2b967e8ecbfefddaf19909b6a9a03b5b969b2a71af52300e3e404419" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "log", + "object", +] + +[[package]] +name = "wasmtime-internal-versioned-export-macros" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2c0062b75377b8d0a20239436b06df2e01a3521e9f14af6ea9b438c60fc030" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "wasmtime-internal-winch" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8542e7cfd5b77ad33ac4cab866cb2b2eca350c7c34ac73e13fe78e83871ad3d7" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "object", + "target-lexicon", + "wasmparser 0.236.1", + "wasmtime-environ", + "wasmtime-internal-cranelift", + "winch-codegen", +] + +[[package]] +name = "wasmtime-internal-wit-bindgen" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c8be7f99d674c7af47ceba83ee4dc4e36132798c920a7bfd7ca44ce7733f99" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "heck", + "indexmap 2.13.0", + "wit-parser", +] + +[[package]] +name = "wasmtime-wasi" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "001ee40c4a289579b0ef3c72cad1396a372dfb535b7b542ca4f7cb68d0566009" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69017e34b0285e3bce3add58b2895aded308400e5ad37ad4f670b0f9127d88f" +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 +8722,47 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" +[[package]] +name = "wiggle" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d63a4f105596bfd9378d1f80659d01045f3ac803c4a1fab13ffe10e8d63227d" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.10.0", + "thiserror 2.0.18", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c686a505d73cfd3508be4c92a51b7b3fac2268879c3bbb6bc98e37885fca8eb3" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd3ac0e3ab2375cd9f439a4653fa714ca66798b1c8a3138db6ac752c600c77b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", + "wiggle-generate", +] + [[package]] name = "winapi" version = "0.3.9" @@ -7732,6 +8794,26 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winch-codegen" +version = "36.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce0c15cfd084585ed8f5519d4f405de98ff530f6afe31b88a5560688879c85e" +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" @@ -7777,6 +8859,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" @@ -7799,6 +8894,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" @@ -7821,6 +8927,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" @@ -8126,11 +9243,11 @@ 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", + "toml 0.9.11+spec-1.1.0", "version_check", ] @@ -8140,12 +9257,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" @@ -8232,18 +9389,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", @@ -8346,9 +9503,9 @@ checksum = "40990edd51aae2c2b6907af74ffb635029d5788228222c4bb811e9351c0caad3" [[package]] name = "zmij" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" [[package]] name = "zopfli" diff --git a/Makefile b/Makefile index 5a047766..bf528c1b 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,8 @@ 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 setup: 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..7eeea1fd --- /dev/null +++ b/docs/tutorial/wasm_modules_tutor.rst @@ -0,0 +1,335 @@ +.. _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, 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: + + - Relatively small binaries + - Predictable output + - Excellent WASI support + - One can learn Go in a few hours + - "Tons" of ready to use libraries + + .. important:: + + 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: + + - **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. In any case, if you find a language that works well, please share your experience +with the community. + +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. 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/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 8c581808..f0799759 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,8 +40,14 @@ impl ArgValue { } } +impl From for serde_json::Value { + fn from(val: ArgValue) -> Self { + val.0 + } +} + /// Struct to call plugin parameters -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct ModRequest { /// Timeout of the module running. /// If timeout is exceeded, module quits. @@ -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 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 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/Cargo.toml b/modules/runtime/wasm-runtime/Cargo.toml new file mode 100644 index 00000000..137263a8 --- /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/examples/caller/Makefile b/modules/runtime/wasm-runtime/examples/caller/Makefile new file mode 100644 index 00000000..72a30fbb --- /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": "caller"}}' | ../../../../../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..ac3246e9 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/caller/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + + api "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 := 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") +} 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..b92f7f6d --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/caller/sysinspect/sysinspect.go @@ -0,0 +1,97 @@ +// Package api provides a way to run system inspection commands +// on the host system from within a WebAssembly module. +package api + +import ( + "encoding/json" + "fmt" + "unsafe" +) + +//go:wasmimport api exec +func __execJSON(reqPtr, reqLen, outPtr, outCap uint32) int32 + +//go:wasmimport api log +func __hostLog(level int32, msgPtr, msgLen uint32) + +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 + + var reqPtr uint32 + if len(reqb) > 0 { + reqPtr = uint32(uintptr(unsafe.Pointer(&reqb[0]))) + } + + n := __execJSON( + reqPtr, + 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 +} + +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) + if len(b) == 0 { + return + } + __hostLog( + level, + uint32(uintptr(unsafe.Pointer(&b[0]))), + uint32(len(b)), + ) +} diff --git a/modules/runtime/wasm-runtime/examples/hello/Makefile b/modules/runtime/wasm-runtime/examples/hello/Makefile new file mode 100644 index 00000000..4527672c --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/hello/Makefile @@ -0,0 +1,84 @@ +MODULE := hellodude +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/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..d7b795f7 --- /dev/null +++ b/modules/runtime/wasm-runtime/examples/hello/main.go @@ -0,0 +1,182 @@ +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 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) + + 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 +} + +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 +} + +// 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 { + 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{ + 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{ + map[string]any{ + "name": "nohello", + "description": "Do not say hello", + }, + }, + + "examples": []any{ + map[string]any{ + "description": "Get module output", + "code": `{ "args": { "key": "VERSION" } }`, + }, + map[string]any{ + "description": "Get module documentation", + "code": `{ "args": { "key": "VERSION" }, "opts": ["man"] }`, + }, + }, + + "returns": map[string]any{ + "description": "Returns greeting and OS release info (if accessible).", + "sample": map[string]any{ + "output": "hello, dude", + "os": map[string]any{ + "PRETTY_NAME": "Debian GNU/Linux 12 (bookworm)", + "VERSION_ID": "12", + }, + }, + }, + } +} + +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(), + } + } + + 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() { + hdr, err := readHeader() + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetEscapeHTML(false) + + if hasOpt(hdr.Opts, "man") { + _ = enc.Encode(doc()) + } else { + _ = enc.Encode(run(hdr)) + } +} 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)) +} 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()); + } + } +} diff --git a/modules/runtime/wasm-runtime/src/main.rs b/modules/runtime/wasm-runtime/src/main.rs new file mode 100644 index 00000000..a75f1945 --- /dev/null +++ b/modules/runtime/wasm-runtime/src/main.rs @@ -0,0 +1,82 @@ +mod wart; + +use clap::Parser; +use colored::Colorize; +use libmodcore::{ + init_mod_doc, + manrndr::print_mod_manual, + modcli::ModuleCli, + modinit::ModInterface, + response::ModResponse, + runtime::{ModRequest, get_call_args, send_call_response}, +}; +use serde_json::Value; +use std::path::{Path, PathBuf}; + +/// List available Wasm modules in the scripts directory +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(err) => { + println!("Failed to list Wasm modules in {}: {err}", wasm_dir.display()); + return; + } + }; + mods.sort(); + + println!("Available Wasm/WASI modules:"); + for (i, m) in mods.iter().enumerate() { + println!(" {}. {}", i + 1, m.bright_green()); + } +} + +/// Run the Wasm runtime with the provided request. +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, + }; + + rt.run() +} + +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() { + 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()); + 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..e3ce34fc --- /dev/null +++ b/modules/runtime/wasm-runtime/src/mod_doc.yaml @@ -0,0 +1,72 @@ +name: "runtime.wasm" +version: "0.1.0" +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." + +# Keyword arguments +arguments: + - name: rt.mod + type: string + required: true + 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 Wasm binary being executed. These arguments will be available within the Wasm binary + as global variables. + +examples: + - description: "Call a Wasm binary named 'hello_world.wasm' 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 Wasm binary successfully." + data: + changed: false + +manpage: | + 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 + 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] + diff --git a/modules/runtime/wasm-runtime/src/wart.rs b/modules/runtime/wasm-runtime/src/wart.rs new file mode 100644 index 00000000..fd03e6c8 --- /dev/null +++ b/modules/runtime/wasm-runtime/src/wart.rs @@ -0,0 +1,132 @@ +use futures::executor; +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 +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("/"); + 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); + 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) + } + + 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}"))); + } + 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 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(), + 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); + return r; + } + 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) { + r.set_message(&format!("Failed to set response data: {err}")); + r.set_retcode(6); + return r; + } + + r + } +} 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() { 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"