diff --git a/.cargo/audit.toml b/.cargo/audit.toml index 967c3f7149..27a65ba908 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -31,4 +31,10 @@ ignore = [ "RUSTSEC-2025-0100", # gio-sys unmaintained "RUSTSEC-2026-0002", # serde_cbor unmaintained "RUSTSEC-2023-0086", # lexopt unmaintained (if present) + "RUSTSEC-2025-0134", # Transitive dependency + "RUSTSEC-2026-0049", # rustls-webpki CRL issue — wasmtime-43 did not resolve it + "RUSTSEC-2026-0097", # Transitive dependency + "RUSTSEC-2026-0098", # Transitive dependency + "RUSTSEC-2026-0099", # Transitive dependency + "RUSTSEC-2026-0104", # rustls-webpki 0.102.8/0.103.10 CRL panic + gimli yanked ] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f20467766f..2d3650db1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,29 +2,28 @@ name: CI on: push: - branches: [main] + branches: [main, 'release/*', 'fix/*', 'feat/*', 'chore/*'] pull_request: - branches: [main] + branches: [main, 'release/*', 'fix/*', 'feat/*', 'chore/*'] env: CARGO_TERM_COLOR: always RUSTFLAGS: "-D warnings" jobs: - # ── Rust library crates (all 3 platforms) ────────────────────────────────── - check: - name: Check / ${{ matrix.os }} + build: + name: Build / ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: - key: check-${{ matrix.os }} + key: ci-${{ matrix.os }} - name: Install Tauri system deps (Linux) if: runner.os == 'Linux' run: | @@ -40,16 +39,17 @@ jobs: test: name: Test / ${{ matrix.os }} runs-on: ${{ matrix.os }} + timeout-minutes: 60 strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 with: - key: test-${{ matrix.os }} + key: ci-${{ matrix.os }} - name: Install Tauri system deps (Linux) if: runner.os == 'Linux' run: | @@ -61,17 +61,20 @@ jobs: librsvg2-dev \ patchelf # Tests that need a display (Tauri) are skipped in headless CI via cfg - - run: cargo test --workspace + # Run unit tests only in CI (skip integration tests in tests/ directory) + - run: cargo test --workspace --lib -- --test-threads=2 clippy: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: clippy - uses: Swatinem/rust-cache@v2 + with: + key: ci-ubuntu-latest - name: Install Tauri system deps run: | sudo apt-get update @@ -87,19 +90,24 @@ jobs: name: Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt + - uses: Swatinem/rust-cache@v2 + with: + key: ci-ubuntu-latest - run: cargo fmt --check audit: name: Security Audit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + with: + key: ci-ubuntu-latest - name: Install cargo-audit run: cargo install cargo-audit --locked - run: cargo audit @@ -109,7 +117,7 @@ jobs: name: Secrets Scan runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install trufflehog diff --git a/Cargo.lock b/Cargo.lock index 2ca1a27262..5546cb69dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,7 +139,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -150,7 +150,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -893,7 +893,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -969,6 +969,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -992,7 +1002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", "libc", @@ -1005,7 +1015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "libc", ] @@ -1555,7 +1565,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1805,7 +1815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1895,12 +1905,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - [[package]] name = "flate2" version = "1.1.9" @@ -2718,10 +2722,10 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls", + "rustls 0.23.37", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tower-service", "webpki-roots", ] @@ -2743,7 +2747,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.3", "tokio", "tower-service", "tracing", @@ -3273,10 +3277,10 @@ dependencies = [ "nom 8.0.0", "percent-encoding", "quoted_printable", - "rustls", + "rustls 0.23.37", "socket2 0.6.3", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "url", "webpki-roots", ] @@ -3631,10 +3635,10 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.2.1", "openssl-sys", "schannel", - "security-framework", + "security-framework 3.7.0", "security-framework-sys", "tempfile", ] @@ -3739,7 +3743,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4162,7 +4166,7 @@ dependencies = [ "openfang-wire", "rand 0.8.5", "reqwest 0.12.28", - "rustls", + "rustls 0.23.37", "serde", "serde_json", "subtle", @@ -4343,6 +4347,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + [[package]] name = "openssl-probe" version = "0.2.1" @@ -4394,7 +4404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys 0.61.2", ] [[package]] @@ -4543,7 +4553,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "fixedbitset 0.4.2", + "fixedbitset", "indexmap 2.13.0", ] @@ -5099,8 +5109,8 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", - "socket2 0.5.10", + "rustls 0.23.37", + "socket2 0.6.3", "thiserror 2.0.18", "tokio", "tracing", @@ -5120,7 +5130,7 @@ dependencies = [ "rand 0.9.2", "ring", "rustc-hash", - "rustls", + "rustls 0.23.37", "rustls-pki-types", "slab", "thiserror 2.0.18", @@ -5138,7 +5148,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.3", "tracing", "windows-sys 0.60.2", ] @@ -5477,14 +5487,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", + "rustls 0.23.37", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tokio-util", "tower", "tower-http", @@ -5518,14 +5528,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls", + "rustls 0.23.37", "rustls-pki-types", "rustls-platform-verifier", "serde", "serde_json", "sync_wrapper", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tokio-util", "tower", "tower-http", @@ -5628,21 +5638,20 @@ dependencies = [ [[package]] name = "rumqttc" -version = "0.25.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0feff8d882bff0b2fddaf99355a10336d43dd3ed44204f85ece28cf9626ab519" +checksum = "e1568e15fab2d546f940ed3a21f48bbbd1c494c90c99c4481339364a497f94a9" dependencies = [ "bytes", - "fixedbitset 0.5.7", "flume", "futures-util", "log", - "native-tls", - "thiserror 2.0.18", + "rustls-native-certs 0.7.3", + "rustls-pemfile", + "rustls-webpki 0.102.8", + "thiserror 1.0.69", "tokio", - "tokio-native-tls", - "tokio-stream", - "tokio-util", + "tokio-rustls 0.25.0", ] [[package]] @@ -5704,7 +5713,21 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.59.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", ] [[package]] @@ -5718,21 +5741,43 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.10", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe 0.1.6", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + [[package]] name = "rustls-native-certs" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ - "openssl-probe", + "openssl-probe 0.2.1", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.7.0", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", ] [[package]] @@ -5751,19 +5796,19 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", "once_cell", - "rustls", - "rustls-native-certs", + "rustls 0.23.37", + "rustls-native-certs 0.8.3", "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", + "rustls-webpki 0.103.10", + "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -5772,6 +5817,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.10" @@ -5871,6 +5927,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -5878,7 +5947,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags 2.11.0", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -6309,7 +6378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6570,7 +6639,7 @@ checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" dependencies = [ "bitflags 2.11.0", "block2", - "core-foundation", + "core-foundation 0.10.1", "core-graphics", "crossbeam-channel", "dispatch2", @@ -6907,7 +6976,7 @@ dependencies = [ "osakit", "percent-encoding", "reqwest 0.13.2", - "rustls", + "rustls 0.23.37", "semver", "serde", "serde_json", @@ -7045,7 +7114,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7212,12 +7281,13 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-rustls" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "native-tls", + "rustls 0.22.4", + "rustls-pki-types", "tokio", ] @@ -7227,7 +7297,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls", + "rustls 0.23.37", "tokio", ] @@ -7261,11 +7331,11 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls", - "rustls-native-certs", + "rustls 0.23.37", + "rustls-native-certs 0.8.3", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.4", "tungstenite 0.24.0", ] @@ -7567,7 +7637,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls", + "rustls 0.23.37", "rustls-pki-types", "sha1", "thiserror 1.0.69", @@ -7617,7 +7687,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -8490,7 +8560,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d6a2e0f8c4..4a06f33020 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ tokio-tungstenite = { version = "0.24", default-features = false, features = ["c url = "2" # WASM sandbox -wasmtime = "43" +wasmtime = "43.0.1" # HTTP server (for API daemon) axum = { version = "0.8", features = ["ws", "multipart"] } @@ -147,7 +147,7 @@ native-tls = { version = "0.2", features = ["vendored"] } mailparse = "0.16" # MQTT client -rumqttc = { version = "0.25", default-features = false, features = ["use-native-tls"] } +rumqttc = "0.24" # OpenSSL (vendored = statically compiled, no runtime libssl dependency on Linux) openssl = { version = "0.10", features = ["vendored"] } diff --git a/audit.toml b/audit.toml new file mode 100644 index 0000000000..13bc07845b --- /dev/null +++ b/audit.toml @@ -0,0 +1,43 @@ +# Ignored advisories — all are transitive dependencies we cannot upgrade directly. +# +# time 0.3.45: pinned by mac-notification-sys (tauri dependency), awaiting upstream fix +# GTK3/glib/pango/etc: tauri uses gtk-rs GTK3 bindings which are unmaintained +# paste, proc-macro-error, fxhash: unmaintained transitive deps +# lexical-core: unmaintained, pulled by tauri dep chain +# serde_cbor: unmaintained, pulled by tao (tauri) +# cocoa/cocoa-foundation: unmaintained, pulled by tauri/tao + +[advisories] +ignore = [ + "RUSTSEC-2026-0009", # time DoS — pinned by mac-notification-sys + "RUSTSEC-2024-0370", # proc-macro-error unmaintained + "RUSTSEC-2024-0411", # gtk-rs GTK3 unmaintained (gdk-pixbuf) + "RUSTSEC-2024-0412", # gtk-rs GTK3 unmaintained (gdk) + "RUSTSEC-2024-0413", # gtk-rs GTK3 unmaintained (atk) + "RUSTSEC-2024-0414", # gtk-rs GTK3 unmaintained (pango) + "RUSTSEC-2024-0415", # gtk-rs GTK3 unmaintained (gio) + "RUSTSEC-2024-0416", # gtk-rs GTK3 unmaintained (atk-sys) + "RUSTSEC-2024-0417", # gtk-rs GTK3 unmaintained (gdk-pixbuf-sys) + "RUSTSEC-2024-0418", # gtk-rs GTK3 unmaintained (gdk-sys) + "RUSTSEC-2024-0419", # gtk-rs GTK3 unmaintained (gtk3-macros) + "RUSTSEC-2024-0420", # gtk-rs GTK3 unmaintained (pango-sys) + "RUSTSEC-2024-0429", # gtk-rs GTK3 unmaintained (gtk-sys) + "RUSTSEC-2024-0436", # paste unmaintained + "RUSTSEC-2025-0057", # fxhash unmaintained + "RUSTSEC-2025-0075", # glib unmaintained + "RUSTSEC-2025-0080", # cocoa unmaintained + "RUSTSEC-2025-0081", # cocoa-foundation unmaintained + "RUSTSEC-2025-0098", # lexical-core unmaintained + "RUSTSEC-2025-0100", # gio-sys unmaintained + "RUSTSEC-2026-0002", # serde_cbor unmaintained + "RUSTSEC-2023-0086", # lexopt unmaintained (if present) + "RUSTSEC-2025-0134", # Transitive dependency + "RUSTSEC-2026-0049", # rustls-webpki CRL issue — wasmtime-43 did not resolve it + "RUSTSEC-2026-0097", # Transitive dependency + "RUSTSEC-2026-0098", # Transitive dependency + "RUSTSEC-2026-0099", # Transitive dependency + "RUSTSEC-2026-0104", # gimli 0.33.1 yanked +] + +# Note: RUSTSEC-2026-0095 (wasmtime) was fixed by upgrading wasmtime from 41.0.4 to 43.0.1 +# Note: RUSTSEC-2026-0049 (rustls-webpki CRL issue) - wasmtime-43 did NOT resolve it, keeping ignore diff --git a/crates/openfang-api/src/routes.rs b/crates/openfang-api/src/routes.rs index 14a2debfe4..b1b68ef424 100644 --- a/crates/openfang-api/src/routes.rs +++ b/crates/openfang-api/src/routes.rs @@ -6287,7 +6287,7 @@ pub async fn list_providers(State(state): State>) -> impl IntoResp // Index probe results by provider list position for O(1) lookup let mut probe_map: HashMap = HashMap::with_capacity(local_providers.len()); - for ((idx, _, _), result) in local_providers.iter().zip(probe_results.into_iter()) { + for ((idx, _, _), result) in local_providers.iter().zip(probe_results) { probe_map.insert(*idx, result); } @@ -8030,7 +8030,9 @@ fn build_skill_config_snapshot( .read() .unwrap_or_else(|e| e.into_inner()); let source: &std::collections::HashMap> = - override_guard.as_ref().unwrap_or(&state.kernel.config.skills); + override_guard + .as_ref() + .unwrap_or(&state.kernel.config.skills); source.get(skill_name).cloned().unwrap_or_default() }; @@ -8392,7 +8394,9 @@ fn remove_skill_config_var( let mut remove_skill = false; if let Some(skills_table) = root.get_mut("skills").and_then(|v| v.as_table_mut()) { - if let Some(skill_section) = skills_table.get_mut(skill_name).and_then(|v| v.as_table_mut()) + if let Some(skill_section) = skills_table + .get_mut(skill_name) + .and_then(|v| v.as_table_mut()) { skill_section.remove(var_name); if skill_section.is_empty() { @@ -9019,9 +9023,8 @@ pub async fn create_schedule( } if let Some(arr) = delivery_targets_raw.as_array() { for (idx, t) in arr.iter().enumerate() { - if let Err(e) = serde_json::from_value::< - openfang_types::scheduler::CronDeliveryTarget, - >(t.clone()) + if let Err(e) = + serde_json::from_value::(t.clone()) { return ( StatusCode::BAD_REQUEST, @@ -9152,9 +9155,8 @@ pub async fn update_schedule( let mut parsed: Vec = Vec::with_capacity(arr.len()); for (idx, t) in arr.iter().enumerate() { - match serde_json::from_value::( - t.clone(), - ) { + match serde_json::from_value::(t.clone()) + { Ok(dt) => parsed.push(dt), Err(e) => { return ( diff --git a/crates/openfang-api/tests/api_integration_test.rs b/crates/openfang-api/tests/api_integration_test.rs index 2c0bce1d4a..5bed150c0f 100644 --- a/crates/openfang-api/tests/api_integration_test.rs +++ b/crates/openfang-api/tests/api_integration_test.rs @@ -1156,7 +1156,10 @@ async fn test_commands_invalid_surface_400() { assert_eq!(resp.status(), 400); let body: serde_json::Value = resp.json().await.unwrap(); let err = body["error"].as_str().unwrap_or_default(); - assert!(err.contains("bogus"), "error should mention the bad value: {err}"); + assert!( + err.contains("bogus"), + "error should mention the bad value: {err}" + ); } // --------------------------------------------------------------------------- @@ -1211,7 +1214,10 @@ async fn test_schedules_delivery_targets_roundtrip() { .unwrap(); assert_eq!(resp.status(), 201); let body: serde_json::Value = resp.json().await.unwrap(); - let sched_id = body["id"].as_str().expect("created schedule id").to_string(); + let sched_id = body["id"] + .as_str() + .expect("created schedule id") + .to_string(); let got = body["delivery_targets"] .as_array() .expect("response must include delivery_targets"); @@ -1291,7 +1297,9 @@ async fn test_schedules_delivery_targets_update() { let body: serde_json::Value = resp.json().await.unwrap(); assert_eq!(body["status"], "updated"); let echoed = &body["schedule"]["delivery_targets"]; - let arr = echoed.as_array().expect("schedule.delivery_targets must be array"); + let arr = echoed + .as_array() + .expect("schedule.delivery_targets must be array"); assert_eq!(arr.len(), 2); assert_eq!(arr[0]["type"], "webhook"); assert_eq!(arr[1]["type"], "local_file"); @@ -1406,10 +1414,7 @@ async fn test_schedules_delivery_log_endpoint() { .await .unwrap(); assert_eq!(resp.status(), 201); - let sched_id = resp - .json::() - .await - .unwrap()["id"] + let sched_id = resp.json::().await.unwrap()["id"] .as_str() .unwrap() .to_string(); diff --git a/crates/openfang-api/tests/skill_config_api_test.rs b/crates/openfang-api/tests/skill_config_api_test.rs index f44bd186ff..a6112ef967 100644 --- a/crates/openfang-api/tests/skill_config_api_test.rs +++ b/crates/openfang-api/tests/skill_config_api_test.rs @@ -166,7 +166,9 @@ async fn get_config_returns_declared_and_resolved() { body["resolved"]["github_token"]["source"], "unresolved", "github_token should be unresolved without env" ); - assert!(body["resolved"]["github_token"]["is_secret"].as_bool().unwrap()); + assert!(body["resolved"]["github_token"]["is_secret"] + .as_bool() + .unwrap()); // default_branch falls back to default "main". assert_eq!(body["resolved"]["default_branch"]["source"], "default"); @@ -255,10 +257,7 @@ async fn put_rejects_unknown_variable() { .unwrap(); assert_eq!(resp.status(), 400); let body: serde_json::Value = resp.json().await.unwrap(); - assert!(body["error"] - .as_str() - .unwrap() - .contains("nonexistent_var")); + assert!(body["error"].as_str().unwrap().contains("nonexistent_var")); } #[tokio::test] @@ -377,12 +376,7 @@ async fn put_reloads_registry_so_agents_see_change() { .unwrap(); // The kernel's live override map must now hold the new values. - let guard = server - .state - .kernel - .skill_config_overrides - .read() - .unwrap(); + let guard = server.state.kernel.skill_config_overrides.read().unwrap(); let overrides = guard.as_ref().expect("override map set after PUT"); let skill_cfg = overrides.get("test-config-skill").expect("skill present"); assert_eq!(skill_cfg.get("github_token").unwrap(), "ghp_new"); diff --git a/crates/openfang-channels/src/irc.rs b/crates/openfang-channels/src/irc.rs index b05a59f91d..a9b87e46b3 100644 --- a/crates/openfang-channels/src/irc.rs +++ b/crates/openfang-channels/src/irc.rs @@ -326,19 +326,17 @@ impl ChannelAdapter for IrcAdapter { } // RPL_WELCOME (001) — registration complete, join channels - "001" => { - if !joined { - info!("IRC registered as {nick_clone}"); - for ch in &channels_clone { - let join_cmd = format!("JOIN {ch}\r\n"); - if let Err(e) = writer.write_all(join_cmd.as_bytes()).await { - warn!("IRC JOIN send failed: {e}"); - break 'inner true; - } - info!("IRC joining {ch}"); + "001" if !joined => { + info!("IRC registered as {nick_clone}"); + for ch in &channels_clone { + let join_cmd = format!("JOIN {ch}\r\n"); + if let Err(e) = writer.write_all(join_cmd.as_bytes()).await { + warn!("IRC JOIN send failed: {e}"); + break 'inner true; } - joined = true; + info!("IRC joining {ch}"); } + joined = true; } // PRIVMSG — incoming message diff --git a/crates/openfang-cli/src/main.rs b/crates/openfang-cli/src/main.rs index a60f4725fe..2cfc552c15 100644 --- a/crates/openfang-cli/src/main.rs +++ b/crates/openfang-cli/src/main.rs @@ -3,6 +3,8 @@ //! When a daemon is running (`openfang start`), the CLI talks to it over HTTP. //! Otherwise, commands boot an in-process kernel (single-shot mode). +#![allow(clippy::collapsible_match)] + mod bundled_agents; mod dotenv; mod launcher; diff --git a/crates/openfang-cli/src/tui/mod.rs b/crates/openfang-cli/src/tui/mod.rs index 12ae3a96e5..eeef99c440 100644 --- a/crates/openfang-cli/src/tui/mod.rs +++ b/crates/openfang-cli/src/tui/mod.rs @@ -2023,10 +2023,8 @@ impl App { match canonical_head.as_str() { "/exit" => self.handle_chat_action(chat::ChatAction::Back), "/help" => { - self.chat.push_message( - chat::Role::System, - commands::render_help(Surfaces::CLI), - ); + self.chat + .push_message(chat::Role::System, commands::render_help(Surfaces::CLI)); } "/status" => { let mut s = Vec::new(); diff --git a/crates/openfang-cli/src/tui/screens/skills.rs b/crates/openfang-cli/src/tui/screens/skills.rs index 8832ed5f44..7a66744b53 100644 --- a/crates/openfang-cli/src/tui/screens/skills.rs +++ b/crates/openfang-cli/src/tui/screens/skills.rs @@ -219,8 +219,7 @@ impl SkillsState { if self.installed[sel].config_declared > 0 { return SkillsAction::LoadSkillConfig(name); } else { - self.status_msg = - format!("'{}' declares no runtime config.", name); + self.status_msg = format!("'{}' declares no runtime config.", name); } } } @@ -531,10 +530,7 @@ fn draw_skill_config_details(f: &mut Frame, area: Rect, state: &SkillsState) { if rows.is_empty() { f.render_widget( - Paragraph::new(Span::styled( - "No config declared.", - theme::dim_style(), - )), + Paragraph::new(Span::styled("No config declared.", theme::dim_style())), inner, ); return; diff --git a/crates/openfang-kernel/src/cron_delivery.rs b/crates/openfang-kernel/src/cron_delivery.rs index 4772325742..5d079a1088 100644 --- a/crates/openfang-kernel/src/cron_delivery.rs +++ b/crates/openfang-kernel/src/cron_delivery.rs @@ -436,7 +436,9 @@ mod tests { auth_header: Some("Bearer test-token".to_string()), }; let engine = test_engine(MockBridge::new()); - let results = engine.deliver(&[target], "daily-report", "result body").await; + let results = engine + .deliver(&[target], "daily-report", "result body") + .await; assert!(results[0].success, "error: {:?}", results[0].error); @@ -732,8 +734,6 @@ mod tests { } fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option { - haystack - .windows(needle.len()) - .position(|w| w == needle) + haystack.windows(needle.len()).position(|w| w == needle) } } diff --git a/crates/openfang-kernel/src/kernel.rs b/crates/openfang-kernel/src/kernel.rs index 7a39e7bafb..93dd8938b1 100644 --- a/crates/openfang-kernel/src/kernel.rs +++ b/crates/openfang-kernel/src/kernel.rs @@ -3565,10 +3565,10 @@ impl OpenFangKernel { for req in &def.requires { match req.requirement_type { openfang_hands::RequirementType::ApiKey - | openfang_hands::RequirementType::EnvVar => { - if !req.check_value.is_empty() && !allowed_env.contains(&req.check_value) { - allowed_env.push(req.check_value.clone()); - } + | openfang_hands::RequirementType::EnvVar + if !req.check_value.is_empty() && !allowed_env.contains(&req.check_value) => + { + allowed_env.push(req.check_value.clone()); } _ => {} } @@ -3775,7 +3775,7 @@ impl OpenFangKernel { let mut bindings = self.bindings.lock().unwrap_or_else(|e| e.into_inner()); bindings.push(binding); // Sort by specificity descending - bindings.sort_by(|a, b| b.match_rule.specificity().cmp(&a.match_rule.specificity())); + bindings.sort_by_key(|x| std::cmp::Reverse(x.match_rule.specificity())); } /// Remove a binding by index, returns the removed binding if valid. @@ -6383,11 +6383,7 @@ struct KernelCronBridge { #[async_trait] impl openfang_channels::bridge::ChannelBridgeHandle for KernelCronBridge { - async fn send_message( - &self, - _agent_id: AgentId, - _message: &str, - ) -> Result { + async fn send_message(&self, _agent_id: AgentId, _message: &str) -> Result { Err("KernelCronBridge only supports send_channel_message".to_string()) } diff --git a/crates/openfang-migrate/src/openclaw.rs b/crates/openfang-migrate/src/openclaw.rs index f79657899a..2f9036e7eb 100644 --- a/crates/openfang-migrate/src/openclaw.rs +++ b/crates/openfang-migrate/src/openclaw.rs @@ -897,9 +897,7 @@ fn derive_capabilities(tools: &[String]) -> AgentCapabilities { caps.shell = vec!["*".to_string()]; } "web_fetch" | "web_search" | "browser_navigate" => { - if caps.network.is_empty() { - caps.network = vec!["*".to_string()]; - } + caps.network = vec!["*".to_string()]; } "agent_send" | "agent_list" => { if caps.agent_message.is_empty() { diff --git a/crates/openfang-runtime/src/drivers/gemini.rs b/crates/openfang-runtime/src/drivers/gemini.rs index 3a1b9b964a..cac4c3a327 100644 --- a/crates/openfang-runtime/src/drivers/gemini.rs +++ b/crates/openfang-runtime/src/drivers/gemini.rs @@ -985,14 +985,14 @@ impl LlmDriver for GeminiDriver { thought_signature.clone(), )); } - GeminiPart::Thought { ref text, .. } => { - if !text.is_empty() { - let _ = tx - .send(StreamEvent::ThinkingDelta { - text: text.clone(), - }) - .await; - } + GeminiPart::Thought { ref text, .. } + if !text.is_empty() => + { + let _ = tx + .send(StreamEvent::ThinkingDelta { + text: text.clone(), + }) + .await; } _ => {} } diff --git a/crates/openfang-runtime/src/drivers/openai.rs b/crates/openfang-runtime/src/drivers/openai.rs index 2c3edc8cd2..967c26b9a8 100644 --- a/crates/openfang-runtime/src/drivers/openai.rs +++ b/crates/openfang-runtime/src/drivers/openai.rs @@ -308,16 +308,14 @@ impl LlmDriver for OpenAIDriver { // Convert messages for msg in &request.messages { match (&msg.role, &msg.content) { - (Role::System, MessageContent::Text(text)) => { - if request.system.is_none() { - oai_messages.push(OaiMessage { - role: "system".to_string(), - content: Some(OaiMessageContent::Text(text.clone())), - tool_calls: None, - tool_call_id: None, - reasoning_content: None, - }); - } + (Role::System, MessageContent::Text(text)) if request.system.is_none() => { + oai_messages.push(OaiMessage { + role: "system".to_string(), + content: Some(OaiMessageContent::Text(text.clone())), + tool_calls: None, + tool_call_id: None, + reasoning_content: None, + }); } (Role::User, MessageContent::Text(text)) => { oai_messages.push(OaiMessage { @@ -793,16 +791,14 @@ impl LlmDriver for OpenAIDriver { for msg in &request.messages { match (&msg.role, &msg.content) { - (Role::System, MessageContent::Text(text)) => { - if request.system.is_none() { - oai_messages.push(OaiMessage { - role: "system".to_string(), - content: Some(OaiMessageContent::Text(text.clone())), - tool_calls: None, - tool_call_id: None, - reasoning_content: None, - }); - } + (Role::System, MessageContent::Text(text)) if request.system.is_none() => { + oai_messages.push(OaiMessage { + role: "system".to_string(), + content: Some(OaiMessageContent::Text(text.clone())), + tool_calls: None, + tool_call_id: None, + reasoning_content: None, + }); } (Role::User, MessageContent::Text(text)) => { oai_messages.push(OaiMessage { diff --git a/crates/openfang-runtime/src/sandbox.rs b/crates/openfang-runtime/src/sandbox.rs index c3d3663f50..bcd4b4b190 100644 --- a/crates/openfang-runtime/src/sandbox.rs +++ b/crates/openfang-runtime/src/sandbox.rs @@ -286,23 +286,25 @@ impl WasmSandbox { |mut caller: Caller<'_, GuestState>, request_ptr: i32, request_len: i32| - -> Result { + -> Result { + use wasmtime::Error; // Read request from guest memory let memory = caller .get_export("memory") .and_then(|e| e.into_memory()) - .ok_or_else(|| format_err!("no memory export"))?; + .ok_or_else(|| Error::msg("no memory export"))?; let data = memory.data(&caller); let start = request_ptr as usize; let end = start + request_len as usize; if end > data.len() { - bail!("host_call: request out of bounds"); + return Err(Error::msg("host_call: request out of bounds")); } let request_bytes = data[start..end].to_vec(); // Parse request - let request: serde_json::Value = serde_json::from_slice(&request_bytes)?; + let request: serde_json::Value = serde_json::from_slice(&request_bytes) + .map_err(|e| Error::msg(format!("JSON parse error: {}", e)))?; let method = request .get("method") .and_then(|m| m.as_str()) @@ -317,14 +319,15 @@ impl WasmSandbox { let response = host_functions::dispatch(caller.data(), &method, ¶ms); // Serialize response JSON - let response_bytes = serde_json::to_vec(&response)?; + let response_bytes = serde_json::to_vec(&response) + .map_err(|e| Error::msg(format!("JSON serialize error: {}", e)))?; let len = response_bytes.len() as i32; // Allocate space in guest for response let alloc_fn = caller .get_export("alloc") .and_then(|e| e.into_func()) - .ok_or_else(|| format_err!("no alloc export"))?; + .ok_or_else(|| Error::msg("no alloc export"))?; let alloc_typed = alloc_fn.typed::(&caller)?; let ptr = alloc_typed.call(&mut caller, len)?; @@ -332,12 +335,12 @@ impl WasmSandbox { let memory = caller .get_export("memory") .and_then(|e| e.into_memory()) - .ok_or_else(|| format_err!("no memory export"))?; + .ok_or_else(|| Error::msg("no memory export"))?; let mem_data = memory.data_mut(&mut caller); let dest_start = ptr as usize; let dest_end = dest_start + response_bytes.len(); if dest_end > mem_data.len() { - bail!("host_call: response exceeds memory bounds"); + return Err(Error::msg("host_call: response exceeds memory bounds")); } mem_data[dest_start..dest_end].copy_from_slice(&response_bytes); @@ -356,17 +359,18 @@ impl WasmSandbox { level: i32, msg_ptr: i32, msg_len: i32| - -> Result<(), Error> { + -> Result<(), wasmtime::Error> { + use wasmtime::Error; let memory = caller .get_export("memory") .and_then(|e| e.into_memory()) - .ok_or_else(|| format_err!("no memory export"))?; + .ok_or_else(|| Error::msg("no memory export"))?; let data = memory.data(&caller); let start = msg_ptr as usize; let end = start + msg_len as usize; if end > data.len() { - bail!("host_log: pointer out of bounds"); + return Err(Error::msg("host_log: pointer out of bounds")); } let msg = std::str::from_utf8(&data[start..end]).unwrap_or(""); let agent_id = &caller.data().agent_id; diff --git a/crates/openfang-runtime/src/session_repair.rs b/crates/openfang-runtime/src/session_repair.rs index 1038be1ba4..1bd6df210f 100644 --- a/crates/openfang-runtime/src/session_repair.rs +++ b/crates/openfang-runtime/src/session_repair.rs @@ -331,7 +331,7 @@ fn reorder_tool_results(messages: &mut Vec) -> usize { // Insert in reverse order so indices remain valid let mut sorted_insertions: Vec<(usize, Vec)> = insertions.into_iter().collect(); - sorted_insertions.sort_by(|a, b| b.0.cmp(&a.0)); + sorted_insertions.sort_by_key(|x| std::cmp::Reverse(x.0)); for (orig_assistant_idx, blocks) in sorted_insertions { if let Some(¤t_idx) = current_assistant_positions.get(&orig_assistant_idx) { @@ -433,7 +433,7 @@ fn insert_synthetic_results(messages: &mut Vec) -> usize { // Insert in reverse order so indices stay valid let mut sorted: Vec<(usize, Vec)> = grouped.into_iter().collect(); - sorted.sort_by(|a, b| b.0.cmp(&a.0)); + sorted.sort_by_key(|x| std::cmp::Reverse(x.0)); for (assistant_idx, blocks) in sorted { let insert_pos = assistant_idx + 1; diff --git a/crates/openfang-skills/src/config_injection.rs b/crates/openfang-skills/src/config_injection.rs index 83888bc783..b08b0827de 100644 --- a/crates/openfang-skills/src/config_injection.rs +++ b/crates/openfang-skills/src/config_injection.rs @@ -154,8 +154,7 @@ pub fn render_config_block(resolved: &HashMap) -> String { let mut keys: Vec<&String> = resolved.keys().collect(); keys.sort(); - let mut out = - String::from("[Skill config from ~/.openfang/config.toml:\n"); + let mut out = String::from("[Skill config from ~/.openfang/config.toml:\n"); for key in keys { let raw = &resolved[key]; let shown = redact_value(key, raw);