diff --git a/.env.example b/.env.example index b9bfcada0e..394d7fc3e7 100644 --- a/.env.example +++ b/.env.example @@ -137,12 +137,13 @@ RUST_LOG=buzz_relay=debug,buzz_datastore=info,buzz_db=debug,buzz_auth=debug,buzz # to a CLI flag of the same name (lowercase, hyphens → underscores). All values # are optional unless noted; defaults are shown in comments. # -# Quick start: -# BUZZ_PRIVATE_KEY= BUZZ_RELAY_URL=ws://localhost:3000 buzz-acp +# Quick start (identity is read from daz-secrets): +# BUZZ_RELAY_URL=ws://localhost:3000 buzz-acp \ +# --secret-service buzz-desktop --secret-account identity # ── Identity & auth ────────────────────────────────────────────────────────── -# Nostr private key (hex or bech32). REQUIRED — identifies the agent on the relay. -# BUZZ_PRIVATE_KEY=<32-byte hex or nsec1… private key> +# Provider coordinates are non-secret CLI flags (`--secret-service` and +# `--secret-account`). Private key bytes must never be placed in this file. # Relay WebSocket URL the harness connects to. # Note: the relay itself uses RELAY_URL (above); this is the ACP harness's @@ -240,11 +241,6 @@ RUST_LOG=buzz_relay=debug,buzz_datastore=info,buzz_db=debug,buzz_auth=debug,buzz # high-throughput agents. Minimum 1. # BUZZ_ACP_EVENT_BUFFER=256 -# ── Legacy aliases ─────────────────────────────────────────────────────────── -# These are accepted for backward compatibility but the canonical names above -# are preferred: -# BUZZ_ACP_PRIVATE_KEY → BUZZ_PRIVATE_KEY - # Optional relay join policy. Markdown is served by the relay so every join # surface can present the same documents. Each document and the independent age # attestation are optional; configuring any one enables policy acceptance. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e65157705a..27f8cd8947 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -127,6 +127,25 @@ jobs: uses: taiki-e/install-action@0fd46367812ee04360509b4169d9f659d6892bb2 # v2.79.15 with: tool: cargo-nextest@0.9.136 + - name: Install daz-secrets conformance provider + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 + with: + repository: darrenoakey/daz-secrets + ref: ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa + path: .ci/daz-secrets + - name: Configure isolated test credential provider + run: | + mkdir -p "$HOME/.config/daz-secrets" "$RUNNER_TEMP/daz-secrets" + go build -trimpath -o "$RUNNER_TEMP/daz-secrets/buzz-ci-provider" \ + ./.ci/daz-secrets/cmd/daz-secrets-conformance-provider + chmod 0755 "$RUNNER_TEMP/daz-secrets/buzz-ci-provider" + printf '%s\n' \ + 'version = 1' \ + "provider_path = \"$RUNNER_TEMP/daz-secrets/buzz-ci-provider\"" \ + 'provider_id = "buzz-ci-provider"' \ + 'timeout_ms = 2000' \ + > "$HOME/.config/daz-secrets/provider.toml" + chmod 0600 "$HOME/.config/daz-secrets/provider.toml" - name: Unit tests run: just test-unit diff --git a/AGENTS.md b/AGENTS.md index 571871c3a4..ac8a85f61f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,10 +164,10 @@ check existing reply handlers for the pattern. ## Agent CLI (`buzz-cli`) -`buzz` is the agent-first CLI. Auth env vars -(`BUZZ_RELAY_URL`, `BUZZ_PRIVATE_KEY`, `BUZZ_AUTH_TAG`) are auto-injected -by the ACP harness into managed agent subprocesses. In development, set -`BUZZ_PRIVATE_KEY` and `BUZZ_RELAY_URL` in your environment manually. +`buzz` is the agent-first CLI. Identity bytes come directly from the configured +`daz-secrets` provider and must never be placed in env, argv, or files. Managed +agents receive only the non-secret provider service/account coordinates. The +relay URL and public owner-attestation metadata are supplied separately. ### Building the CLI diff --git a/Cargo.lock b/Cargo.lock index 937ead564a..bc30709984 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,9 +59,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -74,9 +74,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -133,9 +133,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "appattest" @@ -172,9 +172,9 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] @@ -205,39 +205,15 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "async-broadcast" -version = "0.7.2" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "async-compression" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +checksum = "3976abdc8fe7d1133d43d304afd42abdf5bc3e1319d263d223bde07b5efc4be8" dependencies = [ "compression-codecs", "compression-core", @@ -245,24 +221,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if 1.0.4", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 1.1.4", - "slab", - "windows-sys 0.61.2", -] - [[package]] name = "async-lock" version = "3.4.2" @@ -274,75 +232,22 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-process" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if 1.0.4", - "event-listener", - "futures-lite", - "rustix 1.1.4", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - -[[package]] -name = "async-signal" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if 1.0.4", - "futures-core", - "futures-io", - "rustix 1.1.4", - "signal-hook-registry", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "async-utility" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34a3b57207a7a1007832416c3e4862378c8451b4e8e093e436f48c2d3d2c151" +checksum = "188f83b9a198af8c336e505611edb00d6d2ac5c694241c5a4f9a12316938cfe9" dependencies = [ "futures-util", "gloo-timers", @@ -417,7 +322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84790c55b5704b0d35130bf16a4ce22a8e70eb0ea773522557524d9a4852663d" dependencies = [ "nix 0.30.1", - "rand 0.9.4", + "rand 0.9.5", ] [[package]] @@ -433,14 +338,14 @@ dependencies = [ "serde", "serde_json", "url", - "webpki-roots 1.0.7", + "webpki-roots 1.0.9", ] [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-creds" @@ -453,16 +358,16 @@ dependencies = [ "quick-xml 0.38.4", "rust-ini", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "url", ] [[package]] name = "aws-lc-rs" -version = "1.17.0" +version = "1.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1" dependencies = [ "aws-lc-sys", "zeroize", @@ -470,14 +375,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.41.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] @@ -486,7 +392,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "838b36c8dc927b6db1b6c6b8f5d05865f2213550b9e83bf92fa99ed6525472c0" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -516,7 +422,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1 0.10.6", + "sha1 0.10.7", "sync_wrapper", "tokio", "tokio-tungstenite 0.29.0", @@ -553,7 +459,7 @@ checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -644,20 +550,40 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bitcoin-consensus-encoding" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "207311705279250ba465076a1bac4b1ac982855fff73fc5f67e22158ac58cdc9" +dependencies = [ + "bitcoin-internals", + "hex-conservative 1.2.0", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d573f4cf32996a8dce612e4348cece65a241f1882ed594047c9ba348e8869fa5" + [[package]] name = "bitcoin-io" -version = "0.1.4" +version = "0.1.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" +checksum = "bb5de036369d1ac59d3c1819ebc4d850f89466f5401c571a285b6ed564a4cb78" +dependencies = [ + "bitcoin-consensus-encoding", +] [[package]] name = "bitcoin_hashes" -version = "0.14.1" +version = "0.14.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" dependencies = [ "bitcoin-io", - "hex-conservative", + "hex-conservative 0.2.2", "serde", ] @@ -669,9 +595,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" dependencies = [ "serde_core", ] @@ -710,9 +636,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", ] @@ -735,19 +661,6 @@ dependencies = [ "objc2", ] -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - [[package]] name = "blurhash" version = "0.2.3" @@ -756,9 +669,9 @@ checksum = "e79769241dcd44edf79a732545e8b5cec84c247ac060f5252cd51885d093a8fc" [[package]] name = "bon" -version = "3.9.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" dependencies = [ "bon-macros", "rustversion", @@ -766,9 +679,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.9.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" dependencies = [ "darling 0.23.0", "ident_case", @@ -776,25 +689,25 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "bstr" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" dependencies = [ "memchr", "regex-automata", - "serde", + "serde_core", ] [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "buzz-acp" @@ -807,6 +720,7 @@ dependencies = [ "buzz-sdk", "chrono", "clap", + "daz-secrets", "evalexpr", "futures-util", "hex", @@ -818,15 +732,16 @@ dependencies = [ "serde", "serde_json", "sha2 0.11.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-tungstenite 0.29.0", "tokio-util", - "toml 1.1.2+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", "tracing", "tracing-subscriber", "url", "uuid", + "zeroize", ] [[package]] @@ -843,6 +758,7 @@ dependencies = [ "buzz-search", "buzz-workflow", "clap", + "daz-secrets", "deadpool-redis", "hex", "nostr", @@ -852,6 +768,7 @@ dependencies = [ "tokio", "tracing", "url", + "zeroize", ] [[package]] @@ -891,7 +808,7 @@ dependencies = [ "serde_json", "sha2 0.11.0", "sqlx", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -904,11 +821,11 @@ dependencies = [ "buzz-core", "hex", "nostr", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", "sha2 0.11.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "url", @@ -926,7 +843,7 @@ dependencies = [ "k8s-openapi", "kube", "nostr", - "rand 0.10.1", + "rand 0.10.2", "rustls", "serde", "serde_json", @@ -948,22 +865,24 @@ dependencies = [ "bytes", "chrono", "clap", + "daz-secrets", "diffy", "dirs", "hex", "infer", "nostr", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "rustls", "serde", "serde_json", "sha2 0.11.0", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "url", "uuid", + "zeroize", ] [[package]] @@ -973,7 +892,7 @@ dependencies = [ "proptest", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", "uuid", ] @@ -987,12 +906,12 @@ dependencies = [ "hmac 0.13.0", "nostr", "percent-encoding", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", "sha2 0.11.0", "subtle", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "uuid", "zeroize", @@ -1008,12 +927,12 @@ dependencies = [ "metrics", "metrics-util", "nostr", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", "sha2 0.11.0", "sqlx", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -1026,6 +945,7 @@ dependencies = [ "base64 0.22.1", "buzz-cli", "buzz-core", + "daz-secrets", "git-credential-nostr", "git-sign-nostr", "ignore", @@ -1070,7 +990,7 @@ dependencies = [ "serde_json", "sha2 0.11.0", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tracing", @@ -1105,7 +1025,7 @@ dependencies = [ "hex", "nostr", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-tungstenite 0.29.0", "url", @@ -1120,7 +1040,7 @@ dependencies = [ "serde_json", "serde_yaml", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -1136,7 +1056,7 @@ dependencies = [ "redis", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -1161,13 +1081,13 @@ dependencies = [ "nostr", "p256", "proptest", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "serde", "serde_json", "sha2 0.11.0", "sqlx", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tower", "tower-http", @@ -1219,7 +1139,7 @@ dependencies = [ "opentelemetry_sdk 0.32.1", "postcard", "pulldown-cmark", - "rand 0.10.1", + "rand 0.10.2", "redis", "reqwest 0.13.4", "rust-s3", @@ -1231,7 +1151,7 @@ dependencies = [ "sqlx", "subtle", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-tungstenite 0.29.0", "tokio-util", @@ -1261,7 +1181,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.11.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -1275,7 +1195,7 @@ dependencies = [ "nostr", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", "uuid", ] @@ -1285,7 +1205,7 @@ version = "0.1.0" dependencies = [ "buzz-core", "sqlx", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "uuid", ] @@ -1301,10 +1221,11 @@ dependencies = [ "buzz-sdk", "buzz-ws-client", "chrono", + "daz-secrets", "futures-util", "hex", "nostr", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "rust-s3", "rustls", @@ -1312,13 +1233,14 @@ dependencies = [ "serde_json", "sha2 0.11.0", "sqlx", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-tungstenite 0.29.0", "tracing", "tracing-subscriber", "url", "uuid", + "zeroize", ] [[package]] @@ -1329,7 +1251,7 @@ dependencies = [ "hex", "ort", "ort-sys", - "rand 0.10.1", + "rand 0.10.2", "sentencepiece-model", "serde", "serde_json", @@ -1357,7 +1279,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -1370,7 +1292,7 @@ dependencies = [ "futures-util", "nostr", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-tungstenite 0.29.0", "tracing", @@ -1385,9 +1307,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -1403,9 +1325,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "bzip2" @@ -1447,9 +1369,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "jobserver", @@ -1488,9 +1410,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" @@ -1505,9 +1427,9 @@ dependencies = [ [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.3.0", @@ -1554,9 +1476,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "301b56658598e48f3648647ac6fc887be7e7108eddfa4e9b63fcf3ec58c0cadf" dependencies = [ "clap_builder", "clap_derive", @@ -1564,9 +1486,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "94a65403d1a1bd28f7dc68eb8506e8874808ee5eecb59298de588e2e1407a078" dependencies = [ "anstream", "anstyle", @@ -1576,14 +1498,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -1603,9 +1525,9 @@ dependencies = [ [[package]] name = "cmov" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" [[package]] name = "cobs" @@ -1613,7 +1535,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -1696,15 +1618,6 @@ version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "const-hex" version = "1.19.1" @@ -1775,9 +1688,9 @@ dependencies = [ [[package]] name = "cordyceps" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +checksum = "5b9ab7e0ca1d179628fa0172b2b97203c7fa0cd81be2448bd446fb9559ca9261" dependencies = [ "loom", "tracing", @@ -1900,18 +1813,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1928,18 +1841,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crossterm" @@ -1947,7 +1860,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "mio", "parking_lot", @@ -1963,7 +1876,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "derive_more", "document-features", @@ -2067,43 +1980,16 @@ dependencies = [ "phf", ] -[[package]] -name = "csv" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde_core", -] - -[[package]] -name = "csv-core" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" -dependencies = [ - "memchr", -] - [[package]] name = "ctor" -version = "0.6.3" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e" +checksum = "2d83cb7e7a873830708d6b02a78cd36a592c6fa14bf267b68725103b85c0d77f" dependencies = [ - "ctor-proc-macro", - "dtor", + "link-section", + "linktime-proc-macro", ] -[[package]] -name = "ctor-proc-macro" -version = "0.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" - [[package]] name = "ctr" version = "0.9.2" @@ -2140,9 +2026,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "5.0.0-rc.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f359e08ca85e7bd759e1fd933ff2bccd81864c60a8fba0e259c7f822b0924bf" +checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.3.0", @@ -2164,7 +2050,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2187,6 +2073,16 @@ dependencies = [ "darling_macro 0.23.0", ] +[[package]] +name = "darling" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88490bf1b990d87eaaa7ac8aa887f629a08e7359765b4911faf63c3763347d23" +dependencies = [ + "darling_core 0.24.0", + "darling_macro 0.24.0", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -2198,7 +2094,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2211,7 +2107,20 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084e274f91c482280130e1e34e0b8d6e66776a060d7b6de7b84289ca778868c4" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 3.0.3", ] [[package]] @@ -2222,7 +2131,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2233,7 +2142,18 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.117", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5792fa0d41cd2325ce0ffa64f0a340eaebd4971a3a0c5e1ffd2cc488a355e" +dependencies = [ + "darling_core 0.24.0", + "quote", + "syn 3.0.3", ] [[package]] @@ -2261,15 +2181,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "data-encoding-macro" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c" +checksum = "c6a127ecbb3c4632e1525380e04c0c3fcf8dcb44d32a79ea290d8a36906edcd8" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2277,42 +2197,27 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" +checksum = "c54e03a951783e8b327515db3f2a2fd0e3bed362a96b066f341ce66ed49b4ead" dependencies = [ "data-encoding", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] -name = "dbus" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73" +name = "daz-secrets" +version = "0.1.0-alpha.1" +source = "git+https://github.com/darrenoakey/daz-secrets?rev=ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa#ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa" dependencies = [ - "libc", - "libdbus-sys", - "windows-sys 0.61.2", -] - -[[package]] -name = "dbus-secret-service" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6" -dependencies = [ - "aes", - "block-padding", - "cbc", - "dbus", - "fastrand", - "hkdf 0.12.4", - "num", - "once_cell", - "openssl", - "sha2 0.10.9", - "zeroize", + "directories", + "nix 0.30.1", + "rand 0.9.5", + "serde", + "tokio", + "tokio-util", + "toml 0.9.12+spec-1.1.0", + "windows-permissions", ] [[package]] @@ -2353,9 +2258,9 @@ checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" [[package]] name = "der" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d" dependencies = [ "const-oid", "pem-rfc7468", @@ -2368,7 +2273,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -2380,7 +2284,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2401,7 +2305,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2411,7 +2315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2433,7 +2337,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.117", + "syn 2.0.119", "unicode-xid", ] @@ -2445,9 +2349,9 @@ checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" [[package]] name = "diffy" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05264ab2aab4fb952fc4b0f3f6eff1ddfb4563064053a4ea174d91537584a769" +checksum = "10aec8f7f9393bd6a4f2762be0ceb012d3cbe2478987258cc9960de148561914" dependencies = [ "hashbrown 0.17.1", ] @@ -2469,12 +2373,21 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.0", + "block-buffer 0.12.1", "const-oid", "crypto-common 0.2.2", "ctutils", ] +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs" version = "6.0.0" @@ -2502,7 +2415,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "libc", "objc2", @@ -2510,13 +2423,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -2554,21 +2467,6 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" -[[package]] -name = "dtor" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301" -dependencies = [ - "dtor-proc-macro", -] - -[[package]] -name = "dtor-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" - [[package]] name = "dunce" version = "1.0.5" @@ -2613,7 +2511,7 @@ version = "3.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60" dependencies = [ - "curve25519-dalek 5.0.0-rc.0", + "curve25519-dalek 5.0.0", "ed25519", "rand_core 0.10.1", "serde", @@ -2625,9 +2523,9 @@ dependencies = [ [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" dependencies = [ "serde", ] @@ -2674,12 +2572,6 @@ dependencies = [ "cfg-if 1.0.4", ] -[[package]] -name = "endi" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" - [[package]] name = "endian-type" version = "0.1.2" @@ -2694,28 +2586,7 @@ checksum = "3ed8956bd5c1f0415200516e78ff07ec9e16415ade83c056c230d7b7ea0d55b7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -2767,11 +2638,10 @@ checksum = "b6aff27af350e7b53e82aac3e5ab6389abd8f280640ac034508dff0608c4c7e5" [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -2824,17 +2694,11 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fdeflate" @@ -2930,7 +2794,7 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin 0.9.9", ] [[package]] @@ -2941,7 +2805,7 @@ checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin 0.9.9", ] [[package]] @@ -2994,9 +2858,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" dependencies = [ "futures-channel", "futures-core", @@ -3017,14 +2881,14 @@ dependencies = [ "diatomic-waker", "futures-core", "pin-project-lite", - "spin 0.10.0", + "spin 0.10.1", ] [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" dependencies = [ "futures-core", "futures-sink", @@ -3032,15 +2896,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" dependencies = [ "futures-core", "futures-task", @@ -3060,9 +2924,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" [[package]] name = "futures-lite" @@ -3079,32 +2943,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-channel", "futures-core", @@ -3128,9 +2992,9 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" dependencies = [ "cc", "cfg-if 1.0.4", @@ -3216,6 +3080,7 @@ name = "git-credential-nostr" version = "0.1.0" dependencies = [ "base64 0.22.1", + "daz-secrets", "nostr", "serde_json", "zeroize", @@ -3227,6 +3092,7 @@ version = "0.1.0" dependencies = [ "base64 0.22.1", "chrono", + "daz-secrets", "hex", "libc", "nostr", @@ -3251,14 +3117,14 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "globset" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" dependencies = [ "aho-corasick", "bstr", @@ -3292,9 +3158,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", @@ -3354,9 +3220,9 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" dependencies = [ "hashbrown 0.16.1", ] @@ -3394,46 +3260,61 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "hex-conservative" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35431185f361ccf3ffc58254628af5f1f5d5f28531da2e02e5d6c82bbc282a10" +dependencies = [ + "arrayvec", +] + [[package]] name = "hf-hub" -version = "1.0.0-rc.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89305dc8fe34e165eaf0eb12b6e294e12381d9df9a431bcc52a5809bab4319" +checksum = "e7ccb6bcc85dec15413ef5949879f9a5497ca4568ed702547eb83fac23376e5c" dependencies = [ "base64 0.22.1", "bon", "bytes", "futures", + "getrandom 0.2.17", "globset", "hf-xet", "hyper", "pathdiff", + "percent-encoding", "reqwest 0.13.4", "serde", "serde_json", "sha2 0.11.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-retry", "tokio-util", "tracing", "url", + "wasm-bindgen-futures", ] [[package]] name = "hf-xet" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "430b33fa84f92796d4d263070b6c0d3ca219df7b9a0e1853ee431029b1612bcd" +checksum = "c237ef4fb0ce1962a5117f8bd8c74454b41629826a9df17d14a1840ca18f0754" dependencies = [ + "anyhow", "async-trait", "bytes", "http", "more-asserts", "serde", - "thiserror 2.0.18", + "serde_json", + "thiserror 2.0.19", "tokio", "tokio-util", + "tokio_with_wasm", "tracing", "uuid", "xet-client", @@ -3461,9 +3342,9 @@ dependencies = [ "idna", "ipnet", "jni 0.22.4", - "rand 0.10.1", + "rand 0.10.2", "rustls", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tokio", "tokio-rustls", @@ -3483,9 +3364,9 @@ dependencies = [ "jni 0.22.4", "once_cell", "prefix-trie", - "rand 0.10.1", + "rand 0.10.2", "ring", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "url", @@ -3508,26 +3389,17 @@ dependencies = [ "ndk-context", "once_cell", "parking_lot", - "rand 0.10.1", + "rand 0.10.2", "resolv-conf", "rustls", "smallvec", "system-configuration", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-rustls", "tracing", ] -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac 0.12.1", -] - [[package]] name = "hkdf" version = "0.13.0" @@ -3566,9 +3438,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -3576,9 +3448,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http", @@ -3586,9 +3458,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" dependencies = [ "bytes", "futures-core", @@ -3617,15 +3489,15 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" [[package]] name = "hybrid-array" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" dependencies = [ "subtle", "typenum", @@ -3634,9 +3506,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" dependencies = [ "atomic-waker", "bytes", @@ -3669,7 +3541,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.7", + "webpki-roots 1.0.9", ] [[package]] @@ -3877,9 +3749,9 @@ dependencies = [ [[package]] name = "igd-next" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac9a3c8278f43b4cd8463380f4a25653ac843e5b177e1d3eaf849cc9ba10d4d" +checksum = "de7238d487a9aff61f81b5ab41c0a841532a115a398b5fa92a2fadd0885e2581" dependencies = [ "attohttpc", "bytes", @@ -3889,7 +3761,7 @@ dependencies = [ "hyper", "hyper-util", "log", - "rand 0.10.1", + "rand 0.10.2", "tokio", "url", "xmltree", @@ -3897,9 +3769,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.25" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" +checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" dependencies = [ "crossbeam-deque", "globset", @@ -3985,15 +3857,15 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" +checksum = "2bf84e73fa6f27f299dec58e13223cf70db80da872eb921d4f6138342a0eabc8" dependencies = [ - "darling 0.23.0", + "darling 0.24.0", "indoc", "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -4023,18 +3895,18 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" dependencies = [ "serde", ] [[package]] name = "iroh" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fca9b4b462c343ff88fc0af4096c186f939b602a0bc08723536ef2c31c93971" +checksum = "460de6bc52163b41b1646931f2897e5ab986f0966ade444467fec25024751a72" dependencies = [ "backon", "blake3", @@ -4064,7 +3936,7 @@ dependencies = [ "pin-project", "portable-atomic", "portmapper", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "rustc-hash", "rustls", @@ -4083,18 +3955,18 @@ dependencies = [ [[package]] name = "iroh-base" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830a582cd54410dc1aa71d4786a82c3297d7b0165accd8b6dbbb3b240b48140d" +checksum = "6be73e16ee21c923aca9b3121aaa0db936f7c7ecc156ff47b8dac944c68d59a8" dependencies = [ - "curve25519-dalek 5.0.0-rc.0", + "curve25519-dalek 5.0.0", "data-encoding", "data-encoding-macro", "derive_more", "ed25519-dalek", "getrandom 0.4.3", "n0-error", - "rand 0.10.1", + "rand 0.10.2", "serde", "url", "zeroize", @@ -4102,9 +3974,9 @@ dependencies = [ [[package]] name = "iroh-dns" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516e4eedc38e33ab69a6bd325520332dc3d67b25454e2d590ebb84a25240dd9a" +checksum = "46f6a9b39d18e6345f5c151afd299f2488e2cb5c520fe41b107b6bd3dc4c3349" dependencies = [ "arc-swap", "cfg_aliases", @@ -4115,7 +3987,7 @@ dependencies = [ "n0-future", "ndk-context", "portable-atomic", - "rand 0.10.1", + "rand 0.10.2", "rustls", "simple-dns", "strum", @@ -4148,14 +4020,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "iroh-relay" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8149bb6a57126225a07d6928846d82dcedfd24ea0f863ef7b2eb475e1d726354" +checksum = "24bd586cf927f7b700f56ec3639b53cb5fa901ce284784051ff71092bfbf8193" dependencies = [ "blake3", "bytes", @@ -4171,7 +4043,7 @@ dependencies = [ "iroh-base", "iroh-dns", "iroh-metrics", - "lru 0.18.0", + "lru 0.18.2", "n0-error", "n0-future", "noq", @@ -4179,7 +4051,7 @@ dependencies = [ "num_enum", "pin-project", "postcard", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "rustls", "rustls-pki-types", @@ -4192,8 +4064,7 @@ dependencies = [ "tokio-websockets", "tracing", "url", - "vergen-gitcl", - "webpki-roots 1.0.7", + "webpki-roots 1.0.9", "ws_stream_wasm", ] @@ -4246,7 +4117,7 @@ dependencies = [ "jni-sys 0.4.1", "log", "simd_cesu8", - "thiserror 2.0.18", + "thiserror 2.0.19", "walkdir", "windows-link 0.2.1", ] @@ -4261,7 +4132,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4289,28 +4160,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if 1.0.4", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -4334,7 +4204,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -4357,24 +4227,7 @@ checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" dependencies = [ "hashbrown 0.16.1", "portable-atomic", - "thiserror 2.0.18", -] - -[[package]] -name = "keyring" -version = "3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" -dependencies = [ - "byteorder", - "dbus-secret-service", - "log", - "openssl", - "secret-service", - "security-framework 2.11.1", - "security-framework 3.7.0", - "windows-sys 0.60.2", - "zeroize", + "thiserror 2.0.19", ] [[package]] @@ -4433,7 +4286,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tower", @@ -4455,7 +4308,7 @@ dependencies = [ "serde", "serde-value", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -4472,9 +4325,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "left-right" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0c21e4c8ff95f487fb34e6f9182875f42c84cef966d29216bf115d9bba835a" +checksum = "8bc015ded5d9b3054dbbdb63332cdd6ee42352ccef19e911e25117490e2f48ee" dependencies = [ "crossbeam-utils", "loom", @@ -4483,19 +4336,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" - -[[package]] -name = "libdbus-sys" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" -dependencies = [ - "cc", - "pkg-config", -] +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libloading" @@ -4515,18 +4358,18 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "2026a5056764a10b2bf5d56488cba40da507f5493a6a429340e2004d9ed085fa" dependencies = [ "libc", ] [[package]] name = "libsqlite3-sys" -version = "0.30.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" dependencies = [ "pkg-config", "vcpkg", @@ -4534,13 +4377,25 @@ dependencies = [ [[package]] name = "line-clipping" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +checksum = "e752191d037c44ad111a8caa762921926658402f01cc1253f7bef2020ece4f5e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] +[[package]] +name = "link-section" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee1a0d6e252afe82e7bc2db42fba60e02ddf3b1accaf8cb21d96e34ba61f3d4" + +[[package]] +name = "linktime-proc-macro" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348d0075b1fc163b26d72a7f75fc5141daf2fd1bdf128d873cbaf6785d495bdf" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -4576,9 +4431,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "logos" @@ -4601,7 +4456,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4634,9 +4489,9 @@ checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" [[package]] name = "lru" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +checksum = "5d2f2f9b4ba7e6b24d95e7e899329d35be83bcded72c8540cdd5368932d1d90a" dependencies = [ "hashbrown 0.17.1", ] @@ -4721,7 +4576,7 @@ checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -4736,9 +4591,9 @@ dependencies = [ [[package]] name = "md5" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0" +checksum = "7ebb8d8732c6a6df3d8f032a82911cfc747e00efb95cc46e8d0acd5b5b88570c" [[package]] name = "mdns-sd" @@ -4757,9 +4612,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memmem" @@ -4779,17 +4634,17 @@ dependencies = [ [[package]] name = "mesh-llm-api-client" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "hex", "mesh-llm-client", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "mesh-llm-api-server" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-api-client", @@ -4800,12 +4655,12 @@ dependencies = [ [[package]] name = "mesh-llm-build-info" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" [[package]] name = "mesh-llm-client" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -4822,13 +4677,13 @@ dependencies = [ "mesh-llm-types", "model-artifact", "nostr-sdk", - "prost 0.14.3", - "rand 0.10.1", + "prost 0.14.4", + "rand 0.10.2", "rustls", "serde", "serde_json", "sha2 0.10.9", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -4837,7 +4692,7 @@ dependencies = [ [[package]] name = "mesh-llm-config" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -4853,7 +4708,7 @@ dependencies = [ [[package]] name = "mesh-llm-embedded-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-host-runtime", @@ -4863,7 +4718,7 @@ dependencies = [ [[package]] name = "mesh-llm-events" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "clap", @@ -4875,7 +4730,7 @@ dependencies = [ [[package]] name = "mesh-llm-gpu-bench" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "cc", @@ -4888,7 +4743,7 @@ dependencies = [ [[package]] name = "mesh-llm-guardrails" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "serde", "serde_json", @@ -4897,7 +4752,7 @@ dependencies = [ [[package]] name = "mesh-llm-hardware-profile" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "mesh-llm-native-runtime", ] @@ -4905,7 +4760,7 @@ dependencies = [ [[package]] name = "mesh-llm-host-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "argon2", @@ -4929,7 +4784,6 @@ dependencies = [ "httparse", "iroh", "json5", - "keyring", "libc", "mdns-sd", "mesh-llm-api-server", @@ -4960,8 +4814,8 @@ dependencies = [ "opentelemetry 0.31.0", "opentelemetry-otlp 0.31.1", "opentelemetry_sdk 0.31.0", - "prost 0.14.3", - "rand 0.10.1", + "prost 0.14.4", + "rand 0.10.2", "regex-lite", "reqwest 0.12.28", "rmcp", @@ -4983,7 +4837,7 @@ dependencies = [ "tabwriter", "tar", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "toml 0.9.12+spec-1.1.0", @@ -4998,29 +4852,29 @@ dependencies = [ [[package]] name = "mesh-llm-identity" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "argon2", "base64 0.22.1", "chacha20poly1305", "chrono", "crypto_box", + "daz-secrets", "dirs", "ed25519-dalek", "hex", - "keyring", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", "sha2 0.10.9", - "thiserror 2.0.18", + "thiserror 2.0.19", "zeroize", ] [[package]] name = "mesh-llm-native-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "serde", @@ -5031,7 +4885,7 @@ dependencies = [ [[package]] name = "mesh-llm-node" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-types", @@ -5045,12 +4899,12 @@ dependencies = [ [[package]] name = "mesh-llm-plugin" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", - "prost 0.14.3", - "prost-build 0.14.3", + "prost 0.14.4", + "prost-build 0.14.4", "protoc-bin-vendored", "rmcp", "schemars", @@ -5062,7 +4916,7 @@ dependencies = [ [[package]] name = "mesh-llm-plugin-manager" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5081,12 +4935,12 @@ dependencies = [ [[package]] name = "mesh-llm-protocol" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "hex", "iroh", - "prost 0.14.3", + "prost 0.14.4", "serde_json", "sha2 0.10.9", ] @@ -5094,7 +4948,7 @@ dependencies = [ [[package]] name = "mesh-llm-routing" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "iroh", ] @@ -5102,7 +4956,7 @@ dependencies = [ [[package]] name = "mesh-llm-runtime-install" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5125,7 +4979,7 @@ dependencies = [ [[package]] name = "mesh-llm-sdk" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-api-client", @@ -5140,7 +4994,7 @@ dependencies = [ [[package]] name = "mesh-llm-skills" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5151,7 +5005,7 @@ dependencies = [ [[package]] name = "mesh-llm-system" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "chrono", @@ -5174,7 +5028,7 @@ dependencies = [ [[package]] name = "mesh-llm-types" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "hex", "serde", @@ -5185,12 +5039,12 @@ dependencies = [ [[package]] name = "mesh-llm-ui" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" [[package]] name = "mesh-mixture-of-agents" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "async-trait", "mesh-llm-guardrails", @@ -5229,7 +5083,7 @@ dependencies = [ "metrics-util", "quanta", "rustls", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", ] @@ -5249,7 +5103,7 @@ dependencies = [ "ordered-float 5.3.0", "quanta", "radix_trie", - "rand 0.9.4", + "rand 0.9.5", "rand_xoshiro", "rapidhash", "sketches-ddsketch", @@ -5274,7 +5128,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5326,9 +5180,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "log", @@ -5339,7 +5193,7 @@ dependencies = [ [[package]] name = "model-artifact" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -5350,7 +5204,7 @@ dependencies = [ [[package]] name = "model-hf" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -5368,7 +5222,7 @@ dependencies = [ [[package]] name = "model-package" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "bytes", @@ -5388,7 +5242,7 @@ dependencies = [ [[package]] name = "model-ref" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "serde", ] @@ -5396,7 +5250,7 @@ dependencies = [ [[package]] name = "model-resolver" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "model-artifact", @@ -5441,7 +5295,7 @@ checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5498,7 +5352,7 @@ checksum = "e2acd8b070213b0299282f884b4beba4e7b52d624fdcd504a3ad3665390c11e1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5545,7 +5399,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "tempfile", ] @@ -5606,9 +5460,9 @@ dependencies = [ [[package]] name = "netlink-packet-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3463cbb78394cb0141e2c926b93fc2197e473394b761986eca3b9da2c63ae0f4" +checksum = "b897d7bd4f0af82e68d40d0344cf37e97f9c97ddf74a098de3e4da05e96ca395" dependencies = [ "paste", ] @@ -5619,7 +5473,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2288fcb784eb3defd5fb16f4c4160d5f477de192eac730f43e1d11c24d9a007" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "log", "netlink-packet-core", @@ -5627,16 +5481,17 @@ dependencies = [ [[package]] name = "netlink-proto" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65d130ee111430e47eed7896ea43ca693c387f097dd97376bffafbf25812128" +checksum = "e6f7398dddf5f152d2a91a2921a134c6097056e292c0d4b9906007855e7cece6" dependencies = [ "bytes", - "futures", + "futures-channel", + "futures-util", "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -5704,7 +5559,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "cfg_aliases", "libc", @@ -5717,7 +5572,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "cfg_aliases", "libc", @@ -5729,7 +5584,7 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "cfg_aliases", "libc", @@ -5747,9 +5602,9 @@ dependencies = [ [[package]] name = "noq" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf95190af1bd4a00a10e8255ca0c8ddd9e9a9f5e79151d7a7eb6d56aff5dc89" +checksum = "09e4bb6601fa543c110d8957813267d5a8d775a0f8fbaccf1f615d06ba9b10da" dependencies = [ "bytes", "cfg_aliases", @@ -5760,7 +5615,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "tracing", @@ -5769,9 +5624,9 @@ dependencies = [ [[package]] name = "noq-proto" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa6c890013591e709a3e45dd53501351b7e27e7ff3c7e9fc3dce43e300e7e9d3" +checksum = "baa7b5ccd819a9c68a0d955e67a881032d09b1a17219b1f90b0997a0888e1a15" dependencies = [ "aes-gcm", "bytes", @@ -5780,7 +5635,7 @@ dependencies = [ "getrandom 0.4.3", "identity-hash", "lru-slab", - "rand 0.10.1", + "rand 0.10.2", "rand_pcg", "ring", "rustc-hash", @@ -5788,7 +5643,7 @@ dependencies = [ "rustls-pki-types", "slab", "sorted-index-buffer", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "web-time", @@ -5796,9 +5651,9 @@ dependencies = [ [[package]] name = "noq-udp" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3137a52df66c20090a889828d1c655f21f52294cba64e5c4fbb04fc83eee7c8e" +checksum = "02bba20e097a5a16cd0ad14ec882fae1e80a092a124e9422fc4dddd92e96a647" dependencies = [ "cfg_aliases", "libc", @@ -5809,9 +5664,9 @@ dependencies = [ [[package]] name = "nostr" -version = "0.44.7" +version = "0.44.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d3d987ea7078dc36947cde532637c472a229426702e4331dd7667325378bd9" +checksum = "40ff7b77ef428b40aa2834a6acbae38a0e104c98b306208ca4b87a420d579a4b" dependencies = [ "base64 0.22.1", "bech32", @@ -5902,25 +5757,11 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -5949,7 +5790,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -5961,17 +5802,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.2" @@ -6022,7 +5852,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6043,13 +5873,24 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-foundation", +] + [[package]] name = "objc2-core-foundation" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "dispatch2", "libc", @@ -6062,7 +5903,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e34919aba0d701380d911702455038a8a3587467fe0141d6a71501e7ffe48" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -6082,7 +5923,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "libc", "objc2", @@ -6105,7 +5946,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", ] @@ -6126,7 +5967,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "libc", "objc2", @@ -6165,7 +6006,7 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openai-frontend" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "async-trait", "axum", @@ -6181,11 +6022,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.80" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "foreign-types", "libc", @@ -6201,7 +6042,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6210,24 +6051,14 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "openssl-src" -version = "300.6.0+3.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" -version = "0.9.116" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] @@ -6242,7 +6073,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", ] @@ -6256,7 +6087,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", ] @@ -6284,9 +6115,9 @@ dependencies = [ "opentelemetry-http", "opentelemetry-proto 0.31.0", "opentelemetry_sdk 0.31.0", - "prost 0.14.3", + "prost 0.14.4", "reqwest 0.12.28", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -6299,8 +6130,8 @@ dependencies = [ "opentelemetry 0.32.0", "opentelemetry-proto 0.32.0", "opentelemetry_sdk 0.32.1", - "prost 0.14.3", - "thiserror 2.0.18", + "prost 0.14.4", + "thiserror 2.0.19", "tokio", "tonic", "tonic-types", @@ -6316,7 +6147,7 @@ dependencies = [ "const-hex", "opentelemetry 0.31.0", "opentelemetry_sdk 0.31.0", - "prost 0.14.3", + "prost 0.14.4", "serde", "serde_json", "tonic", @@ -6331,7 +6162,7 @@ checksum = "56d658ba1faf63f7b9c492cfbe6e0ec365440a16132d3270c1065f7b33f1b638" dependencies = [ "opentelemetry 0.32.0", "opentelemetry_sdk 0.32.1", - "prost 0.14.3", + "prost 0.14.4", "tonic", "tonic-prost", ] @@ -6347,8 +6178,8 @@ dependencies = [ "futures-util", "opentelemetry 0.31.0", "percent-encoding", - "rand 0.9.4", - "thiserror 2.0.18", + "rand 0.9.5", + "thiserror 2.0.19", ] [[package]] @@ -6363,8 +6194,8 @@ dependencies = [ "opentelemetry 0.32.0", "percent-encoding", "portable-atomic", - "rand 0.9.4", - "thiserror 2.0.18", + "rand 0.9.5", + "thiserror 2.0.19", "tokio", "tokio-stream", ] @@ -6412,16 +6243,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "ort" version = "2.0.0-rc.12" @@ -6464,26 +6285,35 @@ dependencies = [ [[package]] name = "palette" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" dependencies = [ "approx", - "fast-srgb8", "libm", "palette_derive", + "palette_math", ] [[package]] name = "palette_derive" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", +] + +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" +dependencies = [ + "libm", ] [[package]] @@ -6591,9 +6421,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" +checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" dependencies = [ "memchr", "ucd-trie", @@ -6601,9 +6431,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" +checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd" dependencies = [ "pest", "pest_generator", @@ -6611,22 +6441,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" +checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "pest_meta" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" +checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c" dependencies = [ "pest", ] @@ -6689,7 +6519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.6", + "rand 0.8.7", ] [[package]] @@ -6702,7 +6532,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6731,7 +6561,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6740,17 +6570,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "piper" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - [[package]] name = "pkcs8" version = "0.11.0" @@ -6769,13 +6588,13 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plist" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" dependencies = [ "base64 0.22.1", "indexmap", - "quick-xml 0.39.4", + "quick-xml 0.41.0", "serde", "time", ] @@ -6786,27 +6605,13 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crc32fast", "fdeflate", "flate2", "miniz_oxide", ] -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if 1.0.4", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix 1.1.4", - "windows-sys 0.61.2", -] - [[package]] name = "poly1305" version = "0.8.0" @@ -6832,9 +6637,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" dependencies = [ "serde", ] @@ -6865,7 +6670,7 @@ dependencies = [ "n0-future", "netwatch", "num_enum", - "rand 0.10.1", + "rand 0.10.2", "serde", "smallvec", "socket2", @@ -6898,7 +6703,7 @@ checksum = "e0232bd009a197ceec9cc881ba46f727fcd8060a2d8d6a9dde7a69030a6fe2bb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6943,7 +6748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -6984,9 +6789,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -7013,9 +6818,9 @@ checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set 0.8.0", "bit-vec 0.8.0", - "bitflags 2.13.0", + "bitflags 2.13.1", "num-traits", - "rand 0.9.4", + "rand 0.9.5", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -7036,12 +6841,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", - "prost-derive 0.14.3", + "prost-derive 0.14.4", ] [[package]] @@ -7060,15 +6865,15 @@ dependencies = [ "prost 0.13.5", "prost-types 0.13.5", "regex", - "syn 2.0.117", + "syn 2.0.119", "tempfile", ] [[package]] name = "prost-build" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" +checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" dependencies = [ "heck", "itertools", @@ -7076,10 +6881,10 @@ dependencies = [ "multimap", "petgraph 0.8.3", "prettyplease", - "prost 0.14.3", - "prost-types 0.14.3", + "prost 0.14.4", + "prost-types 0.14.4", "regex", - "syn 2.0.117", + "syn 2.0.119", "tempfile", ] @@ -7093,20 +6898,20 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "prost-derive" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -7133,11 +6938,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ - "prost 0.14.3", + "prost 0.14.4", ] [[package]] @@ -7237,7 +7042,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "memchr", "pulldown-cmark-escape", "unicase", @@ -7251,9 +7056,9 @@ checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] name = "pxfm" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" [[package]] name = "quanta" @@ -7294,18 +7099,18 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.39.4" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", @@ -7315,7 +7120,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "web-time", @@ -7331,14 +7136,14 @@ dependencies = [ "bytes", "getrandom 0.4.3", "lru-slab", - "rand 0.10.1", + "rand 0.10.2", "rand_pcg", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "web-time", @@ -7346,23 +7151,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -7391,9 +7196,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -7402,9 +7207,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -7412,11 +7217,11 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ - "chacha20 0.10.0", + "chacha20 0.10.1", "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -7494,9 +7299,9 @@ dependencies = [ [[package]] name = "rapidhash" -version = "4.4.2" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b266a82f4aa99bb5c25e28d11cc44ace63d91adbcbcee4d323e2ae3d49ef37" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" dependencies = [ "rustversion", ] @@ -7523,17 +7328,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "compact_str 0.9.1", "critical-section", "hashbrown 0.17.1", "itertools", "kasuari", - "lru 0.18.0", + "lru 0.18.2", "palette", "serde", "strum", - "thiserror 2.0.18", + "thiserror 2.0.19", "unicode-segmentation", "unicode-truncate", "unicode-width 0.2.2", @@ -7588,7 +7393,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "hashbrown 0.17.1", "indoc", "instability", @@ -7608,7 +7413,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -7659,9 +7464,9 @@ dependencies = [ [[package]] name = "redis" -version = "1.2.4" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae41a63fd0b8a5372f82b21e810e09a316f5dd7efd96bf08e678fb240fc1918" +checksum = "3257df217f7eab0044627a268c9cc6cdb60c0c421c88f83ac41c4e31520b6b84" dependencies = [ "arc-swap", "arcstr", @@ -7694,7 +7499,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -7705,34 +7510,34 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -7742,9 +7547,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -7759,9 +7564,9 @@ checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" @@ -7808,7 +7613,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams 0.4.2", "web-sys", - "webpki-roots 1.0.7", + "webpki-roots 1.0.9", ] [[package]] @@ -7866,7 +7671,7 @@ dependencies = [ "async-trait", "http", "reqwest 0.13.4", - "thiserror 2.0.18", + "thiserror 2.0.19", "tower-service", ] @@ -7917,14 +7722,14 @@ dependencies = [ "pastey", "pin-project-lite", "process-wrap", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "rmcp-macros", "schemars", "serde", "serde_json", "sse-stream", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "tokio-util", @@ -7943,7 +7748,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -7994,7 +7799,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "sysinfo 0.37.2", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "tokio", "tokio-stream", @@ -8003,9 +7808,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -8022,7 +7827,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -8035,7 +7840,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -8044,9 +7849,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.42" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "aws-lc-rs", "log", @@ -8060,21 +7865,21 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.7.0", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "web-time", "zeroize", @@ -8095,7 +7900,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -8121,9 +7926,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rusty-fork" @@ -8197,9 +8002,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" dependencies = [ "chrono", "dyn-clone", @@ -8211,14 +8016,14 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -8265,7 +8070,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "rand 0.8.6", + "rand 0.8.7", "secp256k1-sys 0.10.1", "serde", ] @@ -8277,7 +8082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" dependencies = [ "bitcoin_hashes", - "rand 0.9.4", + "rand 0.9.5", "secp256k1-sys 0.11.0", ] @@ -8308,45 +8113,13 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secret-service" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4" -dependencies = [ - "aes", - "cbc", - "futures-util", - "generic-array", - "hkdf 0.12.4", - "num", - "once_cell", - "rand 0.8.6", - "serde", - "sha2 0.10.9", - "zbus", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.13.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -8399,9 +8172,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -8429,40 +8202,40 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "serde_derive_internals" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -8484,13 +8257,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -8539,9 +8312,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.2.17", @@ -8574,7 +8347,6 @@ dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.2.17", "digest 0.10.7", - "sha2-asm", ] [[package]] @@ -8588,15 +8360,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha2-asm" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" -dependencies = [ - "cc", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -8641,9 +8404,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" @@ -8688,15 +8451,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -8710,9 +8473,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d93e861ede2e497b47833469b8ec9d5c07fa4c78ce7a00f6eb7dd8168b4b3f" +checksum = "85ee016af5d736b69fc89e19254540fa4b5f5492853fb5503920f084011c78b6" dependencies = [ "bstr", ] @@ -8723,7 +8486,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -8741,7 +8504,7 @@ checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" [[package]] name = "skippy-cache" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "blake3", @@ -8751,15 +8514,15 @@ dependencies = [ [[package]] name = "skippy-coordinator" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "skippy-ffi" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "libloading", ] @@ -8767,15 +8530,15 @@ dependencies = [ [[package]] name = "skippy-metrics" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" [[package]] name = "skippy-protocol" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ - "prost 0.14.3", - "prost-build 0.14.3", + "prost 0.14.4", + "prost-build 0.14.4", "protoc-bin-vendored", "serde", ] @@ -8783,7 +8546,7 @@ dependencies = [ [[package]] name = "skippy-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "libc", @@ -8797,7 +8560,7 @@ dependencies = [ [[package]] name = "skippy-server" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "ahash", "anyhow", @@ -8826,7 +8589,7 @@ dependencies = [ [[package]] name = "skippy-topology" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "serde", "serde_json", @@ -8840,9 +8603,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" dependencies = [ "serde", ] @@ -8860,9 +8623,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -8882,23 +8645,23 @@ checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "spin" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" dependencies = [ "lock_api", ] [[package]] name = "spin" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" [[package]] name = "spki" @@ -8973,13 +8736,13 @@ dependencies = [ "serde_json", "sha2 0.10.9", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "tracing", "url", "uuid", - "webpki-roots 1.0.7", + "webpki-roots 1.0.9", ] [[package]] @@ -8992,7 +8755,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -9015,8 +8778,8 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.117", - "thiserror 2.0.18", + "syn 2.0.119", + "thiserror 2.0.19", "tokio", "url", ] @@ -9027,7 +8790,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "byteorder", "bytes", "chrono", @@ -9044,7 +8807,7 @@ dependencies = [ "sha1 0.11.0", "sha2 0.11.0", "sqlx-core", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", "uuid", ] @@ -9057,7 +8820,7 @@ checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" dependencies = [ "atoi", "base64 0.22.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "byteorder", "chrono", "crc", @@ -9067,20 +8830,20 @@ dependencies = [ "futures-core", "futures-util", "hex", - "hkdf 0.13.0", + "hkdf", "hmac 0.13.0", "itoa", "log", "md-5", "memchr", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", "sha2 0.11.0", "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", "uuid", "whoami", @@ -9106,7 +8869,7 @@ dependencies = [ "percent-encoding", "serde", "sqlx-core", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", "url", "uuid", @@ -9114,9 +8877,9 @@ dependencies = [ [[package]] name = "sse-stream" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3962b63f038885f15bce2c6e02c0e7925c072f1ac86bb60fd44c5c6b762fb72" +checksum = "c123f296ade4ec4b8b0f6162116e6629f5146922ca5ab40ca9d3c2e73ab4761e" dependencies = [ "bytes", "futures-util", @@ -9182,7 +8945,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -9368,9 +9131,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -9394,7 +9168,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -9431,7 +9205,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -9491,7 +9265,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "parking_lot", "rustix 1.1.4", "signal-hook", @@ -9527,7 +9301,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64 0.22.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "fancy-regex 0.11.0", "filedescriptor", "finl_unicode", @@ -9572,11 +9346,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.19", ] [[package]] @@ -9587,37 +9361,36 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if 1.0.4", ] [[package]] name = "time" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "js-sys", "libc", "num-conv", @@ -9630,15 +9403,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -9665,9 +9438,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" dependencies = [ "tinyvec_macros", ] @@ -9697,7 +9470,7 @@ dependencies = [ "macro_rules_attribute", "monostate", "paste", - "rand 0.9.4", + "rand 0.9.5", "rayon", "rayon-cond", "regex", @@ -9705,7 +9478,7 @@ dependencies = [ "serde", "serde_json", "spm_precompiled", - "thiserror 2.0.18", + "thiserror 2.0.19", "unicode-normalization-alignments", "unicode-segmentation", "unicode_categories", @@ -9713,9 +9486,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.52.3" +version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ "bytes", "libc", @@ -9730,13 +9503,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 3.0.3", ] [[package]] @@ -9751,12 +9524,12 @@ dependencies = [ [[package]] name = "tokio-retry" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40f644c762e9d396831ae2f8935c954b0d758c4532e924bead0f666d0c1c8640" +checksum = "4a129d95275ebf4c493ec53bf0f8cd95f5ac161bc4f381700809a54f595d4470" dependencies = [ "pin-project-lite", - "rand 0.10.1", + "rand 0.10.2", "tokio", ] @@ -9784,9 +9557,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" dependencies = [ "futures-core", "pin-project-lite", @@ -9828,23 +9601,24 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" dependencies = [ "bytes", "futures-core", "futures-sink", "futures-util", + "libc", "pin-project-lite", "tokio", ] [[package]] name = "tokio-websockets" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad543404f98bfc969aeb71994105c592acfc6c43323fddcd016bb208d1c65cb" +checksum = "d52efb639344a7c6adb8e62c6f3d2c19c001ff1b79a5041ba1c6ed42e19c6aa5" dependencies = [ "base64 0.22.1", "bytes", @@ -9853,7 +9627,7 @@ dependencies = [ "getrandom 0.4.3", "http", "httparse", - "rand 0.10.1", + "rand 0.10.2", "ring", "rustls-pki-types", "sha1_smol", @@ -9863,6 +9637,30 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio_with_wasm" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34e40fbbbd95441133fe9483f522db15dbfd26dc636164ebd8f2dd28759a6aa6" +dependencies = [ + "js-sys", + "tokio", + "tokio_with_wasm_proc", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "tokio_with_wasm_proc" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d01145a2c788d6aae4cd653afec1e8332534d7d783d01897cefcafe4428de992" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "toml" version = "0.9.12+spec-1.1.0" @@ -9880,9 +9678,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap", "serde_core", @@ -9890,7 +9688,7 @@ dependencies = [ "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -9913,31 +9711,31 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap", "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tonic" @@ -9976,7 +9774,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" dependencies = [ "bytes", - "prost 0.14.3", + "prost 0.14.4", "tonic", ] @@ -9986,8 +9784,8 @@ version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ab1b02061f83d519bba3caa167f88f261ef05720ab8ebc954ade70de3348e8" dependencies = [ - "prost 0.14.3", - "prost-types 0.14.3", + "prost 0.14.4", + "prost-types 0.14.4", "tonic", ] @@ -10018,7 +9816,7 @@ checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", "base64 0.22.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "bytes", "futures-core", "futures-util", @@ -10072,7 +9870,7 @@ checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", "symlink", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "tracing-subscriber", ] @@ -10085,7 +9883,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -10173,11 +9971,11 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.4", + "rand 0.9.5", "rustls", "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.18", + "sha1 0.10.7", + "thiserror 2.0.19", "utf-8", ] @@ -10192,24 +9990,24 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.4", + "rand 0.9.5", "rustls", "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.18", + "sha1 0.10.7", + "thiserror 2.0.19", ] [[package]] name = "twox-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +checksum = "8464ec13c3691491391d9fce00f6416c9a48e46972f72d7865688be2080192c9" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "typewit" @@ -10223,24 +10021,13 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "uds_windows" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" -dependencies = [ - "memoffset", - "tempfile", - "windows-sys 0.61.2", -] - [[package]] name = "ulid" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" dependencies = [ - "rand 0.9.4", + "rand 0.9.5", "web-time", ] @@ -10294,9 +10081,9 @@ checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" @@ -10410,9 +10197,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" dependencies = [ "atomic", "getrandom 0.4.3", @@ -10433,43 +10220,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vergen" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "vergen-lib", -] - -[[package]] -name = "vergen-gitcl" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff3b5300a085d6bcd8fc96a507f706a28ae3814693236c9b409db71a1d15b9" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "time", - "vergen", - "vergen-lib", -] - -[[package]] -name = "vergen-lib" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", -] - [[package]] name = "version_check" version = "0.9.5" @@ -10530,9 +10280,9 @@ dependencies = [ [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] @@ -10548,9 +10298,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if 1.0.4", "once_cell", @@ -10561,9 +10311,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.71" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ "js-sys", "wasm-bindgen", @@ -10571,9 +10321,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10581,22 +10331,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] @@ -10629,9 +10379,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.98" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -10649,15 +10399,15 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.2.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" +checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" dependencies = [ - "core-foundation 0.10.1", "jni 0.22.4", "log", "ndk-context", "objc2", + "objc2-app-kit", "objc2-foundation", "url", "web-sys", @@ -10665,9 +10415,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" dependencies = [ "rustls-pki-types", ] @@ -10678,14 +10428,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.7", + "webpki-roots 1.0.9", ] [[package]] name = "webpki-roots" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -10917,7 +10667,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -10928,7 +10678,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -10963,6 +10713,16 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-permissions" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2ccdc3c6bf4d4a094e031b63fadd08d8e42abd259940eb8aa5fdc09d4bf9be" +dependencies = [ + "bitflags 1.3.2", + "winapi", +] + [[package]] name = "windows-registry" version = "0.6.1" @@ -11270,9 +11030,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -11293,7 +11053,7 @@ dependencies = [ "futures", "log", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows 0.62.2", "windows-core 0.62.2", ] @@ -11328,7 +11088,7 @@ dependencies = [ "pharos", "rustc_version", "send_wrapper", - "thiserror 2.0.18", + "thiserror 2.0.19", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -11344,34 +11104,22 @@ dependencies = [ "rustix 1.1.4", ] -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "xet-client" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e1e496dcbe6a09017acdfaf48e1a646735e7ff5b2a49e2c7e081cca77a59bc8" +checksum = "c3b8da8cc70aa2e3c500c0400e012df82c656ab9fca47f9f939fffc5afd89aca" dependencies = [ "anyhow", "async-trait", "base64 0.22.1", "bytes", - "clap", "crc32fast", "futures", "http", "hyper", - "lazy_static", "more-asserts", - "rand 0.10.1", + "rand 0.10.2", "redb", "reqwest 0.13.4", "reqwest-middleware", @@ -11380,11 +11128,11 @@ dependencies = [ "serde_repr", "statrs", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-retry", + "tokio_with_wasm", "tracing", - "tracing-subscriber", "url", "urlencoding", "web-time", @@ -11394,33 +11142,29 @@ dependencies = [ [[package]] name = "xet-core-structures" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb838aa8eb67d730af301584cf003caad407487606058292a6750711b603fbee" +checksum = "73503c223783dccc864abde22115e09d12f190448a0baf58ab2c54bc709e2f99" dependencies = [ "async-trait", "base64 0.22.1", "blake3", "bytemuck", "bytes", - "clap", "countio", - "csv", "futures", "futures-util", "getrandom 0.4.3", "heapify", "itertools", - "lazy_static", "lz4_flex", "more-asserts", - "rand 0.10.1", + "rand 0.10.2", "regex", "safe-transmute", "serde", "static_assertions", - "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tracing", @@ -11431,32 +11175,31 @@ dependencies = [ [[package]] name = "xet-data" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fd409bef621411a9d9013798540bb8036cb2678f03ab39af89a5e88034ed8c" +checksum = "c89052ec5dec2187cad30b86af92cc24fd61c4a57a795f1ff7ff5f38d49184eb" dependencies = [ "anyhow", "async-trait", "bytes", "chrono", - "clap", "gearhash", "http", "itertools", - "lazy_static", "more-asserts", - "rand 0.10.1", + "rand 0.10.2", "serde", "serde_json", - "sha2 0.10.9", + "sha2 0.11.0", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", + "tokio_with_wasm", "tracing", "url", "uuid", - "walkdir", + "web-time", "xet-client", "xet-core-structures", "xet-runtime", @@ -11464,9 +11207,9 @@ dependencies = [ [[package]] name = "xet-runtime" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d8f121c33866f7648b737abe70d0e2dd9c0af4ffdd7219207531d0283aa63d" +checksum = "af5c60d5eed38ab4c576f4421bae835e7bd07631fb381705605529d2015c106b" dependencies = [ "anyhow", "async-trait", @@ -11480,23 +11223,24 @@ dependencies = [ "git-version", "humantime", "konst", - "lazy_static", "libc", "more-asserts", "oneshot", "pin-project", - "rand 0.10.1", + "rand 0.10.2", "reqwest 0.13.4", "serde", "serde_json", "shellexpand", "sysinfo 0.38.4", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", + "tokio_with_wasm", "tracing", "tracing-appender", "tracing-subscriber", + "web-time", "whoami", "winapi", ] @@ -11518,15 +11262,15 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.15" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" +checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -11541,84 +11285,28 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "synstructure", ] -[[package]] -name = "zbus" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" -dependencies = [ - "async-broadcast", - "async-process", - "async-recursion", - "async-trait", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix 0.29.0", - "ordered-stream", - "rand 0.8.6", - "serde", - "serde_repr", - "sha1 0.10.6", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.117", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -11638,7 +11326,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", "synstructure", ] @@ -11659,7 +11347,7 @@ checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -11692,7 +11380,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.119", ] [[package]] @@ -11708,15 +11396,15 @@ dependencies = [ "flate2", "indexmap", "memchr", - "thiserror 2.0.18", + "thiserror 2.0.19", "zopfli", ] [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zopfli" @@ -11744,40 +11432,3 @@ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core", ] - -[[package]] -name = "zvariant" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.117", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] diff --git a/Cargo.toml b/Cargo.toml index cc1dd0f9df..f99f96d602 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ repository = "https://github.com/block/sprout" # Runtime tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "time", "sync", "io-util", "signal", "process"] } tokio-util = { version = "0.7", features = ["rt", "codec"] } +daz-secrets = { git = "https://github.com/darrenoakey/daz-secrets", rev = "ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa" } # HTTP + WebSocket axum = { version = "0.8", features = ["ws", "macros"] } diff --git a/Justfile b/Justfile index c3d755ffeb..05119aef7d 100644 --- a/Justfile +++ b/Justfile @@ -935,20 +935,20 @@ _release-pr lane version: # ─── Agent Harness ──────────────────────────────────────────────────────────── # Run a goose agent connected to a Buzz relay (foreground) -goose relay="ws://localhost:3000" agents="1" heartbeat="0" prompt="" key="$BUZZ_PRIVATE_KEY": +goose relay="ws://localhost:3000" agents="1" heartbeat="0" prompt="" service="buzz-desktop" account="identity": #!/usr/bin/env bash set -euo pipefail export PATH="{{justfile_directory()}}/bin:$PATH" - source ./scripts/_goose-env.sh "{{relay}}" "{{key}}" "{{agents}}" "{{heartbeat}}" "{{prompt}}" - exec env "${env_args[@]}" ./target/release/buzz-acp + source ./scripts/_goose-env.sh "{{relay}}" "{{service}}" "{{account}}" "{{agents}}" "{{heartbeat}}" "{{prompt}}" + exec env "${env_args[@]}" ./target/release/buzz-acp "${acp_args[@]}" # Run a goose agent in the background (screen session named 'goose-agent-N') -goose-bg relay="ws://localhost:3000" agents="1" heartbeat="0" prompt="" key="$BUZZ_PRIVATE_KEY": +goose-bg relay="ws://localhost:3000" agents="1" heartbeat="0" prompt="" service="buzz-desktop" account="identity": #!/usr/bin/env bash set -euo pipefail export PATH="{{justfile_directory()}}/bin:$PATH" - source ./scripts/_goose-env.sh "{{relay}}" "{{key}}" "{{agents}}" "{{heartbeat}}" "{{prompt}}" - screen -dmS goose-agent-{{agents}} bash -c "$(printf '%q ' env "${env_args[@]}") ./target/release/buzz-acp" + source ./scripts/_goose-env.sh "{{relay}}" "{{service}}" "{{account}}" "{{agents}}" "{{heartbeat}}" "{{prompt}}" + screen -dmS goose-agent-{{agents}} bash -c "$(printf '%q ' env "${env_args[@]}") ./target/release/buzz-acp $(printf '%q ' "${acp_args[@]}")" echo "Agent running in screen session 'goose-agent-{{agents}}'. Attach with: screen -r goose-agent-{{agents}}" # ─── Benchmarking ───────────────────────────────────────────────────────────── diff --git a/README.md b/README.md index 56439f00bc..fa3c54ba49 100644 --- a/README.md +++ b/README.md @@ -177,7 +177,11 @@ For a split-terminal workflow (relay logs separate from Vite output), use `just Want a single-node / VPS relay instead of the local-dev stack? Use the production Compose bundle in [`deploy/compose/`](deploy/compose/README.md) (`docker compose` + Postgres, Redis, MinIO, optional Caddy/TLS). The root [`docker-compose.yml`](docker-compose.yml) is for day-to-day development only. -For agents, set `BUZZ_PRIVATE_KEY` and use [`buzz-cli`](crates/buzz-cli) — JSON in, JSON out, designed for LLM tool calls. +For agents, store the identity with `daz-secrets` and use +[`buzz-cli`](crates/buzz-cli) — JSON in, JSON out, designed for LLM tool calls. +The CLI defaults to `buzz-desktop/identity`; `--secret-service` and +`--secret-account` select a different provider entry without exposing secret +bytes through argv or the environment. --- diff --git a/SECURITY.md b/SECURITY.md index 09ea73022b..419705bc24 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -73,24 +73,27 @@ accidental corruption or single-row edits, but an attacker with database write access can recompute the entire chain after editing. The audit log is designed for SOX-grade compliance and eDiscovery. -### Desktop Secret Storage — OS Keyring - -The Buzz desktop app stores nsec private keys in the operating system keyring -rather than in plaintext files: macOS Keychain, Windows Credential Manager, or -the Linux Secret Service (`gnome-keyring` / `kwallet` via D-Bus). This covers -both the human identity key and every managed-agent key. - -On first launch after upgrading, existing plaintext keys are migrated into the -keyring: the key is imported, read back to verify the round-trip, and only then -is the plaintext deleted. Migration runs only when the keyring is reachable — -if the backend is unavailable that session, the app keeps reading from the -plaintext file and does **not** migrate, so a transient outage cannot resurrect -a rotated key from a leftover file. - -When no keyring backend is available (headless Linux with no Secret Service, for -example), keys fall back to a `0o600` owner-only file. The `BUZZ_PRIVATE_KEY` -environment variable, when set, always takes precedence over both stores — this -is how harnessed agents and CI receive their identity. +### Desktop Secret Storage — Process-Isolated Provider + +Buzz stores human and managed-agent nsec keys through the public `daz-secrets` +provider protocol. The desktop process never calls macOS Keychain, Windows +Credential Manager, or Linux Secret Service directly, so rebuilds and signing +identity changes cannot trigger credential prompts. Secret bytes travel over +anonymous child-process pipes and are never placed in command arguments or the +process environment. + +The provider is selected by the current OS account's owner-only +`~/.config/daz-secrets/provider.toml`. A private encrypted provider can remain +machine-local while the Buzz and `daz-secrets` client code stays public. Other +installations may select a conforming provider, including an optional OS-keyring +adapter. Provider errors fail closed; Buzz does not create a plaintext or +environment-variable fallback. + +On first launch after upgrading, an existing legacy `identity.key` is written +to the provider, read back for an exact round-trip verification, and only then +deleted. Platform-keyring entries are migrated separately by the one-time +operator tool, because touching those entries from a rebuilt app could itself +display authentication UI. ### Input Validation diff --git a/crates/buzz-acp/Cargo.toml b/crates/buzz-acp/Cargo.toml index d047849806..732831d986 100644 --- a/crates/buzz-acp/Cargo.toml +++ b/crates/buzz-acp/Cargo.toml @@ -20,6 +20,7 @@ path = "src/main.rs" buzz-core = { workspace = true } buzz-sdk = { workspace = true } buzz-persona = { path = "../buzz-persona" } +daz-secrets = { workspace = true } # Nostr nostr = { workspace = true } @@ -61,6 +62,7 @@ tracing-subscriber = { workspace = true } # Error handling thiserror = { workspace = true } anyhow = { workspace = true } +zeroize = { workspace = true } # CLI clap = { version = "4", features = ["derive", "env"] } diff --git a/crates/buzz-acp/README.md b/crates/buzz-acp/README.md index e6164b02dd..2faa3741fe 100644 --- a/crates/buzz-acp/README.md +++ b/crates/buzz-acp/README.md @@ -31,16 +31,20 @@ Each agent needs a Nostr keypair — this is the agent's identity in Buzz. Use ` cargo run -p buzz-admin -- generate-key ``` -This prints a public and secret key pair as hex. **Save the secret key immediately — it is not stored and cannot be recovered.** Set `BUZZ_PRIVATE_KEY` to the secret key to act as this identity. +This stores the new identity in the configured `daz-secrets` provider and +prints only its public key. It refuses to overwrite an existing entry. Use +`--secret-service` / `--secret-account` to select a non-default entry. Then register the agent's public key as a relay member so it can read and publish: ```bash -BUZZ_RELAY_PRIVATE_KEY= \ - cargo run -p buzz-admin -- add-member --pubkey +cargo run -p buzz-admin -- \ + --secret-service buzz-relay --secret-account identity \ + add-member --pubkey ``` -`add-member` publishes a kind:13534 membership event, so the relay needs a stable signing key: set `BUZZ_RELAY_PRIVATE_KEY` in the relay's environment (uncomment it in `.env`) and restart the relay before running this. +`add-member` publishes a kind:13534 membership event, so the selected provider +entry must contain the relay's stable signing identity. > **Running multiple agents?** Mint a separate keypair for each. Every agent needs its own identity. @@ -55,11 +59,10 @@ By default, the harness discovers only channels the agent is a **member** of (`G ## Quick Start (goose) ```bash -export BUZZ_PRIVATE_KEY="nsec1..." # your agent's key (see "Generating Keys") export BUZZ_RELAY_URL="ws://localhost:3000" export GOOSE_MODE=auto -buzz-acp +buzz-acp --secret-service buzz-desktop --secret-account identity ``` That's it. The harness spawns `goose acp`, connects to the relay, discovers channels, and starts listening. When someone @mentions the agent, goose receives the message and can reply using the Buzz CLI that the harness configures automatically. @@ -106,7 +109,8 @@ All configuration is via environment variables (or CLI flags — every env var h | Variable | Required | Default | Description | |----------|----------|---------|-------------| -| `BUZZ_PRIVATE_KEY` | **yes** | — | Agent's Nostr private key (`nsec1...`). Used for relay auth and agent identity. | +| `--secret-service` | no | `buzz-desktop` | `daz-secrets` service containing the agent identity. | +| `--secret-account` | no | `identity` | `daz-secrets` account containing the agent identity. | | `BUZZ_RELAY_URL` | no | `ws://localhost:3000` | Relay WebSocket URL. | | `BUZZ_ACP_AGENT_COMMAND` | no | `goose` | Agent binary to spawn. | | `BUZZ_ACP_AGENT_ARGS` | no | `acp` | Agent arguments (comma-separated). | diff --git a/crates/buzz-acp/src/acp.rs b/crates/buzz-acp/src/acp.rs index 93109fa94d..69e3b077cd 100644 --- a/crates/buzz-acp/src/acp.rs +++ b/crates/buzz-acp/src/acp.rs @@ -2469,16 +2469,10 @@ mod tests { name: "test-mcp".into(), command: "/usr/local/bin/test-mcp-server".into(), args: vec![], - env: vec![ - EnvVar { - name: "BUZZ_RELAY_URL".into(), - value: "ws://localhost:3000".into(), - }, - EnvVar { - name: "BUZZ_PRIVATE_KEY".into(), - value: "nsec1abc".into(), - }, - ], + env: vec![EnvVar { + name: "BUZZ_RELAY_URL".into(), + value: "ws://localhost:3000".into(), + }], }; let serialized = serde_json::to_value(&server).unwrap(); assert_eq!(serialized["name"].as_str(), Some("test-mcp")); @@ -2489,7 +2483,7 @@ mod tests { assert!(serialized["args"].is_array()); assert_eq!(serialized["args"].as_array().unwrap().len(), 0); assert!(serialized["env"].is_array()); - assert_eq!(serialized["env"].as_array().unwrap().len(), 2); + assert_eq!(serialized["env"].as_array().unwrap().len(), 1); assert_eq!( serialized["env"][0]["name"].as_str(), Some("BUZZ_RELAY_URL") diff --git a/crates/buzz-acp/src/base_prompt.md b/crates/buzz-acp/src/base_prompt.md index 1d85221f11..9270412d39 100644 --- a/crates/buzz-acp/src/base_prompt.md +++ b/crates/buzz-acp/src/base_prompt.md @@ -8,7 +8,7 @@ When a human references work "you" are doing in another channel, that work belon ## Buzz CLI -The `buzz` CLI is your primary interface. Auth env vars: `BUZZ_RELAY_URL`, `BUZZ_PRIVATE_KEY`, `BUZZ_AUTH_TAG`. Exit codes: 0 ok, 1 user error, 2 network, 3 auth, 4 other. Output is structured JSON. +The `buzz` CLI is your primary interface. Its identity is supplied by the configured local secret provider; never request, read, print, or copy private key material. Exit codes: 0 ok, 1 user error, 2 network, 3 auth, 4 other. Output is structured JSON. | Group | Key commands | |-------|-------------| diff --git a/crates/buzz-acp/src/config.rs b/crates/buzz-acp/src/config.rs index d959685846..ef87be364e 100644 --- a/crates/buzz-acp/src/config.rs +++ b/crates/buzz-acp/src/config.rs @@ -45,6 +45,9 @@ pub enum ConfigError { #[error("config file error: {0}")] ConfigFile(String), + + #[error("secret provider unavailable")] + SecretProvider, } #[derive(Debug, Clone, PartialEq, clap::ValueEnum)] @@ -235,8 +238,13 @@ pub struct CliArgs { #[arg(long, env = "BUZZ_RELAY_URL", default_value = "ws://localhost:3000")] pub relay_url: String, - #[arg(long, env = "BUZZ_PRIVATE_KEY", hide_env_values = true)] - pub private_key: String, + /// daz-secrets service containing the harness identity. + #[arg(long, default_value = "buzz-desktop")] + pub secret_service: String, + + /// daz-secrets account containing the harness identity. + #[arg(long, default_value = "identity")] + pub secret_account: String, /// Agent owner pubkey (64-char hex). Used for --respond-to=owner-only gate. #[arg(long, env = "BUZZ_ACP_AGENT_OWNER")] @@ -490,6 +498,10 @@ pub struct ChannelFilter { #[derive(Debug)] pub struct Config { pub keys: Keys, + /// Non-secret daz-secrets coordinates for child tools that need the same + /// identity. The secret itself is never forwarded through argv or env. + pub secret_service: String, + pub secret_account: String, pub relay_url: String, pub agent_command: String, pub agent_args: Vec, @@ -798,7 +810,7 @@ pub fn normalize_agent_args(command: &str, agent_args: Vec) -> Vec) -> Vec Result { - let keys = Keys::parse(&args.private_key)?; - // Best-effort zeroize: overwrite the raw private key string to reduce - // exposure via core dumps or heap inspection (#41). Without the `zeroize` - // crate we can only clear the String — the allocator may retain copies. - args.private_key - .replace_range(.., &"0".repeat(args.private_key.len())); - args.private_key.clear(); - + pub fn from_args(args: CliArgs) -> Result { + let client = daz_secrets::BlockingClient::from_default_config() + .map_err(|_| ConfigError::SecretProvider)?; + let secret = client + .get(&args.secret_service, &args.secret_account) + .map_err(|_| ConfigError::SecretProvider)?; + let secret_value = zeroize::Zeroizing::new(secret.value); + let encoded = + std::str::from_utf8(&secret_value).map_err(|_| ConfigError::SecretProvider)?; + let keys = Keys::parse(encoded.trim())?; + Self::from_args_with_keys(args, keys) + } + + fn from_args_with_keys(args: CliArgs, keys: Keys) -> Result { let system_prompt = if let Some(text) = args.system_prompt { Some(text) } else if let Some(ref path) = args.system_prompt_file { @@ -1056,6 +1070,8 @@ impl Config { let config = Config { keys, + secret_service: args.secret_service, + secret_account: args.secret_account, relay_url: args.relay_url, agent_command, agent_args, @@ -1435,6 +1451,8 @@ mod tests { fn test_config(mode: SubscribeMode) -> Config { Config { keys: nostr::Keys::generate(), + secret_service: "buzz-test".into(), + secret_account: "identity".into(), relay_url: "ws://localhost:3000".into(), agent_command: "goose".into(), agent_args: vec!["acp".into()], @@ -2188,16 +2206,14 @@ channels = "ALL" #[test] fn lazy_pool_defaults_off() { - let key = "0".repeat(64); - assert!(!CliArgs::parse_from(["buzz-acp", "--private-key", &key]).lazy_pool); + assert!(!CliArgs::parse_from(["buzz-acp"]).lazy_pool); } #[test] fn lazy_pool_cli_flag_enables_deferred_startup() { - let key = "0".repeat(64); - let args = CliArgs::try_parse_from(["buzz-acp", "--private-key", &key, "--lazy-pool=true"]); + let args = CliArgs::try_parse_from(["buzz-acp", "--lazy-pool=true"]); assert!(args.is_err(), "bool flags do not take an explicit value"); - assert!(CliArgs::parse_from(["buzz-acp", "--private-key", &key, "--lazy-pool"]).lazy_pool); + assert!(CliArgs::parse_from(["buzz-acp", "--lazy-pool"]).lazy_pool); } #[test] @@ -2552,7 +2568,7 @@ channels = "ALL" fn test_multiple_event_handling_default_is_steer() { // Parse a minimal arg set; the default for --multiple-event-handling // must be `steer` (steering is the default mid-turn delivery path). - let args = CliArgs::parse_from(["buzz-acp", "--private-key", &"0".repeat(64)]); + let args = CliArgs::parse_from(["buzz-acp"]); assert_eq!(args.multiple_event_handling, MultipleEventHandling::Steer); // Dedup default must remain `queue` so steering's requirement is met. assert!(matches!(args.dedup, DedupMode::Queue)); @@ -2733,7 +2749,7 @@ channels = "ALL" // std::env::set_var to avoid test-parallelism races on shared env state. // The env-var wiring is covered by the clap #[arg(env)] attribute itself. - // A minimal valid private key for test use (secp256k1 scalar = 1). + // A minimal valid private key for exercising post-provider validation. const TEST_PRIVATE_KEY: &str = "0000000000000000000000000000000000000000000000000000000000000001"; @@ -2742,15 +2758,13 @@ channels = "ALL" // --allowed-respond-to=owner-only,allowlist + --respond-to=anyone → ConfigError let args = CliArgs::try_parse_from([ "buzz-acp", - "--private-key", - TEST_PRIVATE_KEY, "--respond-to", "anyone", "--allowed-respond-to", "owner-only,allowlist", ]) .expect("clap should parse args"); - let result = Config::from_args(args); + let result = Config::from_args_with_keys(args, Keys::parse(TEST_PRIVATE_KEY).unwrap()); assert!( result.is_err(), @@ -2772,15 +2786,13 @@ channels = "ALL" // --allowed-respond-to=owner-only,allowlist + --respond-to=owner-only → Ok let args = CliArgs::try_parse_from([ "buzz-acp", - "--private-key", - TEST_PRIVATE_KEY, "--respond-to", "owner-only", "--allowed-respond-to", "owner-only,allowlist", ]) .expect("clap should parse args"); - let result = Config::from_args(args); + let result = Config::from_args_with_keys(args, Keys::parse(TEST_PRIVATE_KEY).unwrap()); assert!( result.is_ok(), @@ -2791,15 +2803,9 @@ channels = "ALL" #[test] fn allowed_respond_to_full_path_unset_allows_all() { // No --allowed-respond-to flag → anyone is accepted. - let args = CliArgs::try_parse_from([ - "buzz-acp", - "--private-key", - TEST_PRIVATE_KEY, - "--respond-to", - "anyone", - ]) - .expect("clap should parse args"); - let result = Config::from_args(args); + let args = CliArgs::try_parse_from(["buzz-acp", "--respond-to", "anyone"]) + .expect("clap should parse args"); + let result = Config::from_args_with_keys(args, Keys::parse(TEST_PRIVATE_KEY).unwrap()); assert!( result.is_ok(), @@ -2813,13 +2819,11 @@ channels = "ALL" fn max_turn_duration_at_ceiling_is_accepted() { let args = CliArgs::try_parse_from([ "buzz-acp", - "--private-key", - TEST_PRIVATE_KEY, "--max-turn-duration", &MAX_TURN_DURATION_CEILING_SECS.to_string(), ]) .expect("clap should parse args"); - let result = Config::from_args(args); + let result = Config::from_args_with_keys(args, Keys::parse(TEST_PRIVATE_KEY).unwrap()); assert!( result.is_ok(), @@ -2830,15 +2834,9 @@ channels = "ALL" #[test] fn max_turn_duration_above_ceiling_is_rejected() { let over = MAX_TURN_DURATION_CEILING_SECS + 1; - let args = CliArgs::try_parse_from([ - "buzz-acp", - "--private-key", - TEST_PRIVATE_KEY, - "--max-turn-duration", - &over.to_string(), - ]) - .expect("clap should parse args"); - let result = Config::from_args(args); + let args = CliArgs::try_parse_from(["buzz-acp", "--max-turn-duration", &over.to_string()]) + .expect("clap should parse args"); + let result = Config::from_args_with_keys(args, Keys::parse(TEST_PRIVATE_KEY).unwrap()); assert!( result.is_err(), diff --git a/crates/buzz-acp/src/lib.rs b/crates/buzz-acp/src/lib.rs index 0c4e5f158c..2a6d7bc423 100644 --- a/crates/buzz-acp/src/lib.rs +++ b/crates/buzz-acp/src/lib.rs @@ -35,7 +35,7 @@ use config::{ }; use filter::SubscriptionRule; use futures_util::FutureExt; -use nostr::{PublicKey, ToBech32}; +use nostr::PublicKey; use pool::{ AgentPool, ControlSignal, IdleSwitchResult, OwnedAgent, PromptContext, PromptOutcome, PromptResult, PromptSource, SessionState, TimeoutKind, @@ -4288,25 +4288,17 @@ fn build_mcp_servers(config: &Config) -> Vec { .unwrap_or("mcp") .to_string(), command: config.mcp_command.clone(), - args: vec![], + args: vec![ + "--secret-service".into(), + config.secret_service.clone(), + "--secret-account".into(), + config.secret_account.clone(), + ], env: { - let mut env = vec![ - EnvVar { - name: "BUZZ_RELAY_URL".into(), - value: config.relay_url.clone(), - }, - EnvVar { - name: "BUZZ_PRIVATE_KEY".into(), - // bech32 encoding of a valid secret key is infallible. - // Panic here is correct: injecting a bogus secret would cause - // delayed, hard-to-diagnose agent failures downstream. - value: config - .keys - .secret_key() - .to_bech32() - .expect("secret key bech32 encoding should never fail"), - }, - ]; + let mut env = vec![EnvVar { + name: "BUZZ_RELAY_URL".into(), + value: config.relay_url.clone(), + }]; // Forward BUZZ_AUTH_TAG (NIP-OA owner attestation credential) // so the MCP server can attach it to every signed event. if let Ok(auth_tag) = std::env::var("BUZZ_AUTH_TAG") { @@ -5097,6 +5089,8 @@ mod build_mcp_servers_tests { fn test_config() -> Config { Config { keys: nostr::Keys::generate(), + secret_service: "buzz-test".into(), + secret_account: "identity".into(), relay_url: "ws://localhost:3000".into(), agent_command: "goose".into(), agent_args: vec!["acp".into()], @@ -5153,9 +5147,15 @@ mod build_mcp_servers_tests { names.contains(&"BUZZ_RELAY_URL"), "missing BUZZ_RELAY_URL; got {names:?}" ); - assert!( - names.contains(&"BUZZ_PRIVATE_KEY"), - "missing BUZZ_PRIVATE_KEY; got {names:?}" + assert!(!names.contains(&"BUZZ_PRIVATE_KEY")); + assert_eq!( + server.args, + [ + "--secret-service", + "buzz-test", + "--secret-account", + "identity" + ] ); } @@ -5316,6 +5316,8 @@ mod error_outcome_emission_tests { fn test_config() -> Config { Config { keys: nostr::Keys::generate(), + secret_service: "buzz-test".into(), + secret_account: "identity".into(), relay_url: "ws://localhost:3000".into(), // `true` exits cleanly, so the async respawn fails fast and // harmlessly off the JoinSet — irrelevant to the synchronous diff --git a/crates/buzz-acp/src/queue.rs b/crates/buzz-acp/src/queue.rs index 5c960de202..7301dc31c3 100644 --- a/crates/buzz-acp/src/queue.rs +++ b/crates/buzz-acp/src/queue.rs @@ -310,25 +310,21 @@ impl EventQueue { .keys() .find(|id| !self.in_flight_channels.contains(id)) .copied(); - match cancelled_id { - Some(id) => { - // Move cancelled events into the regular events slot. - // No new events to merge — re-dispatch the original batch. - let cancelled = self.cancelled_batches.remove(&id).unwrap_or_default(); - let cancel_reason = self.cancel_reasons.remove(&id); - self.in_flight_channels.insert(id); - self.in_flight_deadlines - .insert(id, now + self.in_flight_deadline); - self.in_flight_batch_sizes.insert(id, cancelled.len()); - return Some(FlushBatch { - channel_id: id, - events: cancelled, - cancelled_events: vec![], - cancel_reason, - }); - } - None => return None, - } + let id = cancelled_id?; + // Move cancelled events into the regular events slot. + // No new events to merge — re-dispatch the original batch. + let cancelled = self.cancelled_batches.remove(&id).unwrap_or_default(); + let cancel_reason = self.cancel_reasons.remove(&id); + self.in_flight_channels.insert(id); + self.in_flight_deadlines + .insert(id, now + self.in_flight_deadline); + self.in_flight_batch_sizes.insert(id, cancelled.len()); + return Some(FlushBatch { + channel_id: id, + events: cancelled, + cancelled_events: vec![], + cancel_reason, + }); } }; @@ -944,10 +940,8 @@ pub fn extract_slash_command(content: &str, known_names: &[&str]) -> Option 0).then_some(len) }); - match name_len { - Some(len) => rest = after_at[len..].trim_start(), - None => return None, // bare '@' — not a mention - } + let len = name_len?; // bare '@' is not a mention + rest = after_at[len..].trim_start(); } else { break; } diff --git a/crates/buzz-admin/Cargo.toml b/crates/buzz-admin/Cargo.toml index 7a69e146bb..6a39237d31 100644 --- a/crates/buzz-admin/Cargo.toml +++ b/crates/buzz-admin/Cargo.toml @@ -35,3 +35,5 @@ tracing = { workspace = true } sqlx = { workspace = true } url = { workspace = true } clap = { version = "4", features = ["derive"] } +daz-secrets = { workspace = true } +zeroize = { workspace = true } diff --git a/crates/buzz-admin/src/main.rs b/crates/buzz-admin/src/main.rs index bb30ddfae4..7dc9af7515 100644 --- a/crates/buzz-admin/src/main.rs +++ b/crates/buzz-admin/src/main.rs @@ -28,12 +28,20 @@ use buzz_core::tenant::{relay_url_authority, TenantContext}; use buzz_db::{Db, DbConfig}; use buzz_pubsub::{EventTopic, PubSubManager}; use clap::{Parser, Subcommand}; -use nostr::{EventBuilder, Keys, Kind, Tag}; +use nostr::{EventBuilder, Keys, Kind, Tag, ToBech32}; use tracing::warn; #[derive(Parser)] #[command(name = "buzz-admin", about = "Buzz instance administration")] struct Cli { + /// daz-secrets service containing the relay signing identity. + #[arg(long, global = true, default_value = "buzz-relay")] + secret_service: String, + + /// daz-secrets account containing the relay signing identity. + #[arg(long, global = true, default_value = "identity")] + secret_account: String, + #[command(subcommand)] command: Command, } @@ -86,13 +94,7 @@ enum Command { /// Channels created via direct SQL (seed scripts, pre-migration data) won't /// have Nostr discovery events. This command creates them so pure-nostr /// clients can see those channels. Idempotent — safe to run multiple times. - ReconcileChannels { - /// Relay private key (hex) for signing events. Falls back to - /// BUZZ_RELAY_PRIVATE_KEY env var. If neither is set, generates - /// an ephemeral key (events will be unverifiable after restart). - #[arg(long)] - relay_key: Option, - }, + ReconcileChannels, } #[derive(Subcommand)] @@ -128,12 +130,28 @@ async fn main() { } async fn run(cli: Cli) -> Result { + let secret_service = cli.secret_service; + let secret_account = cli.secret_account; match cli.command { Command::GenerateKey => { + let client = daz_secrets::BlockingClient::from_default_config() + .map_err(|_| anyhow::anyhow!("secret provider is unavailable"))?; + match client.get(&secret_service, &secret_account) { + Ok(_) => anyhow::bail!("relay identity already exists; refusing to overwrite it"), + Err(error) if error.code() == daz_secrets::ErrorCode::NotFound => {} + Err(_) => anyhow::bail!("secret provider is unavailable"), + } let keys = Keys::generate(); + let nsec = zeroize::Zeroizing::new( + keys.secret_key() + .to_bech32() + .map_err(|_| anyhow::anyhow!("failed to encode generated identity"))?, + ); + client + .set(&secret_service, &secret_account, nsec.as_bytes(), None) + .map_err(|_| anyhow::anyhow!("failed to store generated identity"))?; println!("Public key: {}", keys.public_key().to_hex()); - println!("Secret key: {}", keys.secret_key().display_secret()); - println!("\nSet BUZZ_PRIVATE_KEY to the secret key to use this identity."); + println!("Stored in secret provider: {secret_service}/{secret_account}"); Ok(0) } Command::Migrate => { @@ -142,20 +160,29 @@ async fn run(cli: Cli) -> Result { println!("Database migrations complete."); Ok(0) } - Command::AddMember { pubkey, role } => cmd_add_member(pubkey, role).await, - Command::RemoveMember { pubkey, role } => cmd_remove_member(pubkey, role).await, + Command::AddMember { pubkey, role } => { + cmd_add_member(pubkey, role, &secret_service, &secret_account).await + } + Command::RemoveMember { pubkey, role } => { + cmd_remove_member(pubkey, role, &secret_service, &secret_account).await + } Command::ListMembers => cmd_list_members().await, Command::ProductFeedback { command: ProductFeedbackCommand::List { limit }, } => cmd_list_product_feedback(limit).await, - Command::ReconcileChannels { relay_key } => { - reconcile_channels(relay_key).await?; + Command::ReconcileChannels => { + reconcile_channels(&secret_service, &secret_account).await?; Ok(0) } } } -async fn cmd_add_member(pubkey_arg: String, role: String) -> Result { +async fn cmd_add_member( + pubkey_arg: String, + role: String, + secret_service: &str, + secret_account: &str, +) -> Result { if let Err(msg) = validate_role(&role) { eprintln!("error: {msg}"); return Ok(1); @@ -169,7 +196,8 @@ async fn cmd_add_member(pubkey_arg: String, role: String) -> Result { } }; - let (db, pubsub, relay_keypair) = connect_member_services().await?; + let (db, pubsub, relay_keypair) = + connect_member_services(secret_service, secret_account).await?; let tenant = resolve_admin_tenant(&db).await?; match db @@ -191,7 +219,12 @@ async fn cmd_add_member(pubkey_arg: String, role: String) -> Result { Ok(0) } -async fn cmd_remove_member(pubkey_arg: String, role_filter: Option) -> Result { +async fn cmd_remove_member( + pubkey_arg: String, + role_filter: Option, + secret_service: &str, + secret_account: &str, +) -> Result { if let Some(ref role) = role_filter { if let Err(msg) = validate_role(role) { eprintln!("error: {msg}"); @@ -207,7 +240,8 @@ async fn cmd_remove_member(pubkey_arg: String, role_filter: Option) -> R } }; - let (db, pubsub, relay_keypair) = connect_member_services().await?; + let (db, pubsub, relay_keypair) = + connect_member_services(secret_service, secret_account).await?; let tenant = resolve_admin_tenant(&db).await?; use buzz_db::relay_members::RemoveResult; @@ -385,19 +419,13 @@ async fn publish_membership_list_with_bump( /// Connect to DB, Redis pub/sub, and load the relay keypair. /// -/// `BUZZ_RELAY_PRIVATE_KEY` is required — the CLI signs kind:13534 events. -async fn connect_member_services() -> Result<(Db, Arc, Keys)> { +/// The relay identity is required — the CLI signs kind:13534 events. +async fn connect_member_services( + secret_service: &str, + secret_account: &str, +) -> Result<(Db, Arc, Keys)> { let db = connect_db().await?; - - let relay_keypair = { - let hex = std::env::var("BUZZ_RELAY_PRIVATE_KEY").map_err(|_| { - anyhow::anyhow!( - "BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-member.\n\ - The relay must have a stable signing key to publish kind:13534 events." - ) - })?; - Keys::parse(&hex).map_err(|e| anyhow::anyhow!("invalid BUZZ_RELAY_PRIVATE_KEY: {e}"))? - }; + let relay_keypair = load_relay_keys(secret_service, secret_account)?; let redis_url = std::env::var("REDIS_URL").unwrap_or_else(|_| "redis://localhost:6379".to_string()); @@ -458,28 +486,25 @@ async fn resolve_admin_tenant(db: &Db) -> Result { Ok(TenantContext::resolved(record.id, record.host)) } -async fn reconcile_channels(relay_key_arg: Option) -> Result<()> { +fn load_relay_keys(secret_service: &str, secret_account: &str) -> Result { + let client = daz_secrets::BlockingClient::from_default_config() + .map_err(|_| anyhow::anyhow!("secret provider is unavailable"))?; + let secret = client + .get(secret_service, secret_account) + .map_err(|_| anyhow::anyhow!("relay signing identity is unavailable"))?; + let secret_value = zeroize::Zeroizing::new(secret.value); + let encoded = std::str::from_utf8(&secret_value) + .map_err(|_| anyhow::anyhow!("relay signing identity is not valid UTF-8"))?; + Keys::parse(encoded.trim()).map_err(|_| anyhow::anyhow!("relay signing identity is invalid")) +} + +async fn reconcile_channels(secret_service: &str, secret_account: &str) -> Result<()> { use buzz_core::kind::KIND_NIP29_GROUP_ADMINS; use buzz_db::event::EventQuery; let db = connect_db().await?; - // Resolve relay signing key: arg > env > ephemeral - let relay_keys = match relay_key_arg.or_else(|| std::env::var("BUZZ_RELAY_PRIVATE_KEY").ok()) { - Some(key_hex) => { - Keys::parse(&key_hex).map_err(|e| anyhow::anyhow!("invalid relay key: {e}"))? - } - None => { - let k = Keys::generate(); - eprintln!( - "Warning: no relay key provided — using ephemeral key {}", - k.public_key().to_hex() - ); - eprintln!("Events signed with this key won't be verifiable after this run."); - eprintln!("Pass --relay-key or set BUZZ_RELAY_PRIVATE_KEY for production use."); - k - } - }; + let relay_keys = load_relay_keys(secret_service, secret_account)?; let tenant = resolve_admin_tenant(&db).await?; let channels = db.list_channels(tenant.community(), None).await?; diff --git a/crates/buzz-agent/src/hints.rs b/crates/buzz-agent/src/hints.rs index 9fb99f0ebc..22c4b4fcac 100644 --- a/crates/buzz-agent/src/hints.rs +++ b/crates/buzz-agent/src/hints.rs @@ -30,10 +30,7 @@ fn find_git_root(start: &Path) -> Option { if current.join(".git").exists() { return Some(current); } - match current.parent() { - Some(parent) => current = parent.to_path_buf(), - None => return None, - } + current = current.parent()?.to_path_buf(); } } diff --git a/crates/buzz-agent/src/mcp.rs b/crates/buzz-agent/src/mcp.rs index 9ae125a0b7..001f8b9bb3 100644 --- a/crates/buzz-agent/src/mcp.rs +++ b/crates/buzz-agent/src/mcp.rs @@ -77,13 +77,8 @@ const PASSTHROUGH_ENV: &[&str] = &[ // was configured correctly and the child could not see it. "SSL_CERT_FILE", "SSL_CERT_DIR", - // Buzz identity — dev-mcp writes NOSTR_PRIVATE_KEY to a keyfile then - // removes it from its own env (children never see it). BUZZ_PRIVATE_KEY - // and BUZZ_RELAY_URL are kept for the buzz CLI. BUZZ_AUTH_TAG is a - // non-secret signed ownership attestation needed by portable owner-scoped - // CLI operations; MCP subprocesses are trusted like the agent runtime. - "NOSTR_PRIVATE_KEY", - "BUZZ_PRIVATE_KEY", + // Buzz transport metadata. Identity bytes are never inherited; the MCP + // server receives only daz-secrets coordinates in its explicit argv. "BUZZ_RELAY_URL", "BUZZ_AUTH_TAG", // Agent display name — dev-mcp uses it as the git author name. On the diff --git a/crates/buzz-cli/Cargo.toml b/crates/buzz-cli/Cargo.toml index 1476e60bfd..a7c543b00a 100644 --- a/crates/buzz-cli/Cargo.toml +++ b/crates/buzz-cli/Cargo.toml @@ -85,6 +85,8 @@ rustls = { version = "0.23", default-features = false, features = ["ring", "std" # Random number generation — full jitter for exponential backoff in with_retry rand = { workspace = true } +daz-secrets = { workspace = true } +zeroize = { workspace = true } [dev-dependencies] # Scratch files for channel-templates.json fixtures in tests diff --git a/crates/buzz-cli/README.md b/crates/buzz-cli/README.md index a2dcdce6d2..9f9bdaf04f 100644 --- a/crates/buzz-cli/README.md +++ b/crates/buzz-cli/README.md @@ -10,14 +10,16 @@ cargo install --path crates/buzz-cli ## Authentication -| Env Var | Mode | Use Case | -|---------|------|----------| -| `BUZZ_PRIVATE_KEY` | NIP-98 Schnorr signature | Agents with a keypair | +Buzz loads the Nostr identity directly from daz-secrets. The default item is +`buzz-desktop/identity`; managed agents receive their own nonsecret provider +coordinates through process-local git config. ```bash -# Private key identity (NIP-98 signed requests) -export BUZZ_PRIVATE_KEY="nsec1..." +daz-secrets set buzz-desktop identity buzz channels list + +# Or select another provider item without putting secret bytes in argv. +buzz --secret-service my-app --secret-account relay-identity channels list ``` ## Usage diff --git a/crates/buzz-cli/src/commands/mem.rs b/crates/buzz-cli/src/commands/mem.rs index eb15921bd4..ffae4c6da8 100644 --- a/crates/buzz-cli/src/commands/mem.rs +++ b/crates/buzz-cli/src/commands/mem.rs @@ -8,7 +8,7 @@ //! - `buzz mem patch ` — apply a unified diff to the current value //! - `buzz mem rm ` — publish a tombstone //! -//! By default, the caller's `BUZZ_PRIVATE_KEY` is the agent's nsec. The +//! By default, the caller's daz-secrets identity is the agent's nsec. The //! agent's owner pubkey is resolved from `BUZZ_AUTH_TAG` (NIP-OA attestation) //! or the `--owner` flag. Read commands also support owner-side recovery via //! `--agent `: the CLI identity is treated as the owner and decrypts diff --git a/crates/buzz-cli/src/lib.rs b/crates/buzz-cli/src/lib.rs index 8a8bb053b0..b8ebad598f 100644 --- a/crates/buzz-cli/src/lib.rs +++ b/crates/buzz-cli/src/lib.rs @@ -10,6 +10,7 @@ use client::BuzzClient; use error::CliError; use nostr::Keys; use uuid::Uuid; +use zeroize::Zeroizing; /// Run the Buzz CLI from raw arguments (including `argv[0]`). /// @@ -69,7 +70,8 @@ Buzz CLI — interact with a Buzz relay Configuration (flags override env vars): BUZZ_RELAY_URL Relay base URL [default: http://localhost:3000] - BUZZ_PRIVATE_KEY Nostr private key (hex or nsec) [required] + --secret-service daz-secrets service [default: git config or buzz-desktop] + --secret-account daz-secrets account [default: git config or identity] BUZZ_AUTH_TAG NIP-OA auth tag JSON [optional] The 'pack' subcommand runs locally and does not require a relay connection. @@ -82,9 +84,13 @@ struct Cli { #[arg(long, env = "BUZZ_RELAY_URL", default_value = "http://localhost:3000")] relay: String, - /// Nostr private key (hex or nsec). This is the CLI's identity. - #[arg(long, env = "BUZZ_PRIVATE_KEY", hide_env_values = true)] - private_key: Option, + /// daz-secrets service containing the Nostr identity. + #[arg(long)] + secret_service: Option, + + /// daz-secrets account containing the Nostr identity. + #[arg(long)] + secret_account: Option, /// NIP-OA auth tag JSON (owner attestation). Injected into every signed event. #[arg(long, env = "BUZZ_AUTH_TAG", hide_env_values = true)] @@ -1934,13 +1940,28 @@ async fn run(cli: Cli) -> Result<(), CliError> { }; } - // Auth: private key is required for all relay operations. - // The keypair IS the identity — no tokens, no other auth. - let private_key_str = cli.private_key.ok_or_else(|| { - CliError::Auth("BUZZ_PRIVATE_KEY is required (use --private-key or set env var)".into()) - })?; - let keys = Keys::parse(&private_key_str) - .map_err(|e| CliError::Key(format!("invalid BUZZ_PRIVATE_KEY: {e}")))?; + // Auth: the keypair IS the identity. Load it directly from daz-secrets so + // private bytes never enter argv, environment variables, or plaintext + // files. Managed-agent runtimes expose their nonsecret coordinates through + // process-local git config; standalone installs use the desktop identity. + let secret_service = cli + .secret_service + .or_else(|| git_config("nostr.secretService")) + .unwrap_or_else(|| "buzz-desktop".to_string()); + let secret_account = cli + .secret_account + .or_else(|| git_config("nostr.secretAccount")) + .unwrap_or_else(|| "identity".to_string()); + let provider = daz_secrets::BlockingClient::from_default_config() + .map_err(|_| CliError::Auth("daz-secrets provider is unavailable".into()))?; + let secret = provider + .get(&secret_service, &secret_account) + .map_err(|_| CliError::Auth("Nostr identity is unavailable from daz-secrets".into()))?; + let private_key = Zeroizing::new(secret.value); + let private_key_str = std::str::from_utf8(&private_key) + .map_err(|_| CliError::Auth("Nostr identity has invalid encoding".into()))?; + let keys = Keys::parse(private_key_str.trim()) + .map_err(|_| CliError::Key("invalid Nostr identity in daz-secrets".into()))?; // NIP-OA: parse and verify the auth tag if provided. // @@ -1997,6 +2018,19 @@ async fn run(cli: Cli) -> Result<(), CliError> { } } +fn git_config(key: &str) -> Option { + let output = std::process::Command::new("git") + .args(["config", "--get", key]) + .stdin(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .output() + .ok()?; + output + .status + .success() + .then(|| String::from_utf8_lossy(&output.stdout).trim().to_string()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/buzz-dev-mcp/Cargo.toml b/crates/buzz-dev-mcp/Cargo.toml index 8b711b8063..228a1ca388 100644 --- a/crates/buzz-dev-mcp/Cargo.toml +++ b/crates/buzz-dev-mcp/Cargo.toml @@ -39,6 +39,7 @@ reqwest = { workspace = true } base64 = "0.22" image = { version = "0.25", default-features = false, features = ["jpeg", "png", "gif", "webp"] } buzz-core = { workspace = true } +daz-secrets = { workspace = true } [target.'cfg(unix)'.dependencies] nix = { version = "0.31", default-features = false, features = ["signal", "process"] } diff --git a/crates/buzz-dev-mcp/src/lib.rs b/crates/buzz-dev-mcp/src/lib.rs index 9b98974802..266e57bf36 100644 --- a/crates/buzz-dev-mcp/src/lib.rs +++ b/crates/buzz-dev-mcp/src/lib.rs @@ -170,6 +170,8 @@ async fn async_main(cmd: String) -> Result<(), Box> { std::process::exit(buzz_cli::run_from_args(std::env::args()).await); } + let (secret_service, secret_account) = parse_secret_coordinates()?; + // MCP server mode — safe to init tracing now. tracing_subscriber::fmt() .with_writer(std::io::stderr) @@ -177,14 +179,40 @@ async fn async_main(cmd: String) -> Result<(), Box> { .init(); let cwd = std::env::current_dir()?; - let shim = shim::Shim::install()?; - let state = Arc::new(shell::SharedState::new(cwd, shim)?); + let shim = shim::Shim::install(&secret_service, &secret_account)?; + let state = Arc::new(shell::SharedState::new( + cwd, + shim, + secret_service, + secret_account, + )?); let service = DevMcp::new(state).serve(stdio()).await?; service.waiting().await?; Ok(()) } +fn parse_secret_coordinates() -> Result<(String, String), Box> { + let mut service = "buzz-desktop".to_string(); + let mut account = "identity".to_string(); + let mut args = std::env::args().skip(1); + while let Some(arg) = args.next() { + let target = match arg.as_str() { + "--secret-service" => &mut service, + "--secret-account" => &mut account, + _ => return Err(format!("unknown buzz-dev-mcp argument: {arg}").into()), + }; + let value = args + .next() + .ok_or_else(|| format!("{arg} requires a value"))?; + if value.trim().is_empty() { + return Err(format!("{arg} must not be empty").into()); + } + *target = value; + } + Ok((service, account)) +} + /// Suppress the console window that Windows otherwise allocates for every /// console-subsystem child process spawned from a non-console parent. /// No-op on non-Windows platforms. diff --git a/crates/buzz-dev-mcp/src/read_file.rs b/crates/buzz-dev-mcp/src/read_file.rs index c9233390bc..d1a8a0589a 100644 --- a/crates/buzz-dev-mcp/src/read_file.rs +++ b/crates/buzz-dev-mcp/src/read_file.rs @@ -72,8 +72,14 @@ mod tests { use tempfile::tempdir; fn make_state(cwd: &std::path::Path) -> SharedState { - let shim = crate::shim::Shim::install().expect("shim install"); - SharedState::new(cwd.to_path_buf(), shim).expect("state new") + let shim = crate::shim::Shim::install_without_identity().expect("shim install"); + SharedState::new( + cwd.to_path_buf(), + shim, + "buzz-test".into(), + "identity".into(), + ) + .expect("state new") } #[test] diff --git a/crates/buzz-dev-mcp/src/shell.rs b/crates/buzz-dev-mcp/src/shell.rs index 7aa95b1d87..7c272fe386 100644 --- a/crates/buzz-dev-mcp/src/shell.rs +++ b/crates/buzz-dev-mcp/src/shell.rs @@ -26,6 +26,8 @@ const READ_CHUNK: usize = 16 * 1024; pub struct SharedState { pub cwd: PathBuf, pub shim: Shim, + pub secret_service: String, + pub secret_account: String, pub session_dir: TempDir, pub bootstrap_instructions: String, /// The shell resolved at construction: `Ok((path, display_name))` when a shell @@ -37,7 +39,12 @@ pub struct SharedState { } impl SharedState { - pub fn new(cwd: PathBuf, shim: Shim) -> std::io::Result { + pub fn new( + cwd: PathBuf, + shim: Shim, + secret_service: String, + secret_account: String, + ) -> std::io::Result { let session_dir = tempfile::Builder::new() .prefix("buzz-dev-mcp-session-") .tempdir()?; @@ -54,6 +61,8 @@ impl SharedState { Ok(Self { cwd, shim, + secret_service, + secret_account, session_dir, bootstrap_instructions, resolved_shell, @@ -74,12 +83,11 @@ impl SharedState { fn build_bootstrap(cwd: &Path, shell_hint: &str) -> String { let stack = detect_stack(cwd); - let buzz_hint = - if std::env::var("BUZZ_RELAY_URL").is_ok() && std::env::var("BUZZ_PRIVATE_KEY").is_ok() { - "\nBuzz relay configured. Run `buzz --help` to see available commands.\n" - } else { - "" - }; + let buzz_hint = if std::env::var("BUZZ_RELAY_URL").is_ok() { + "\nBuzz relay configured. Run `buzz --help` to see available commands.\n" + } else { + "" + }; format!( "Working directory: {}\n\ Detected stack: {}\n\ @@ -167,8 +175,8 @@ pub async fn run( cmd.arg(shell_arg).arg(&p.command); cmd.current_dir(&workdir); cmd.env("PATH", &state.shim.path_env); - // NOSTR_PRIVATE_KEY is already removed from this process's env (shim.rs). - // BUZZ_PRIVATE_KEY is intentionally inherited — the buzz CLI needs it. + // Git receives only non-secret daz-secrets coordinates. Helpers and the + // Buzz CLI resolve the identity directly from the provider when needed. for (k, v) in &state.shim.git_env { cmd.env(k, v); } @@ -989,8 +997,14 @@ mod tests { use tempfile::tempdir; fn make_state(cwd: &std::path::Path) -> SharedState { - let shim = Shim::install().expect("shim install"); - SharedState::new(cwd.to_path_buf(), shim).expect("state new") + let shim = Shim::install_without_identity().expect("shim install"); + SharedState::new( + cwd.to_path_buf(), + shim, + "buzz-test".into(), + "identity".into(), + ) + .expect("state new") } /// Pull the JSON body out of a CallToolResult so tests can assert on fields. @@ -1273,8 +1287,14 @@ mod windows_resolver_tests { touch(&fake_pwsh); env::set_var("BUZZ_SHELL", &fake_pwsh); - let shim = crate::shim::Shim::install().expect("shim"); - let state = SharedState::new(dir.path().to_path_buf(), shim).expect("state"); + let shim = crate::shim::Shim::install_without_identity().expect("shim"); + let state = SharedState::new( + dir.path().to_path_buf(), + shim, + "buzz-test".into(), + "identity".into(), + ) + .expect("state"); env::remove_var("BUZZ_SHELL"); diff --git a/crates/buzz-dev-mcp/src/shim.rs b/crates/buzz-dev-mcp/src/shim.rs index cccf0e6eca..a76a4e35bb 100644 --- a/crates/buzz-dev-mcp/src/shim.rs +++ b/crates/buzz-dev-mcp/src/shim.rs @@ -1,19 +1,19 @@ use nostr::ToBech32; use std::path::{Path, PathBuf}; use tempfile::TempDir; -use zeroize::Zeroize; +use zeroize::Zeroizing; /// Session-scoped shim directory providing tools and git config to shell children. /// /// On install: /// 1. Creates a 0700 tempdir with symlinks back to our binary (multicall) -/// 2. If `NOSTR_PRIVATE_KEY` is set: writes a 0600 keyfile, derives the pubkey, -/// builds ephemeral `GIT_CONFIG_*` env vars, then removes the env var +/// 2. Resolves the identity from daz-secrets long enough to derive its public +/// key, then builds ephemeral `GIT_CONFIG_*` entries containing only the +/// provider coordinates and public identity /// 3. Prepends the shim dir to PATH /// -/// Shell children receive `path_env`, `git_env`, and `BUZZ_PRIVATE_KEY` (for -/// the buzz CLI). `NOSTR_PRIVATE_KEY` is removed from the process env after -/// the keyfile is written — git helpers read from the keyfile only. +/// Shell children receive `path_env` and non-secret `git_env`. They never +/// receive private key bytes through files, argv, or environment variables. /// Cleaned up on drop (TempDir). pub struct Shim { _dir: TempDir, @@ -22,7 +22,27 @@ pub struct Shim { } impl Shim { - pub fn install() -> std::io::Result { + pub fn install(secret_service: &str, secret_account: &str) -> std::io::Result { + let client = + daz_secrets::BlockingClient::from_default_config().map_err(secret_provider_error)?; + let secret = client + .get(secret_service, secret_account) + .map_err(secret_provider_error)?; + let secret_value = Zeroizing::new(secret.value); + let encoded = std::str::from_utf8(&secret_value) + .map_err(|_| secret_provider_error("identity is not valid UTF-8"))?; + let keys = nostr::Keys::parse(encoded.trim()) + .map_err(|_| secret_provider_error("identity is not a valid Nostr key"))?; + let info = KeyInfo::new(&keys, secret_service, secret_account); + Self::install_with_identity(Some(&info)) + } + + #[cfg(test)] + pub fn install_without_identity() -> std::io::Result { + Self::install_with_identity(None) + } + + fn install_with_identity(info: Option<&KeyInfo>) -> std::io::Result { let dir = tempfile::Builder::new().prefix("buzz-dev-mcp-").tempdir()?; set_owner_only(dir.path())?; @@ -48,24 +68,7 @@ impl Shim { .to_string_lossy() .into_owned(); - // Read and unconditionally remove NOSTR_PRIVATE_KEY from this process's - // env. The key must never leak to child processes regardless of whether - // keyfile creation succeeds. - let mut nostr_key = std::env::var("NOSTR_PRIVATE_KEY").ok(); - std::env::remove_var("NOSTR_PRIVATE_KEY"); - - // Ephemeral git config: write key to 0600 keyfile, derive pubkey, build - // GIT_CONFIG_* env vars for nostr auth + signing. - let git_env = match nostr_key - .as_deref() - .and_then(|k| write_keyfile(dir.path(), k)) - { - Some(info) => build_git_env(&info), - None => Vec::new(), - }; - if let Some(ref mut k) = nostr_key { - k.zeroize(); - } + let git_env = info.map(build_git_env).unwrap_or_default(); Ok(Self { _dir: dir, @@ -76,76 +79,30 @@ impl Shim { } struct KeyInfo { - keyfile_path: String, + secret_service: String, + secret_account: String, pubkey_hex: String, npub: String, } -/// Write the nostr private key to an owner-only file in the shim dir. -/// Returns key metadata or None if key is empty/invalid. -/// Warns to stderr if the key is invalid (operator mistake). -fn write_keyfile(shim_dir: &Path, raw: &str) -> Option { - if raw.is_empty() { - return None; - } - let keys = match nostr::Keys::parse(raw) { - Ok(k) => k, - Err(e) => { - eprintln!( - "buzz-dev-mcp: warning: NOSTR_PRIVATE_KEY is set but invalid ({e}); \ - git auth/signing will be disabled" - ); - return None; +impl KeyInfo { + fn new(keys: &nostr::Keys, secret_service: &str, secret_account: &str) -> Self { + let pubkey_hex = keys.public_key().to_hex(); + let npub = keys + .public_key() + .to_bech32() + .unwrap_or_else(|_| pubkey_hex.clone()); + Self { + secret_service: secret_service.to_string(), + secret_account: secret_account.to_string(), + pubkey_hex, + npub, } - }; - let pubkey_hex = keys.public_key().to_hex(); - let npub = keys - .public_key() - .to_bech32() - .unwrap_or_else(|_| pubkey_hex.clone()); - - let keyfile = shim_dir.join(".nostr-key"); - if write_keyfile_atomic(&keyfile, raw.as_bytes()).is_err() { - eprintln!( - "buzz-dev-mcp: warning: failed to write nostr keyfile; git auth/signing disabled" - ); - return None; } - let keyfile_path = match keyfile.to_str() { - Some(s) => s.to_owned(), - None => { - eprintln!( - "buzz-dev-mcp: warning: tempdir path is not valid UTF-8; git auth/signing disabled" - ); - return None; - } - }; - - Some(KeyInfo { - keyfile_path, - pubkey_hex, - npub, - }) } -/// Write `data` to `path` with 0600 permissions set at creation time via -/// `OpenOptions::mode()` (no window where the file is world-readable). -/// Non-Unix: plain write — acceptable inside our 0700 tempdir. -#[cfg(unix)] -fn write_keyfile_atomic(path: &Path, data: &[u8]) -> std::io::Result<()> { - use std::io::Write; - use std::os::unix::fs::OpenOptionsExt; - let mut f = std::fs::OpenOptions::new() - .write(true) - .create_new(true) - .mode(0o600) - .open(path)?; - f.write_all(data) -} - -#[cfg(not(unix))] -fn write_keyfile_atomic(path: &Path, data: &[u8]) -> std::io::Result<()> { - std::fs::write(path, data) +fn secret_provider_error(error: impl std::fmt::Display) -> std::io::Error { + std::io::Error::other(format!("daz-secrets identity lookup failed: {error}")) } /// Derive a NIP-05-style email from the pubkey and relay URL. @@ -299,7 +256,8 @@ fn build_git_env(info: &KeyInfo) -> Vec<(String, String)> { // Required: Buzz relay verifies NIP-98 against the full repo-root URL. // Without useHttpPath, git only passes the host and auth is rejected. ("credential.useHttpPath", "true".into()), - ("nostr.keyfile", info.keyfile_path.clone()), + ("nostr.secretService", info.secret_service.clone()), + ("nostr.secretAccount", info.secret_account.clone()), ("gpg.format", "x509".into()), ("gpg.x509.program", "git-sign-nostr".into()), ("commit.gpgSign", "true".into()), @@ -374,7 +332,8 @@ mod git_user_name_tests { fn key_info() -> KeyInfo { KeyInfo { - keyfile_path: "/tmp/.nostr-key".into(), + secret_service: "buzz-test".into(), + secret_account: "identity".into(), pubkey_hex: PUBKEY_HEX.into(), npub: NPUB.into(), } diff --git a/crates/buzz-dev-mcp/src/str_replace.rs b/crates/buzz-dev-mcp/src/str_replace.rs index cffd65f909..8d2257210b 100644 --- a/crates/buzz-dev-mcp/src/str_replace.rs +++ b/crates/buzz-dev-mcp/src/str_replace.rs @@ -229,8 +229,14 @@ mod tests { } fn make_state(cwd: &std::path::Path) -> SharedState { - let shim = crate::shim::Shim::install().expect("shim install"); - SharedState::new(cwd.to_path_buf(), shim).expect("state new") + let shim = crate::shim::Shim::install_without_identity().expect("shim install"); + SharedState::new( + cwd.to_path_buf(), + shim, + "buzz-test".into(), + "identity".into(), + ) + .expect("state new") } #[test] diff --git a/crates/buzz-dev-mcp/src/view_image.rs b/crates/buzz-dev-mcp/src/view_image.rs index 441338ab12..3145f6907d 100644 --- a/crates/buzz-dev-mcp/src/view_image.rs +++ b/crates/buzz-dev-mcp/src/view_image.rs @@ -130,7 +130,7 @@ async fn load_source( } Ok((bytes, "data:URL".to_string())) } else if src.starts_with("http://") || src.starts_with("https://") { - let bytes = fetch_url(src).await?; + let bytes = fetch_url(state, src).await?; Ok((bytes, src.to_string())) } else if src.contains("://") { // Treat any other `scheme://...` form as an explicit reject so @@ -283,45 +283,57 @@ fn server_authority(url: &reqwest::Url) -> Option { } } -/// Mint a `t=get` Authorization header for `url` when it is relay-hosted -/// media and `BUZZ_PRIVATE_KEY` is available; `None` otherwise. +/// Mint a `t=get` Authorization header for relay-hosted media using the +/// configured daz-secrets identity; `None` for non-relay URLs. /// /// Fail-open by design: while the relay's media-read-auth flag is off, an /// unauthenticated request still succeeds, so a missing/invalid key degrades /// to an unsigned fetch instead of an error. Once the flag is on, the fetch /// 403s and the error path below names the missing key. -fn relay_media_get_auth(url: &reqwest::Url) -> Option { - let relay = std::env::var("BUZZ_RELAY_URL").ok()?; - let relay = reqwest::Url::parse(&relay).ok()?; - if !is_relay_media_url(url, &relay) { - return None; - } - let key = std::env::var("BUZZ_PRIVATE_KEY").ok()?; - let keys = match nostr::Keys::parse(&key) { - Ok(k) => k, - Err(e) => { - tracing::warn!("BUZZ_PRIVATE_KEY invalid; fetching relay media unauthenticated: {e}"); - return None; - } +fn relay_media_get_auth( + state: &SharedState, + url: &reqwest::Url, +) -> Result, ErrorData> { + let Some(relay) = std::env::var("BUZZ_RELAY_URL") + .ok() + .and_then(|value| reqwest::Url::parse(&value).ok()) + else { + return Ok(None); }; - let authority = server_authority(url)?; - match sign_media_get_auth(&keys, &authority) { - Ok(header) => Some(header), - Err(e) => { - tracing::warn!("media get auth signing failed; fetching unauthenticated: {e}"); - None - } + if !is_relay_media_url(url, &relay) { + return Ok(None); } + let client = daz_secrets::BlockingClient::from_default_config().map_err(|_| { + ErrorData::internal_error("secret provider is unavailable".to_string(), None) + })?; + let secret = client + .get(&state.secret_service, &state.secret_account) + .map_err(|_| { + ErrorData::internal_error("relay media identity is unavailable".to_string(), None) + })?; + let secret_value = zeroize::Zeroizing::new(secret.value); + let encoded = std::str::from_utf8(&secret_value).map_err(|_| { + ErrorData::internal_error("relay media identity is invalid".to_string(), None) + })?; + let keys = nostr::Keys::parse(encoded.trim()).map_err(|_| { + ErrorData::internal_error("relay media identity is invalid".to_string(), None) + })?; + let authority = server_authority(url).ok_or_else(|| { + ErrorData::internal_error("relay media URL has no authority".to_string(), None) + })?; + sign_media_get_auth(&keys, &authority) + .map(Some) + .map_err(|_| ErrorData::internal_error("media auth signing failed".to_string(), None)) } /// Fetch an http(s) URL with a streaming read and a hard byte cap. /// Refuses up-front if `Content-Length` advertises more than the cap. /// Relay-hosted `/media/` URLs get a signed Blossom `t=get` header when -/// `BUZZ_RELAY_URL` + `BUZZ_PRIVATE_KEY` are configured. -async fn fetch_url(url: &str) -> Result, ErrorData> { +/// the relay URL and secret-provider coordinates are configured. +async fn fetch_url(state: &SharedState, url: &str) -> Result, ErrorData> { let parsed = reqwest::Url::parse(url) .map_err(|e| invalid_params(format!("invalid URL: {url} ({e})")))?; - let auth = relay_media_get_auth(&parsed); + let auth = relay_media_get_auth(state, &parsed)?; let mut client_builder = reqwest::Client::builder() .connect_timeout(FETCH_TIMEOUT) .timeout(FETCH_TIMEOUT); @@ -353,7 +365,7 @@ async fn fetch_url(url: &str) -> Result, ErrorData> { if matches!(status.as_u16(), 401 | 403) && !authed { return Err(invalid_params(format!( "fetch {url} returned HTTP {status} — this relay requires authenticated media \ - reads; set BUZZ_PRIVATE_KEY (and BUZZ_RELAY_URL) to a member identity" + reads; configure a member identity in the local secret provider" ))); } return Err(invalid_params(format!( @@ -682,8 +694,14 @@ mod tests { use tempfile::tempdir; fn make_state(cwd: &std::path::Path) -> SharedState { - let shim = crate::shim::Shim::install().expect("shim install"); - SharedState::new(cwd.to_path_buf(), shim).expect("state new") + let shim = crate::shim::Shim::install_without_identity().expect("shim install"); + SharedState::new( + cwd.to_path_buf(), + shim, + "buzz-test".into(), + "identity".into(), + ) + .expect("state new") } fn write_png_rgba(path: &std::path::Path, w: u32, h: u32) -> Vec { diff --git a/crates/buzz-pairing-cli/src/main.rs b/crates/buzz-pairing-cli/src/main.rs index 1eb9d215f9..2f16b168ad 100644 --- a/crates/buzz-pairing-cli/src/main.rs +++ b/crates/buzz-pairing-cli/src/main.rs @@ -319,7 +319,7 @@ async fn cmd_target(relay_override: Option, show_secret: bool) -> Result }; println!("Received {kind_label} payload!"); if show_secret { - println!("{kind_label}: {}", &*payload); + println!("{kind_label}: {}", *payload); } else { println!("(use --show-secret to display the received secret)"); } diff --git a/crates/buzz-relay/Cargo.toml b/crates/buzz-relay/Cargo.toml index 41bdc3b9e9..339abb5eb7 100644 --- a/crates/buzz-relay/Cargo.toml +++ b/crates/buzz-relay/Cargo.toml @@ -84,8 +84,8 @@ async-compression = { version = "0.4.42", features = ["tokio", "gzip"] } dev = ["buzz-auth/dev"] [dev-dependencies] -mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] } -mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] } +mesh-llm-sdk = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"] } +mesh-llm-host-runtime = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"] } buzz-core = { workspace = true, features = ["test-utils"] } buzz-auth = { workspace = true, features = ["dev"] } reqwest = { workspace = true } diff --git a/crates/buzz-test-client/Cargo.toml b/crates/buzz-test-client/Cargo.toml index e495c16300..3cd3247410 100644 --- a/crates/buzz-test-client/Cargo.toml +++ b/crates/buzz-test-client/Cargo.toml @@ -23,6 +23,8 @@ thiserror = { workspace = true } uuid = { workspace = true } url = { workspace = true } rustls = "0.23" +daz-secrets = { workspace = true } +zeroize = { workspace = true } [dev-dependencies] tracing-subscriber = { workspace = true } diff --git a/crates/buzz-test-client/src/main.rs b/crates/buzz-test-client/src/main.rs index 858f795c83..3086d0976b 100644 --- a/crates/buzz-test-client/src/main.rs +++ b/crates/buzz-test-client/src/main.rs @@ -11,6 +11,8 @@ //! --channel Channel ID for send/subscribe //! --subscribe Subscribe to a channel and print events //! --kind Event kind [default: 9] +//! --secret-service daz-secrets service [default: buzz-desktop] +//! --secret-account daz-secrets account [default: identity] //! ``` //! //! # Examples @@ -47,10 +49,16 @@ async fn main() { let channel = opts.channel.as_deref().unwrap_or("default"); let kind = opts.kind.unwrap_or(9); - let keys = match std::env::var("BUZZ_PRIVATE_KEY") { - Ok(sk) => Keys::parse(&sk).expect("invalid BUZZ_PRIVATE_KEY"), - Err(_) => Keys::generate(), - }; + let service = opts.secret_service.as_deref().unwrap_or("buzz-desktop"); + let account = opts.secret_account.as_deref().unwrap_or("identity"); + let client = + daz_secrets::BlockingClient::from_default_config().expect("secret provider is unavailable"); + let secret = client + .get(service, account) + .expect("test client identity is unavailable"); + let secret_value = zeroize::Zeroizing::new(secret.value); + let encoded = std::str::from_utf8(&secret_value).expect("test client identity is not UTF-8"); + let keys = Keys::parse(encoded.trim()).expect("test client identity is invalid"); println!("Using pubkey: {}", keys.public_key()); if opts.subscribe { @@ -159,6 +167,8 @@ struct CliOpts { channel: Option, subscribe: bool, kind: Option, + secret_service: Option, + secret_account: Option, } fn parse_args(args: &[String]) -> CliOpts { @@ -168,6 +178,8 @@ fn parse_args(args: &[String]) -> CliOpts { channel: None, subscribe: false, kind: None, + secret_service: None, + secret_account: None, }; let mut i = 1; @@ -192,6 +204,14 @@ fn parse_args(args: &[String]) -> CliOpts { i += 1; opts.kind = args.get(i).and_then(|s| s.parse().ok()); } + "--secret-service" => { + i += 1; + opts.secret_service = args.get(i).cloned(); + } + "--secret-account" => { + i += 1; + opts.secret_account = args.get(i).cloned(); + } "--help" | "-h" => { print_help(); std::process::exit(0); @@ -220,6 +240,8 @@ OPTIONS: --channel Channel ID for send/subscribe [default: default] --subscribe Subscribe to a channel and print events --kind Event kind [default: 9] + --secret-service daz-secrets service [default: buzz-desktop] + --secret-account daz-secrets account [default: identity] --help Print this help message EXAMPLES: diff --git a/crates/git-credential-nostr/Cargo.toml b/crates/git-credential-nostr/Cargo.toml index dcd433264f..26875514e4 100644 --- a/crates/git-credential-nostr/Cargo.toml +++ b/crates/git-credential-nostr/Cargo.toml @@ -19,3 +19,4 @@ nostr = { workspace = true } serde_json = { workspace = true } zeroize = { workspace = true } base64 = "0.22" +daz-secrets = { workspace = true } diff --git a/crates/git-credential-nostr/README.md b/crates/git-credential-nostr/README.md index 827f8d55a3..41f3c69760 100644 --- a/crates/git-credential-nostr/README.md +++ b/crates/git-credential-nostr/README.md @@ -20,21 +20,22 @@ cargo install --path crates/git-credential-nostr git config --global credential.helper nostr git config --global credential.useHttpPath true -# 2. Store your nsec in a key file (must be 0600). -mkdir -p ~/.nostr -echo "nsec1..." > ~/.nostr/key && chmod 600 ~/.nostr/key -git config --global nostr.keyfile ~/.nostr/key +# 2. Store your nsec through the interactive daz-secrets CLI. +daz-secrets set buzz-desktop identity +git config --global nostr.secretService buzz-desktop +git config --global nostr.secretAccount identity ``` That's it. Use git normally — `git clone`, `git push`, `git fetch`. ## CI / CD -Set `$NOSTR_PRIVATE_KEY` instead of a key file. The env var takes precedence -over `nostr.keyfile` and avoids touching the filesystem: +Install an unattended daz-secrets provider for the CI account, then configure +only the nonsecret provider coordinates: ```bash -export NOSTR_PRIVATE_KEY=nsec1... +git config nostr.secretService ci-build +git config nostr.secretAccount relay-identity git clone https://relay.example.com/git/owner/repo.git ``` @@ -42,8 +43,8 @@ git clone https://relay.example.com/git/owner/repo.git When a Buzz git server returns `HTTP 401` with a `WWW-Authenticate: Nostr realm="...", method="GET"` header, git calls this -helper with the request details on stdin. The helper loads your Nostr private -key, builds a [NIP-98](https://github.com/nostr-protocol/nips/blob/master/98.md) +helper with the request details on stdin. The helper reads your Nostr private +key directly from daz-secrets, builds a [NIP-98](https://github.com/nostr-protocol/nips/blob/master/98.md) kind-27235 event signed over the request URL and method, base64-encodes it, and writes it back to stdout. Git then retries the request with `Authorization: Nostr `, which the server verifies by checking the event @@ -61,8 +62,7 @@ git ──stdin──▶ git-credential-nostr ──stdout──▶ git | Error | Cause | Fix | |-------|-------|-----| -| `no nostr key configured` | Neither `$NOSTR_PRIVATE_KEY` nor `nostr.keyfile` is set | Follow the Setup steps above | -| `insecure permissions` | Key file is readable by group/others | `chmod 600 ~/.nostr/key` | +| `nostr identity is unavailable from daz-secrets` | The configured provider item is absent or unavailable | Verify the provider and `nostr.secretService` / `nostr.secretAccount` | | `method hint` | Server's `WWW-Authenticate` header is missing `method="..."` | Upgrade the Buzz server | | `useHttpPath` | `credential.useHttpPath` is not set | `git config --global credential.useHttpPath true` | | Empty output / no auth | git version is older than 2.46 | Upgrade git | diff --git a/crates/git-credential-nostr/src/lib.rs b/crates/git-credential-nostr/src/lib.rs index b51443600d..e856caa54e 100644 --- a/crates/git-credential-nostr/src/lib.rs +++ b/crates/git-credential-nostr/src/lib.rs @@ -11,7 +11,7 @@ use base64::Engine as _; use nostr::nips::nip98::{HttpData, HttpMethod}; use nostr::types::Url; use nostr::{EventBuilder, Keys, Tag}; -use zeroize::Zeroize; +use zeroize::Zeroizing; fn git_config(key: &str) -> Option { let out = std::process::Command::new("git") @@ -25,50 +25,15 @@ fn git_config(key: &str) -> Option { } } -#[cfg(unix)] -fn check_keyfile_permissions(path: &str) -> Result<(), String> { - use std::os::unix::fs::PermissionsExt; - let meta = std::fs::metadata(path).map_err(|e| format!("cannot stat keyfile {path}: {e}"))?; - let mode = meta.permissions().mode() & 0o777; - if mode & 0o177 != 0 { - return Err(format!( - "keyfile {path} has insecure permissions (expected 0600)" - )); - } - Ok(()) -} - -#[cfg(not(unix))] -fn check_keyfile_permissions(path: &str) -> Result<(), String> { - eprintln!("warning: cannot check keyfile permissions on this platform ({path})"); - Ok(()) -} - -/// Max keyfile size — nsec1 is 63 bytes; hex keys are 64 bytes. 256 is generous. -const MAX_KEYFILE_BYTES: u64 = 256; - -fn load_key() -> Result { - if let Ok(val) = std::env::var("NOSTR_PRIVATE_KEY") { - if !val.is_empty() { - return Ok(val); - } - } - let path = git_config("nostr.keyfile").ok_or_else(|| { - "no nostr key configured. Set $NOSTR_PRIVATE_KEY or git config nostr.keyfile".to_string() - })?; - check_keyfile_permissions(&path)?; - let meta = std::fs::metadata(&path).map_err(|e| format!("cannot stat keyfile {path}: {e}"))?; - if !meta.is_file() { - return Err(format!("keyfile {path} is not a regular file")); - } - if meta.len() > MAX_KEYFILE_BYTES { - return Err(format!( - "keyfile {path} exceeds {MAX_KEYFILE_BYTES}-byte size limit" - )); - } - let raw = - std::fs::read_to_string(&path).map_err(|e| format!("cannot read keyfile {path}: {e}"))?; - Ok(raw.trim().to_string()) +fn load_key() -> Result>, String> { + let service = git_config("nostr.secretService").unwrap_or_else(|| "buzz-desktop".to_string()); + let account = git_config("nostr.secretAccount").unwrap_or_else(|| "identity".to_string()); + let client = daz_secrets::BlockingClient::from_default_config() + .map_err(|_| "daz-secrets provider is unavailable".to_string())?; + let secret = client + .get(&service, &account) + .map_err(|_| "nostr identity is unavailable from daz-secrets".to_string())?; + Ok(Zeroizing::new(secret.value)) } /// Load the NIP-OA owner attestation injected by Buzz Desktop/ACP. @@ -205,7 +170,7 @@ pub fn run() -> i32 { .unwrap_or(path); let url = format!("{protocol}://{host}/{repo_path}"); - let mut raw_key = match load_key() { + let raw_key = match load_key() { Ok(k) => k, Err(e) => { eprintln!("error: {e}"); @@ -213,15 +178,20 @@ pub fn run() -> i32 { } }; - let keys = match Keys::parse(&raw_key) { + let encoded_key = match std::str::from_utf8(&raw_key) { + Ok(value) => value.trim(), + Err(_) => { + eprintln!("error: invalid nostr private key encoding"); + return 1; + } + }; + let keys = match Keys::parse(encoded_key) { Ok(k) => k, Err(e) => { - raw_key.zeroize(); eprintln!("error: invalid nostr private key: {e}"); return 1; } }; - raw_key.zeroize(); let parsed_url = Url::parse(&url).unwrap_or_else(|e| panic!("invalid URL {url:?}: {e}")); let http_data = HttpData::new(parsed_url, method); diff --git a/crates/git-credential-nostr/tests/integration.rs b/crates/git-credential-nostr/tests/integration.rs index 6697b45f39..fa6903245e 100644 --- a/crates/git-credential-nostr/tests/integration.rs +++ b/crates/git-credential-nostr/tests/integration.rs @@ -5,14 +5,56 @@ use std::io::Write; use std::process::{Command, Stdio}; +use std::sync::atomic::{AtomicU64, Ordering}; use base64::Engine as _; +use daz_secrets::BlockingClient; use nostr::{Keys, ToBech32}; -/// Spawn the binary, write `input` to stdin, collect output. -/// `env_vars` are added on top of the inherited environment. -/// `NOSTR_PRIVATE_KEY` is always cleared first to prevent test pollution. -fn run_helper(input: &str, env_vars: &[(&str, &str)]) -> std::process::Output { +static NEXT_ACCOUNT: AtomicU64 = AtomicU64::new(1); + +struct ProviderEntry { + client: BlockingClient, + service: String, + account: String, +} + +impl ProviderEntry { + fn new(value: Option<&str>) -> Self { + let client = BlockingClient::from_default_config().expect("daz-secrets test provider"); + let service = "buzz-credential-tests".to_string(); + let account = format!( + "pid-{}-{}", + std::process::id(), + NEXT_ACCOUNT.fetch_add(1, Ordering::Relaxed) + ); + if let Some(value) = value { + client + .set(&service, &account, value.as_bytes(), None) + .expect("seed provider identity"); + } + Self { + client, + service, + account, + } + } +} + +impl Drop for ProviderEntry { + fn drop(&mut self) { + let _ = self.client.delete(&self.service, &self.account, None); + } +} + +/// Spawn the binary against a real daz-secrets provider, write `input` to +/// stdin, and collect output. Secret bytes travel only through the provider. +fn run_helper( + input: &str, + provider_value: Option<&str>, + env_vars: &[(&str, &str)], +) -> std::process::Output { + let entry = ProviderEntry::new(provider_value); let bin = env!("CARGO_BIN_EXE_git-credential-nostr"); let mut cmd = Command::new(bin); cmd.stdin(Stdio::piped()) @@ -21,11 +63,14 @@ fn run_helper(input: &str, env_vars: &[(&str, &str)]) -> std::process::Output { .current_dir(std::env::temp_dir()) .env_remove("NOSTR_PRIVATE_KEY") .env_remove("BUZZ_AUTH_TAG") - .env_remove("GIT_CONFIG_COUNT") // Prevent git config on the test machine from supplying credentials. .env("GIT_CONFIG_GLOBAL", "/dev/null") .env("GIT_CONFIG_NOSYSTEM", "1") - .env("HOME", std::env::temp_dir()); + .env("GIT_CONFIG_COUNT", "2") + .env("GIT_CONFIG_KEY_0", "nostr.secretService") + .env("GIT_CONFIG_VALUE_0", &entry.service) + .env("GIT_CONFIG_KEY_1", "nostr.secretAccount") + .env("GIT_CONFIG_VALUE_1", &entry.account); for (k, v) in env_vars { cmd.env(k, v); } @@ -36,7 +81,9 @@ fn run_helper(input: &str, env_vars: &[(&str, &str)]) -> std::process::Output { .unwrap() .write_all(input.as_bytes()) .unwrap(); - child.wait_with_output().expect("failed to wait on child") + let output = child.wait_with_output().expect("failed to wait on child"); + drop(entry); + output } /// Generate a fresh nsec string for use in tests. @@ -62,7 +109,7 @@ fn valid_input() -> String { #[test] fn happy_path() { let nsec = fresh_nsec(); - let out = run_helper(&valid_input(), &[("NOSTR_PRIVATE_KEY", &nsec)]); + let out = run_helper(&valid_input(), Some(&nsec), &[]); assert!( out.status.success(), @@ -135,10 +182,7 @@ fn includes_nip_oa_auth_tag_in_signed_event() { ]) .expect("serialize auth tag"); - let out = run_helper( - &valid_input(), - &[("NOSTR_PRIVATE_KEY", &nsec), ("BUZZ_AUTH_TAG", &auth_tag)], - ); + let out = run_helper(&valid_input(), Some(&nsec), &[("BUZZ_AUTH_TAG", &auth_tag)]); assert!( out.status.success(), "helper failed: {}", @@ -175,7 +219,8 @@ fn malformed_nip_oa_auth_tag_fails_closed() { let nsec = fresh_nsec(); let out = run_helper( &valid_input(), - &[("NOSTR_PRIVATE_KEY", &nsec), ("BUZZ_AUTH_TAG", "not-json")], + Some(&nsec), + &[("BUZZ_AUTH_TAG", "not-json")], ); assert_eq!(out.status.code(), Some(1)); @@ -191,8 +236,7 @@ fn old_git_no_authtype_capability() { path=git/owner/repo.git/info/refs\n\ \n"; - let nsec = fresh_nsec(); - let out = run_helper(input, &[("NOSTR_PRIVATE_KEY", &nsec)]); + let out = run_helper(input, None, &[]); assert!( out.status.success(), @@ -213,12 +257,10 @@ fn old_git_no_authtype_capability() { ); } -/// No key configured at all → exit 1, stderr mentions "no nostr key configured". +/// No provider item configured → exit 1 without falling back to env or files. #[test] fn missing_key() { - // run_helper already clears NOSTR_PRIVATE_KEY and points HOME at a temp dir - // that has no git config, so no keyfile will be found. - let out = run_helper(&valid_input(), &[]); + let out = run_helper(&valid_input(), None, &[]); assert_eq!( out.status.code(), @@ -228,8 +270,8 @@ fn missing_key() { let stderr = String::from_utf8_lossy(&out.stderr); assert!( - stderr.contains("no nostr key configured"), - "expected 'no nostr key configured' in stderr, got:\n{stderr}" + stderr.contains("identity is unavailable from daz-secrets"), + "expected provider-unavailable identity error in stderr, got:\n{stderr}" ); } @@ -246,8 +288,7 @@ fn missing_method_hint() { wwwauth[]=Nostr realm=\"buzz\"\n\ \n"; - let nsec = fresh_nsec(); - let out = run_helper(input, &[("NOSTR_PRIVATE_KEY", &nsec)]); + let out = run_helper(input, None, &[]); assert!( out.status.success(), @@ -274,8 +315,7 @@ fn missing_path() { wwwauth[]=Nostr realm=\"buzz\", method=\"GET\"\n\ \n"; - let nsec = fresh_nsec(); - let out = run_helper(input, &[("NOSTR_PRIVATE_KEY", &nsec)]); + let out = run_helper(input, None, &[]); assert_eq!( out.status.code(), @@ -290,67 +330,15 @@ fn missing_path() { ); } -/// Keyfile with 0644 permissions → exit 1, stderr mentions "insecure permissions". -#[cfg(unix)] +/// Malformed provider bytes fail closed without emitting a credential. #[test] -fn bad_keyfile_permissions() { - use std::os::unix::fs::PermissionsExt; - - let nsec = fresh_nsec(); - - // Write keyfile to a temp path. - let tmp_dir = std::env::temp_dir(); - let keyfile = tmp_dir.join(format!( - "nostr-test-key-{}.nsec", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .subsec_nanos() - )); - std::fs::write(&keyfile, &nsec).expect("failed to write temp keyfile"); - - // Set insecure permissions (0644). - std::fs::set_permissions(&keyfile, std::fs::Permissions::from_mode(0o644)) - .expect("failed to set permissions"); - - // Point a scratch git config at the keyfile. - let git_config_dir = tmp_dir.join(format!( - "nostr-test-gitconfig-{}", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .subsec_nanos() - )); - std::fs::create_dir_all(&git_config_dir).unwrap(); - let git_config_file = git_config_dir.join(".gitconfig"); - std::fs::write( - &git_config_file, - format!("[nostr]\n\tkeyfile = {}\n", keyfile.display()), - ) - .expect("failed to write git config"); - - let out = run_helper( - &valid_input(), - &[ - ("HOME", git_config_dir.to_str().unwrap()), - ("GIT_CONFIG_GLOBAL", git_config_file.to_str().unwrap()), - ], - ); - - // Clean up regardless of outcome. - let _ = std::fs::remove_file(&keyfile); - let _ = std::fs::remove_file(&git_config_file); - let _ = std::fs::remove_dir(&git_config_dir); - - assert_eq!( - out.status.code(), - Some(1), - "expected exit 1 for insecure keyfile permissions" - ); - +fn malformed_provider_key_fails_closed() { + let out = run_helper(&valid_input(), Some("not-a-private-key"), &[]); + assert_eq!(out.status.code(), Some(1)); let stderr = String::from_utf8_lossy(&out.stderr); assert!( - stderr.contains("insecure permissions"), - "expected 'insecure permissions' in stderr, got:\n{stderr}" + stderr.contains("invalid nostr private key"), + "got:\n{stderr}" ); + assert!(!String::from_utf8_lossy(&out.stdout).contains("credential=")); } diff --git a/crates/git-sign-nostr/Cargo.toml b/crates/git-sign-nostr/Cargo.toml index 4a9aef0d9b..62402a7e11 100644 --- a/crates/git-sign-nostr/Cargo.toml +++ b/crates/git-sign-nostr/Cargo.toml @@ -28,6 +28,7 @@ hex = { workspace = true } # Secret key zeroization on drop. zeroize = { workspace = true, features = ["derive"] } +daz-secrets = { workspace = true } # Nostr key parsing (nsec/npub bech32), secp256k1 Schnorr signing, SHA-256. # Uses the full default feature set because we need: Keys, PublicKey, diff --git a/crates/git-sign-nostr/README.md b/crates/git-sign-nostr/README.md index 908682fd7f..139b688a77 100644 --- a/crates/git-sign-nostr/README.md +++ b/crates/git-sign-nostr/README.md @@ -14,7 +14,8 @@ git config tag.gpgsign true git config user.signingkey # Set the private key (env var) -export NOSTR_PRIVATE_KEY= +git config nostr.secretService buzz-desktop +git config nostr.secretAccount identity # Optional: NIP-OA owner attestation export BUZZ_AUTH_TAG='["auth","","",""]' @@ -28,9 +29,10 @@ git verify-commit HEAD ## Key Loading Priority -1. `NOSTR_PRIVATE_KEY` environment variable -2. `BUZZ_PRIVATE_KEY` environment variable -3. Keyfile at path from `git config nostr.keyfile` +The signing identity is read from the local `daz-secrets` provider. The Git +configuration keys `nostr.secretService` and `nostr.secretAccount` select the +entry and default to `buzz-desktop` / `identity`. Private key bytes are never +accepted through environment variables, argv, or files. Keys may be hex (64 chars) or NIP-19 bech32 (`nsec1...`). diff --git a/crates/git-sign-nostr/src/lib.rs b/crates/git-sign-nostr/src/lib.rs index d316711200..900b93ad9e 100644 --- a/crates/git-sign-nostr/src/lib.rs +++ b/crates/git-sign-nostr/src/lib.rs @@ -42,10 +42,9 @@ //! may optimize this away). The `SecretKey` type in the nostr crate wraps //! `secp256k1::SecretKey` which also lacks `Zeroize`, so some residual copies //! may persist until the process exits (short-lived by design). -//! - **Environment variables:** Private keys in env vars are inherently risky -//! (visible in `/proc`, shell history, crash dumps). Prefer keyfile storage. -//! Env vars are removed from the process environment immediately after reading -//! to minimize the exposure window. +//! - **Secret storage:** Private keys are loaded on demand from the configured +//! `daz-secrets` provider. They are never accepted through environment +//! variables, command-line arguments, or files. //! - **Unsafe code:** This crate uses minimal `unsafe` for Unix fd operations //! (`from_raw_fd`, `fcntl`) where no safe Rust API exists. Each block is //! documented with safety invariants. This is an accepted exception to the @@ -84,7 +83,7 @@ use chrono::DateTime; use nostr::hashes::sha256::Hash as Sha256Hash; use nostr::hashes::{Hash, HashEngine}; use nostr::secp256k1::schnorr::Signature; -use nostr::secp256k1::{Keypair, Message}; +use nostr::secp256k1::{Keypair, Message, XOnlyPublicKey}; use nostr::{FromBech32, PublicKey, SecretKey, SECP256K1}; use zeroize::Zeroize; @@ -389,64 +388,32 @@ macro_rules! status_or_fail { }; } -/// Load the private key from env vars or git config keyfile. -/// -/// Priority: NOSTR_PRIVATE_KEY > BUZZ_PRIVATE_KEY > git config nostr.keyfile +/// Load the private key from the configured daz-secrets provider. /// /// Returns a zeroize-on-drop string containing the raw key material. fn load_key() -> Result, Error> { - // 1. NOSTR_PRIVATE_KEY - if let Ok(mut val) = std::env::var("NOSTR_PRIVATE_KEY") { - // Cap at 128 bytes: nsec1 bech32 is ~63 chars, hex is 64 chars. - // 128 bytes is generous headroom; anything larger is malformed input. - if val.len() > 128 { - val.zeroize(); - std::env::remove_var("NOSTR_PRIVATE_KEY"); - return Err(Error::Fatal( - "NOSTR_PRIVATE_KEY exceeds 128-byte size limit".to_string(), - )); - } - let trimmed = val.trim().to_string(); - val.zeroize(); - // Remove from process environment to minimize exposure window - std::env::remove_var("NOSTR_PRIVATE_KEY"); - if !trimmed.is_empty() { - return Ok(zeroize::Zeroizing::new(trimmed)); - } + let service = git_config("nostr.secretService").unwrap_or_else(|| "buzz-desktop".into()); + let account = git_config("nostr.secretAccount").unwrap_or_else(|| "identity".into()); + let client = daz_secrets::BlockingClient::from_default_config() + .map_err(|_| Error::Fatal("secret provider is unavailable".into()))?; + let secret = client + .get(&service, &account) + .map_err(|_| Error::Fatal("signing identity is unavailable".into()))?; + if secret.value.len() > 128 { + return Err(Error::Fatal( + "signing identity exceeds 128-byte size limit".into(), + )); } - - // 2. BUZZ_PRIVATE_KEY - if let Ok(mut val) = std::env::var("BUZZ_PRIVATE_KEY") { - // Cap at 128 bytes: nsec1 bech32 is ~63 chars, hex is 64 chars. - // 128 bytes is generous headroom; anything larger is malformed input. - if val.len() > 128 { - val.zeroize(); - std::env::remove_var("BUZZ_PRIVATE_KEY"); - return Err(Error::Fatal( - "BUZZ_PRIVATE_KEY exceeds 128-byte size limit".to_string(), - )); - } - let trimmed = val.trim().to_string(); - val.zeroize(); - // Remove from process environment to minimize exposure window - std::env::remove_var("BUZZ_PRIVATE_KEY"); - if !trimmed.is_empty() { - return Ok(zeroize::Zeroizing::new(trimmed)); - } + let mut value = zeroize::Zeroizing::new( + String::from_utf8(secret.value) + .map_err(|_| Error::Fatal("signing identity is not valid UTF-8".into()))?, + ); + let trimmed = zeroize::Zeroizing::new(value.trim().to_string()); + value.zeroize(); + if trimmed.is_empty() { + return Err(Error::Fatal("signing identity is empty".into())); } - - // 3. nostr.keyfile git config - let path = git_config("nostr.keyfile").ok_or_else(|| { - Error::Fatal( - "no key available: set NOSTR_PRIVATE_KEY, BUZZ_PRIVATE_KEY, \ - or git config nostr.keyfile" - .to_string(), - ) - })?; - - // Delegate to read_keyfile_secure which handles permission checks, - // size limits, and Zeroizing wrapping in one place. - read_keyfile_secure(&path) + Ok(trimmed) } /// Load the NIP-OA auth tag from env or git config. @@ -766,123 +733,6 @@ fn git_config_strict(key: &str) -> Result, String> { } } -/// Open a keyfile with symlink rejection and permission checks. -/// -/// Uses `O_NOFOLLOW` to reject symlinks atomically at the kernel level (no -/// TOCTOU between stat and open). Uses `O_NONBLOCK` to prevent blocking on -/// FIFOs — cleared after confirming the path is a regular file. Then fstats -/// the opened handle to verify permissions. Returns the opened file handle. -#[cfg(unix)] -fn open_keyfile(path: &str) -> Result { - use std::os::unix::fs::{MetadataExt, OpenOptionsExt, PermissionsExt}; - use std::os::unix::io::AsRawFd; - - // O_NOFOLLOW: fail with ELOOP if path is a symlink. - // O_NONBLOCK: prevent blocking if path is a FIFO (cleared below once we - // confirm it's a regular file). - let file = fs::OpenOptions::new() - .read(true) - .custom_flags(libc::O_NOFOLLOW | libc::O_NONBLOCK) - .open(path) - .map_err(|e| { - if e.raw_os_error() == Some(libc::ELOOP) { - Error::Fatal(format!("keyfile {path} is a symlink (not allowed)")) - } else { - Error::Fatal(format!("cannot open keyfile {path}: {e}")) - } - })?; - - // fstat the opened handle — no TOCTOU since we already have the fd - let meta = file - .metadata() - .map_err(|e| Error::Fatal(format!("cannot stat keyfile {path}: {e}")))?; - - if !meta.file_type().is_file() { - return Err(Error::Fatal(format!( - "keyfile {path} is not a regular file" - ))); - } - - // Clear O_NONBLOCK now that we know it's a regular file — reads on regular - // files are always non-blocking anyway, but clearing it is cleaner. - let fd = file.as_raw_fd(); - // SAFETY EXCEPTION: Required for Unix fd operations; no safe Rust API exists - // for fcntl F_GETFL/F_SETFL. The fd comes from a File we just opened and - // fstat'd — it is valid for the duration of this block. We only modify the - // O_NONBLOCK flag; no memory is read or written through the fd here. - unsafe { - let flags = libc::fcntl(fd, libc::F_GETFL); - if flags >= 0 { - libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK); - } - } - - let mode = meta.permissions().mode() & 0o777; - if mode & 0o177 != 0 { - return Err(Error::Fatal(format!( - "keyfile {path} has insecure permissions {mode:04o} (expected 0600 or 0400)" - ))); - } - - // Verify the keyfile is owned by the current user. A 0600 file owned by - // another UID could still be readable via ACLs or privileged execution. - // SAFETY EXCEPTION: getuid(2) has no preconditions and no side effects. - let current_uid = unsafe { libc::getuid() }; - if meta.uid() != current_uid { - return Err(Error::Fatal(format!( - "keyfile {path} is owned by uid {} but current uid is {current_uid}", - meta.uid() - ))); - } - - Ok(file) -} - -#[cfg(not(unix))] -fn check_keyfile_permissions(_path: &str) -> Result<(), Error> { - // No permission checking on non-unix platforms. - Ok(()) -} - -/// Read a keyfile securely, returning its trimmed contents as a `Zeroizing`. -/// -/// Performs platform-appropriate permission/symlink checks, enforces the 1 KB -/// size limit, and wraps the buffer in `Zeroizing` from the moment it is -/// allocated so the secret material is erased on drop regardless of the return -/// path. -fn read_keyfile_secure(path: &str) -> Result, Error> { - // Max keyfile size: nsec1 bech32 is ~63 chars, hex is 64 chars. - // 1 KB allows generous headroom for whitespace/newlines. - const MAX_KEYFILE: u64 = 1024; - - #[cfg(unix)] - let file = open_keyfile(path)?; - - #[cfg(not(unix))] - let file = { - check_keyfile_permissions(path)?; - fs::File::open(path) - .map_err(|e| Error::Fatal(format!("cannot open keyfile {path}: {e}")))? - }; - - // Allocate inside Zeroizing immediately so the buffer is erased on any - // early-return error path, not just on the success path. - let mut buf = zeroize::Zeroizing::new(String::new()); - file.take(MAX_KEYFILE + 1) - .read_to_string(&mut buf) - .map_err(|e| Error::Fatal(format!("cannot read keyfile {path}: {e}")))?; - if buf.len() as u64 > MAX_KEYFILE { - return Err(Error::Fatal(format!( - "keyfile {path} exceeds {MAX_KEYFILE} byte limit" - ))); - } - - // Trim in-place: build a new Zeroizing from the trimmed slice, - // then let the original (with leading/trailing whitespace) be zeroized. - let trimmed = zeroize::Zeroizing::new(buf.trim().to_string()); - Ok(trimmed) -} - /// Compute the NIP-GS signing hash. /// /// ```text @@ -1373,6 +1223,7 @@ fn parse_envelope(json_str: &str) -> Result { .as_str() .ok_or("pk must be a string")?; validate_hex_field(pk, 64, "pk")?; + validate_xonly_public_key(pk).map_err(|e| format!("pk is not a valid BIP-340 key: {e}"))?; // sig (required, 128-char lowercase hex) let sig = obj @@ -1420,7 +1271,7 @@ fn parse_envelope(json_str: &str) -> Result { } // Validate oa[0] is a valid BIP-340 x-only public key (not just hex) - PublicKey::from_hex(owner) + validate_xonly_public_key(owner) .map_err(|e| format!("oa[0] is not a valid BIP-340 public key: {e}"))?; // Self-attestation is meaningless — owner must differ from signer @@ -1461,6 +1312,13 @@ fn validate_hex_field(val: &str, expected_len: usize, name: &str) -> Result<(), Ok(()) } +fn validate_xonly_public_key(value: &str) -> Result<(), String> { + let bytes = hex::decode(value).map_err(|error| error.to_string())?; + XOnlyPublicKey::from_slice(&bytes) + .map(|_| ()) + .map_err(|error| error.to_string()) +} + fn parse_armor(content: &str) -> Result<&str, String> { // NIP-GS spec requires armor to end with a newline after the END marker. let content = content @@ -2116,8 +1974,10 @@ Initial commit" #[test] fn test_parse_envelope_rejects_invalid_oa_pubkey() { - // oa[0] is valid hex but not a valid BIP-340 point (all zeros) - let zero_pk = "0".repeat(64); + // oa[0] is valid hex but exceeds the secp256k1 field modulus, so it + // cannot encode an x-coordinate. x=0 is not a sound negative fixture: + // current secp256k1 accepts it because a curve point exists at x=0. + let invalid_pk = "f".repeat(64); let fake_sig = "b".repeat(128); let sig_field = "a".repeat(128); let json = [ @@ -2126,7 +1986,7 @@ Initial commit" r#"","sig":""#, &sig_field, r#"","t":1700000000,"oa":[""#, - &zero_pk, + &invalid_pk, r#"","",""#, &fake_sig, r#""]}"#, diff --git a/desktop/package.json b/desktop/package.json index a1fd2e919d..95f8a83641 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -14,7 +14,7 @@ "lint": "biome lint .", "check": "biome check . && pnpm check:file-sizes && pnpm check:px-text && pnpm check:pubkey-truncation", "format": "biome format --write .", - "test": "node --import ./test-loader.mjs --experimental-strip-types --test \"src/**/*.test.mjs\"", + "test": "node --no-experimental-webstorage --import ./test-loader.mjs --experimental-strip-types --test \"src/**/*.test.mjs\"", "preview": "vite preview", "tauri": "tauri", "test:e2e": "pnpm build:e2e && playwright test", diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index fbaa547a03..0ab899a92d 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -52,9 +52,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +checksum = "f8eb277bec05f56a0e0591f155a484cbd0f4f07ff2905051a48c72f004f7ed58" dependencies = [ "cipher 0.5.2", "cpubits", @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -105,7 +105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda177466b9524d59f1b12f0dd30b68696788e9992a7e959021c4a0ed96fcf59" dependencies = [ "base64 0.22.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "home", "libc", "log", @@ -150,7 +150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" dependencies = [ "alsa-sys", - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "libc", ] @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -226,9 +226,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "approx" @@ -395,7 +395,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -424,20 +424,20 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "async-utility" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34a3b57207a7a1007832416c3e4862378c8451b4e8e093e436f48c2d3d2c151" +checksum = "188f83b9a198af8c336e505611edb00d6d2ac5c694241c5a4f9a12316938cfe9" dependencies = [ "futures-util", "gloo-timers", @@ -526,7 +526,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84790c55b5704b0d35130bf16a4ce22a8e70eb0ea773522557524d9a4852663d" dependencies = [ "nix 0.30.1", - "rand 0.9.4", + "rand 0.9.5", ] [[package]] @@ -542,7 +542,7 @@ dependencies = [ "serde", "serde_json", "url", - "webpki-roots 1.0.8", + "webpki-roots 1.0.9", ] [[package]] @@ -611,16 +611,16 @@ dependencies = [ "quick-xml 0.38.4", "rust-ini", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "url", ] [[package]] name = "aws-lc-rs" -version = "1.17.1" +version = "1.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" +checksum = "00bdb5da18dac48ca2cc7cd4a98e533e8635a58e2361d13a1a4ee3888e0d72f1" dependencies = [ "aws-lc-sys", "zeroize", @@ -628,9 +628,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.42.0" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" +checksum = "43103168cc76fe62678a375e722fc9cb3a0146159ac5828bc4f0dfd755c2224c" dependencies = [ "cc", "cmake", @@ -645,7 +645,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "838b36c8dc927b6db1b6c6b8f5d05865f2213550b9e83bf92fa99ed6525472c0" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -675,7 +675,7 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1 0.10.6", + "sha1 0.10.7", "sync_wrapper", "tokio", "tokio-tungstenite 0.29.0", @@ -712,7 +712,7 @@ checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -811,21 +811,20 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitcoin-consensus-encoding" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2d6094e2a1ba3c93b5a596fe5a10d1a10c3c6e06785cde89f693a044c01aa40" +checksum = "207311705279250ba465076a1bac4b1ac982855fff73fc5f67e22158ac58cdc9" dependencies = [ "bitcoin-internals", + "hex-conservative 1.2.0", + "serde", ] [[package]] name = "bitcoin-internals" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" -dependencies = [ - "hex-conservative 0.3.2", -] +checksum = "d573f4cf32996a8dce612e4348cece65a241f1882ed594047c9ba348e8869fa5" [[package]] name = "bitcoin-io" @@ -855,9 +854,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" dependencies = [ "serde_core", ] @@ -963,7 +962,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -998,9 +997,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.3" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530" dependencies = [ "memchr", "regex-automata", @@ -1052,7 +1051,7 @@ dependencies = [ "serde_json", "sha2 0.11.0", "subtle", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "uuid", "zeroize", @@ -1080,6 +1079,7 @@ dependencies = [ "bzip2 0.6.1", "chrono", "ctrlc", + "daz-secrets", "dirs", "earshot", "ed25519-dalek", @@ -1090,7 +1090,6 @@ dependencies = [ "image", "infer", "iroh", - "keyring", "libc", "mesh-llm-client", "mesh-llm-events", @@ -1115,7 +1114,6 @@ dependencies = [ "rubato", "rusqlite", "rustls", - "security-framework 3.7.0", "serde", "serde_json", "serde_yaml", @@ -1173,7 +1171,7 @@ dependencies = [ "serde_json", "sha2 0.11.0", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tracing", @@ -1188,7 +1186,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -1199,7 +1197,7 @@ dependencies = [ "nostr", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", "uuid", ] @@ -1239,9 +1237,9 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" [[package]] name = "byteorder" @@ -1299,7 +1297,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cairo-sys-rs", "glib", "libc", @@ -1320,9 +1318,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" dependencies = [ "serde_core", ] @@ -1347,7 +1345,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -1380,9 +1378,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.66" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" dependencies = [ "find-msvc-tools", "jobserver", @@ -1437,9 +1435,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" @@ -1513,9 +1511,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "301b56658598e48f3648647ac6fc887be7e7108eddfa4e9b63fcf3ec58c0cadf" dependencies = [ "clap_builder", "clap_derive", @@ -1523,9 +1521,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "94a65403d1a1bd28f7dc68eb8506e8874808ee5eecb59298de588e2e1407a078" dependencies = [ "anstream", "anstyle", @@ -1535,14 +1533,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1581,7 +1579,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -1732,9 +1730,9 @@ dependencies = [ [[package]] name = "cordyceps" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +checksum = "5b9ab7e0ca1d179628fa0172b2b97203c7fa0cd81be2448bd446fb9559ca9261" dependencies = [ "loom", "tracing", @@ -1772,7 +1770,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation 0.10.1", "core-graphics-types", "foreign-types 0.5.0", @@ -1785,7 +1783,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation 0.10.1", "libc", ] @@ -1796,7 +1794,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2-audio-toolbox", "objc2-core-audio", @@ -1922,7 +1920,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "mio", "parking_lot", @@ -1938,7 +1936,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "derive_more", "document-features", @@ -1983,6 +1981,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", + "rand_core 0.10.1", ] [[package]] @@ -2044,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2069,9 +2068,9 @@ dependencies = [ [[package]] name = "ctor" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb22e947478ccf9dc44d8922042c677a63fbb88f2cb468521d1145816e5087cb" +checksum = "2d83cb7e7a873830708d6b02a78cd36a592c6fa14bf267b68725103b85c0d77f" dependencies = [ "link-section", "linktime-proc-macro", @@ -2135,9 +2134,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "5.0.0-rc.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f359e08ca85e7bd759e1fd933ff2bccd81864c60a8fba0e259c7f822b0924bf" +checksum = "b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.3.0", @@ -2159,7 +2158,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2182,6 +2181,16 @@ dependencies = [ "darling_macro 0.23.0", ] +[[package]] +name = "darling" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88490bf1b990d87eaaa7ac8aa887f629a08e7359765b4911faf63c3763347d23" +dependencies = [ + "darling_core 0.24.0", + "darling_macro 0.24.0", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -2193,7 +2202,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2206,7 +2215,20 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084e274f91c482280130e1e34e0b8d6e66776a060d7b6de7b84289ca778868c4" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 3.0.3", ] [[package]] @@ -2217,7 +2239,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2228,7 +2250,18 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5792fa0d41cd2325ce0ffa64f0a340eaebd4971a3a0c5e1ffd2cc488a355e" +dependencies = [ + "darling_core 0.24.0", + "quote", + "syn 3.0.3", ] [[package]] @@ -2248,15 +2281,15 @@ checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" [[package]] name = "data-encoding" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "data-encoding-macro" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c" +checksum = "c6a127ecbb3c4632e1525380e04c0c3fcf8dcb44d32a79ea290d8a36906edcd8" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2264,12 +2297,27 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" +checksum = "c54e03a951783e8b327515db3f2a2fd0e3bed362a96b066f341ce66ed49b4ead" dependencies = [ "data-encoding", - "syn 2.0.118", + "syn 3.0.3", +] + +[[package]] +name = "daz-secrets" +version = "0.1.0-alpha.1" +source = "git+https://github.com/darrenoakey/daz-secrets?rev=ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa#ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa" +dependencies = [ + "directories", + "nix 0.30.1", + "rand 0.9.5", + "serde", + "tokio", + "tokio-util", + "toml 0.9.12+spec-1.1.0", + "windows-permissions", ] [[package]] @@ -2283,25 +2331,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "dbus-secret-service" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708b509edf7889e53d7efb0ffadd994cc6c2345ccb62f55cfd6b0682165e4fa6" -dependencies = [ - "aes 0.8.4", - "block-padding", - "cbc", - "dbus", - "fastrand", - "hkdf", - "num", - "once_cell", - "openssl", - "sha2 0.10.9", - "zeroize", -] - [[package]] name = "deflate64" version = "0.1.12" @@ -2342,7 +2371,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2363,7 +2392,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2373,7 +2402,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2395,7 +2424,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.118", + "syn 2.0.119", "unicode-xid", ] @@ -2429,6 +2458,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs" version = "6.0.0" @@ -2456,7 +2494,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "libc", "objc2", @@ -2464,13 +2502,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -2493,7 +2531,7 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2588,9 +2626,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "earshot" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7984231f8b4c72eb3b88c70040dc1e4ff6803fa9169e93c0ac465942d74fa36a" +checksum = "86b09710f15e995d175f80aa9101f37cd2bc12bb45593e7eac1809ab99acd1ab" [[package]] name = "ed25519" @@ -2609,7 +2647,7 @@ version = "3.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b011170fe4f04665565b4110afef66774fe9ffff278f3eb5b81cc73d26e27d60" dependencies = [ - "curve25519-dalek 5.0.0-rc.0", + "curve25519-dalek 5.0.0", "ed25519", "rand_core 0.10.1", "serde", @@ -2621,9 +2659,9 @@ dependencies = [ [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" [[package]] name = "embed-resource" @@ -2634,7 +2672,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 1.1.2+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", "vswhom", "winreg 0.55.0", ] @@ -2680,7 +2718,7 @@ checksum = "3ed8956bd5c1f0415200516e78ff07ec9e16415ade83c056c230d7b7ea0d55b7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2701,7 +2739,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2754,11 +2792,10 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.4.1" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" dependencies = [ - "concurrent-queue", "parking", "pin-project-lite", ] @@ -2812,17 +2849,11 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fax" @@ -2925,7 +2956,7 @@ checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" dependencies = [ "futures-core", "futures-sink", - "spin 0.9.8", + "spin 0.9.9", ] [[package]] @@ -2967,13 +2998,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -3005,9 +3036,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" dependencies = [ "futures-channel", "futures-core", @@ -3028,14 +3059,14 @@ dependencies = [ "diatomic-waker", "futures-core", "pin-project-lite", - "spin 0.10.0", + "spin 0.10.1", ] [[package]] name = "futures-channel" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" dependencies = [ "futures-core", "futures-sink", @@ -3043,15 +3074,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" [[package]] name = "futures-executor" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" dependencies = [ "futures-core", "futures-task", @@ -3060,9 +3091,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" [[package]] name = "futures-lite" @@ -3079,32 +3110,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "futures-sink" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ "futures-channel", "futures-core", @@ -3369,7 +3400,7 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3378,7 +3409,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "futures-channel", "futures-core", "futures-executor", @@ -3406,7 +3437,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3421,9 +3452,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "global-hotkey" @@ -3437,7 +3468,7 @@ dependencies = [ "objc2-app-kit", "once_cell", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows-sys 0.59.0", "x11rb", "xkeysym", @@ -3445,9 +3476,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.18" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" dependencies = [ "aho-corasick", "bstr", @@ -3528,7 +3559,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3654,51 +3685,56 @@ dependencies = [ [[package]] name = "hex-conservative" -version = "0.3.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" +checksum = "35431185f361ccf3ffc58254628af5f1f5d5f28531da2e02e5d6c82bbc282a10" dependencies = [ "arrayvec", ] [[package]] name = "hf-hub" -version = "1.0.0-rc.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89305dc8fe34e165eaf0eb12b6e294e12381d9df9a431bcc52a5809bab4319" +checksum = "e7ccb6bcc85dec15413ef5949879f9a5497ca4568ed702547eb83fac23376e5c" dependencies = [ "base64 0.22.1", "bon", "bytes", "futures", + "getrandom 0.2.17", "globset", "hf-xet", "hyper", "pathdiff", + "percent-encoding", "reqwest 0.13.4", "serde", "serde_json", "sha2 0.11.0", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-retry", "tokio-util", "tracing", "url", + "wasm-bindgen-futures", ] [[package]] name = "hf-xet" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba6e94f549dbe76ced2c56ada52958e63f9056afabb21f74aae1b5777c8cd5d" +checksum = "c237ef4fb0ce1962a5117f8bd8c74454b41629826a9df17d14a1840ca18f0754" dependencies = [ + "anyhow", "async-trait", "bytes", "http", "more-asserts", "serde", - "thiserror 2.0.18", + "serde_json", + "thiserror 2.0.19", "tokio", "tokio-util", "tokio_with_wasm", @@ -3731,7 +3767,7 @@ dependencies = [ "jni 0.22.4", "rand 0.10.2", "rustls", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tokio", "tokio-rustls", @@ -3753,7 +3789,7 @@ dependencies = [ "prefix-trie", "rand 0.10.2", "ring", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "url", @@ -3781,21 +3817,12 @@ dependencies = [ "rustls", "smallvec", "system-configuration", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-rustls", "tracing", ] -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac 0.12.1", -] - [[package]] name = "hmac" version = "0.12.1" @@ -3835,9 +3862,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -3845,9 +3872,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http", @@ -3855,9 +3882,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" dependencies = [ "bytes", "futures-core", @@ -3886,18 +3913,18 @@ checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" [[package]] name = "hybrid-array" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" dependencies = [ "typenum", ] [[package]] name = "hyper" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" dependencies = [ "atomic-waker", "bytes", @@ -3928,7 +3955,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.8", + "webpki-roots 1.0.9", ] [[package]] @@ -4261,15 +4288,15 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" +checksum = "2bf84e73fa6f27f299dec58e13223cf70db80da872eb921d4f6138342a0eabc8" dependencies = [ - "darling 0.23.0", + "darling 0.24.0", "indoc", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -4299,23 +4326,23 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78" dependencies = [ "serde", ] [[package]] name = "iroh" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fca9b4b462c343ff88fc0af4096c186f939b602a0bc08723536ef2c31c93971" +checksum = "460de6bc52163b41b1646931f2897e5ab986f0966ade444467fec25024751a72" dependencies = [ "backon", "blake3", "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "ctutils", "data-encoding", "derive_more", @@ -4359,11 +4386,11 @@ dependencies = [ [[package]] name = "iroh-base" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830a582cd54410dc1aa71d4786a82c3297d7b0165accd8b6dbbb3b240b48140d" +checksum = "6be73e16ee21c923aca9b3121aaa0db936f7c7ecc156ff47b8dac944c68d59a8" dependencies = [ - "curve25519-dalek 5.0.0-rc.0", + "curve25519-dalek 5.0.0", "data-encoding", "data-encoding-macro", "derive_more", @@ -4378,12 +4405,12 @@ dependencies = [ [[package]] name = "iroh-dns" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516e4eedc38e33ab69a6bd325520332dc3d67b25454e2d590ebb84a25240dd9a" +checksum = "46f6a9b39d18e6345f5c151afd299f2488e2cb5c520fe41b107b6bd3dc4c3349" dependencies = [ "arc-swap", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "derive_more", "hickory-resolver", "iroh-base", @@ -4424,18 +4451,18 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "iroh-relay" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8149bb6a57126225a07d6928846d82dcedfd24ea0f863ef7b2eb475e1d726354" +checksum = "24bd586cf927f7b700f56ec3639b53cb5fa901ce284784051ff71092bfbf8193" dependencies = [ "blake3", "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "data-encoding", "derive_more", "getrandom 0.4.3", @@ -4447,7 +4474,7 @@ dependencies = [ "iroh-base", "iroh-dns", "iroh-metrics", - "lru 0.18.1", + "lru 0.18.2", "n0-error", "n0-future", "noq", @@ -4468,8 +4495,7 @@ dependencies = [ "tokio-websockets", "tracing", "url", - "vergen-gitcl", - "webpki-roots 1.0.8", + "webpki-roots 1.0.9", "ws_stream_wasm", ] @@ -4564,7 +4590,7 @@ dependencies = [ "jni-sys 0.4.1", "log", "simd_cesu8", - "thiserror 2.0.18", + "thiserror 2.0.19", "walkdir", "windows-link 0.2.1", ] @@ -4579,7 +4605,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4607,7 +4633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4671,7 +4697,7 @@ checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" dependencies = [ "hashbrown 0.16.1", "portable-atomic", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -4680,28 +4706,11 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "serde", "unicode-segmentation", ] -[[package]] -name = "keyring" -version = "3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c" -dependencies = [ - "byteorder", - "dbus-secret-service", - "log", - "openssl", - "secret-service", - "security-framework 2.11.1", - "security-framework 3.7.0", - "windows-sys 0.60.2", - "zeroize", -] - [[package]] name = "konst" version = "0.4.3" @@ -4763,9 +4772,9 @@ checksum = "34b357333733e8260735ba5894eb928c02ecc69c78715f01a8019e7fa7f2db4c" [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libdbus-sys" @@ -4773,7 +4782,6 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" dependencies = [ - "cc", "pkg-config", ] @@ -4805,9 +4813,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +checksum = "2026a5056764a10b2bf5d56488cba40da507f5493a6a429340e2004d9ed085fa" dependencies = [ "libc", ] @@ -4825,24 +4833,24 @@ dependencies = [ [[package]] name = "line-clipping" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +checksum = "e752191d037c44ad111a8caa762921926658402f01cc1253f7bef2020ece4f5e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] name = "link-section" -version = "0.19.0" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e333fe507b738576d6da5bb3f1a7d7a1c80307ed9ef31624c057d844c19c93e9" +checksum = "5ee1a0d6e252afe82e7bc2db42fba60e02ddf3b1accaf8cb21d96e34ba61f3d4" [[package]] name = "linktime-proc-macro" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7b0a3383c2a1002d11349c92c85a666a5fb679e96c79d782cf0dbe557fd6ee" +checksum = "348d0075b1fc163b26d72a7f75fc5141daf2fd1bdf128d873cbaf6785d495bdf" [[package]] name = "linux-raw-sys" @@ -4904,7 +4912,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4937,9 +4945,9 @@ checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" [[package]] name = "lru" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6180140927ee907000b0aa540091f6ea512ead4447c92b8fc35bc72788a5a6" +checksum = "5d2f2f9b4ba7e6b24d95e7e899329d35be83bcded72c8540cdd5368932d1d90a" dependencies = [ "hashbrown 0.17.1", ] @@ -5085,7 +5093,7 @@ checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5133,17 +5141,17 @@ dependencies = [ [[package]] name = "mesh-llm-api-client" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "hex", "mesh-llm-client", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "mesh-llm-api-server" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-api-client", @@ -5154,12 +5162,12 @@ dependencies = [ [[package]] name = "mesh-llm-build-info" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" [[package]] name = "mesh-llm-client" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -5182,7 +5190,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "uuid", @@ -5191,7 +5199,7 @@ dependencies = [ [[package]] name = "mesh-llm-config" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5200,14 +5208,14 @@ dependencies = [ "serde", "skippy-protocol", "toml 0.9.12+spec-1.1.0", - "toml_edit 0.25.12+spec-1.1.0", + "toml_edit 0.25.13+spec-1.1.0", "url", ] [[package]] name = "mesh-llm-embedded-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-host-runtime", @@ -5217,7 +5225,7 @@ dependencies = [ [[package]] name = "mesh-llm-events" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "clap", @@ -5229,7 +5237,7 @@ dependencies = [ [[package]] name = "mesh-llm-gpu-bench" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "cc", @@ -5242,7 +5250,7 @@ dependencies = [ [[package]] name = "mesh-llm-guardrails" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "serde", "serde_json", @@ -5251,7 +5259,7 @@ dependencies = [ [[package]] name = "mesh-llm-hardware-profile" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "mesh-llm-native-runtime", ] @@ -5259,7 +5267,7 @@ dependencies = [ [[package]] name = "mesh-llm-host-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "argon2", @@ -5283,7 +5291,6 @@ dependencies = [ "httparse", "iroh", "json5", - "keyring", "libc", "mdns-sd", "mesh-llm-api-server", @@ -5321,7 +5328,7 @@ dependencies = [ "rmcp", "rpassword", "rustls", - "schemars 1.2.1", + "schemars 1.2.2", "semver", "serde", "serde_json", @@ -5337,7 +5344,7 @@ dependencies = [ "tabwriter", "tar", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "toml 0.9.12+spec-1.1.0", @@ -5352,29 +5359,29 @@ dependencies = [ [[package]] name = "mesh-llm-identity" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "argon2", "base64 0.22.1", "chacha20poly1305", "chrono", "crypto_box", + "daz-secrets", "dirs", "ed25519-dalek", "hex", - "keyring", "rand 0.10.2", "serde", "serde_json", "sha2 0.10.9", - "thiserror 2.0.18", + "thiserror 2.0.19", "zeroize", ] [[package]] name = "mesh-llm-native-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "serde", @@ -5385,7 +5392,7 @@ dependencies = [ [[package]] name = "mesh-llm-node" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-types", @@ -5399,7 +5406,7 @@ dependencies = [ [[package]] name = "mesh-llm-plugin" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -5407,7 +5414,7 @@ dependencies = [ "prost-build 0.14.4", "protoc-bin-vendored", "rmcp", - "schemars 1.2.1", + "schemars 1.2.2", "serde", "serde_json", "tokio", @@ -5416,7 +5423,7 @@ dependencies = [ [[package]] name = "mesh-llm-plugin-manager" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5435,7 +5442,7 @@ dependencies = [ [[package]] name = "mesh-llm-protocol" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "hex", @@ -5448,7 +5455,7 @@ dependencies = [ [[package]] name = "mesh-llm-routing" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "iroh", ] @@ -5456,7 +5463,7 @@ dependencies = [ [[package]] name = "mesh-llm-runtime-install" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5479,7 +5486,7 @@ dependencies = [ [[package]] name = "mesh-llm-sdk" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "mesh-llm-api-client", @@ -5494,7 +5501,7 @@ dependencies = [ [[package]] name = "mesh-llm-skills" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "dirs", @@ -5505,7 +5512,7 @@ dependencies = [ [[package]] name = "mesh-llm-system" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "chrono", @@ -5528,7 +5535,7 @@ dependencies = [ [[package]] name = "mesh-llm-types" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "hex", "serde", @@ -5539,12 +5546,12 @@ dependencies = [ [[package]] name = "mesh-llm-ui" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" [[package]] name = "mesh-mixture-of-agents" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "async-trait", "mesh-llm-guardrails", @@ -5574,7 +5581,7 @@ checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5626,9 +5633,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "log", @@ -5648,7 +5655,7 @@ dependencies = [ [[package]] name = "model-artifact" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -5659,7 +5666,7 @@ dependencies = [ [[package]] name = "model-hf" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "async-trait", @@ -5677,7 +5684,7 @@ dependencies = [ [[package]] name = "model-package" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "bytes", @@ -5697,7 +5704,7 @@ dependencies = [ [[package]] name = "model-ref" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "serde", ] @@ -5705,7 +5712,7 @@ dependencies = [ [[package]] name = "model-resolver" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "model-artifact", @@ -5750,7 +5757,7 @@ checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5800,7 +5807,7 @@ dependencies = [ "once_cell", "png 0.18.1", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows-sys 0.61.2", ] @@ -5828,7 +5835,7 @@ checksum = "e2acd8b070213b0299282f884b4beba4e7b52d624fdcd504a3ad3665390c11e1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5837,7 +5844,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2ab99dfb861450e68853d34ae665243a88b8c493d01ba957321a1e9b2312bbe" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "derive_more", "futures-buffered", "futures-lite", @@ -5875,7 +5882,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "tempfile", ] @@ -5901,7 +5908,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -5973,9 +5980,9 @@ dependencies = [ [[package]] name = "netlink-packet-core" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3463cbb78394cb0141e2c926b93fc2197e473394b761986eca3b9da2c63ae0f4" +checksum = "b897d7bd4f0af82e68d40d0344cf37e97f9c97ddf74a098de3e4da05e96ca395" dependencies = [ "paste", ] @@ -5986,7 +5993,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2288fcb784eb3defd5fb16f4c4160d5f477de192eac730f43e1d11c24d9a007" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "log", "netlink-packet-core", @@ -5994,16 +6001,17 @@ dependencies = [ [[package]] name = "netlink-proto" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65d130ee111430e47eed7896ea43ca693c387f097dd97376bffafbf25812128" +checksum = "e6f7398dddf5f152d2a91a2921a134c6097056e292c0d4b9906007855e7cece6" dependencies = [ "bytes", - "futures", + "futures-channel", + "futures-util", "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -6027,7 +6035,7 @@ checksum = "4d9cbe01741347ef750d743d6690603f5eed8341e679fb51c8e629337aa11976" dependencies = [ "atomic-waker", "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "derive_more", "ipnet", "js-sys", @@ -6068,7 +6076,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "cfg_aliases 0.1.1", "libc", @@ -6080,9 +6088,9 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "libc", "memoffset", ] @@ -6093,9 +6101,9 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "libc", ] @@ -6105,9 +6113,9 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "libc", ] @@ -6132,12 +6140,12 @@ dependencies = [ [[package]] name = "noq" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf95190af1bd4a00a10e8255ca0c8ddd9e9a9f5e79151d7a7eb6d56aff5dc89" +checksum = "09e4bb6601fa543c110d8957813267d5a8d775a0f8fbaccf1f615d06ba9b10da" dependencies = [ "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "derive_more", "noq-proto", "noq-udp", @@ -6145,7 +6153,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "tracing", @@ -6154,9 +6162,9 @@ dependencies = [ [[package]] name = "noq-proto" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa6c890013591e709a3e45dd53501351b7e27e7ff3c7e9fc3dce43e300e7e9d3" +checksum = "baa7b5ccd819a9c68a0d955e67a881032d09b1a17219b1f90b0997a0888e1a15" dependencies = [ "aes-gcm", "bytes", @@ -6173,7 +6181,7 @@ dependencies = [ "rustls-pki-types", "slab", "sorted-index-buffer", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "web-time", @@ -6181,11 +6189,11 @@ dependencies = [ [[package]] name = "noq-udp" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3137a52df66c20090a889828d1c655f21f52294cba64e5c4fbb04fc83eee7c8e" +checksum = "02bba20e097a5a16cd0ad14ec882fae1e80a092a124e9422fc4dddd92e96a647" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "libc", "socket2", "tracing", @@ -6194,9 +6202,9 @@ dependencies = [ [[package]] name = "nostr" -version = "0.44.7" +version = "0.44.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d3d987ea7078dc36947cde532637c472a229426702e4331dd7667325378bd9" +checksum = "40ff7b77ef428b40aa2834a6acbae38a0e104c98b306208ca4b87a420d579a4b" dependencies = [ "base64 0.22.1", "bech32", @@ -6214,6 +6222,7 @@ dependencies = [ "serde_json", "unicode-normalization", "url", + "zeroize", ] [[package]] @@ -6280,7 +6289,7 @@ dependencies = [ "mac-notification-sys", "serde", "tauri-winrt-notification", - "zbus 5.17.0", + "zbus", ] [[package]] @@ -6301,20 +6310,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.8" @@ -6348,7 +6343,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -6360,16 +6355,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.4.2" @@ -6411,7 +6396,7 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -6439,7 +6424,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-core-foundation", @@ -6453,7 +6438,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2", "objc2-core-audio", @@ -6478,7 +6463,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-foundation", ] @@ -6502,7 +6487,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", ] @@ -6522,7 +6507,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "dispatch2", "libc", @@ -6535,7 +6520,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "objc2", "objc2-core-foundation", @@ -6568,7 +6553,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", "objc2-core-graphics", @@ -6580,7 +6565,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e34919aba0d701380d911702455038a8a3587467fe0141d6a71501e7ffe48" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -6609,7 +6594,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "libc", "objc2", @@ -6632,7 +6617,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", ] @@ -6643,7 +6628,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-app-kit", "objc2-foundation", @@ -6655,7 +6640,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", "objc2-foundation", @@ -6667,7 +6652,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2", "objc2-core-foundation", ] @@ -6688,7 +6673,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "libc", "objc2", @@ -6702,7 +6687,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-cloud-kit", @@ -6723,7 +6708,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-foundation", @@ -6735,7 +6720,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "objc2", "objc2-app-kit", @@ -6773,9 +6758,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open" -version = "5.3.6" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d3b65c44123a56e0133d2cd06ce4361bd3ca99d41198b2f25e3c3db9b8b4a" +checksum = "f9cfef937e9c486488c7e3d949ae31c0f1d06bdacd75b99c086cb35356e30408" dependencies = [ "dunce", "is-wsl", @@ -6785,7 +6770,7 @@ dependencies = [ [[package]] name = "openai-frontend" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "async-trait", "axum", @@ -6805,7 +6790,7 @@ version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if 1.0.4", "foreign-types 0.3.2", "libc", @@ -6821,7 +6806,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -6830,15 +6815,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "openssl-src" -version = "300.6.1+3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" version = "0.9.117" @@ -6847,7 +6823,6 @@ checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] @@ -6862,7 +6837,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", ] @@ -6892,7 +6867,7 @@ dependencies = [ "opentelemetry_sdk", "prost 0.14.4", "reqwest 0.12.28", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -6923,8 +6898,8 @@ dependencies = [ "futures-util", "opentelemetry", "percent-encoding", - "rand 0.9.4", - "thiserror 2.0.18", + "rand 0.9.5", + "thiserror 2.0.19", ] [[package]] @@ -7019,31 +6994,40 @@ dependencies = [ "objc2-osa-kit", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "palette" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" dependencies = [ "approx", - "fast-srgb8", "libm", "palette_derive", + "palette_math", ] [[package]] name = "palette_derive" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" +dependencies = [ + "libm", ] [[package]] @@ -7176,9 +7160,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" +checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" dependencies = [ "memchr", "ucd-trie", @@ -7186,9 +7170,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" +checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd" dependencies = [ "pest", "pest_generator", @@ -7196,22 +7180,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" +checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "pest_meta" -version = "2.8.7" +version = "2.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" +checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c" dependencies = [ "pest", ] @@ -7295,7 +7279,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand 0.8.6", + "rand 0.8.7", ] [[package]] @@ -7318,7 +7302,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7331,7 +7315,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7369,7 +7353,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7437,7 +7421,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crc32fast", "fdeflate", "flate2", @@ -7483,9 +7467,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" dependencies = [ "serde", ] @@ -7570,7 +7554,7 @@ checksum = "e0232bd009a197ceec9cc881ba46f727fcd8060a2d8d6a9dde7a69030a6fe2bb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7627,7 +7611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7665,7 +7649,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.12+spec-1.1.0", + "toml_edit 0.25.13+spec-1.1.0", ] [[package]] @@ -7694,9 +7678,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -7721,9 +7705,9 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "num-traits", - "rand 0.9.4", + "rand 0.9.5", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -7766,7 +7750,7 @@ dependencies = [ "prost 0.13.5", "prost-types 0.13.5", "regex", - "syn 2.0.118", + "syn 2.0.119", "tempfile", ] @@ -7785,7 +7769,7 @@ dependencies = [ "prost 0.14.4", "prost-types 0.14.4", "regex", - "syn 2.0.118", + "syn 2.0.119", "tempfile", ] @@ -7799,7 +7783,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7812,7 +7796,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -7975,14 +7959,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", "rustls", "socket2", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tracing", "web-time", @@ -8005,7 +7989,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror 2.0.19", "tinyvec", "tracing", "web-time", @@ -8017,7 +8001,7 @@ version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" dependencies = [ - "cfg_aliases 0.2.1", + "cfg_aliases 0.2.2", "libc", "once_cell", "socket2", @@ -8027,9 +8011,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -8048,9 +8032,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -8059,9 +8043,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -8172,17 +8156,17 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "compact_str 0.9.1", "critical-section", "hashbrown 0.17.1", "itertools", "kasuari", - "lru 0.18.1", + "lru 0.18.2", "palette", "serde", "strum", - "thiserror 2.0.18", + "thiserror 2.0.19", "unicode-segmentation", "unicode-truncate", "unicode-width 0.2.2", @@ -8237,7 +8221,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "hashbrown 0.17.1", "indoc", "instability", @@ -8318,7 +8302,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -8329,34 +8313,34 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "ref-cast" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "regex" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -8366,9 +8350,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.15" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -8432,7 +8416,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams 0.4.2", "web-sys", - "webpki-roots 1.0.8", + "webpki-roots 1.0.9", ] [[package]] @@ -8491,7 +8475,7 @@ dependencies = [ "async-trait", "http", "reqwest 0.13.4", - "thiserror 2.0.18", + "thiserror 2.0.19", "tower-service", ] @@ -8568,11 +8552,11 @@ dependencies = [ "rand 0.10.2", "reqwest 0.13.4", "rmcp-macros", - "schemars 1.2.1", + "schemars 1.2.2", "serde", "serde_json", "sse-stream", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-stream", "tokio-util", @@ -8591,7 +8575,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -8607,7 +8591,7 @@ dependencies = [ "rand_distr", "rtrb", "symphonia", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -8648,7 +8632,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "165ca6e57b20e1351573e3729b958bc62f0e48025386970b6e4d29e7a7e71f3f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", @@ -8694,7 +8678,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "sysinfo 0.37.2", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "tokio", "tokio-stream", @@ -8736,7 +8720,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -8749,7 +8733,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -8769,9 +8753,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.42" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "aws-lc-rs", "log", @@ -8792,14 +8776,14 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.7.0", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "web-time", "zeroize", @@ -8820,7 +8804,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.7.0", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -8937,14 +8921,14 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" dependencies = [ "chrono", "dyn-clone", "ref-cast", - "schemars_derive 1.2.1", + "schemars_derive 1.2.2", "serde", "serde_json", ] @@ -8957,20 +8941,20 @@ checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", - "serde_derive_internals", - "syn 2.0.118", + "serde_derive_internals 0.29.1", + "syn 2.0.119", ] [[package]] name = "schemars_derive" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" dependencies = [ "proc-macro2", "quote", - "serde_derive_internals", - "syn 2.0.118", + "serde_derive_internals 0.30.0", + "syn 3.0.3", ] [[package]] @@ -9003,7 +8987,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "rand 0.8.6", + "rand 0.8.7", "secp256k1-sys", "serde", ] @@ -9017,45 +9001,13 @@ dependencies = [ "cc", ] -[[package]] -name = "secret-service" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4d35ad99a181be0a60ffcbe85d680d98f87bdc4d7644ade319b87076b9dbfd4" -dependencies = [ - "aes 0.8.4", - "cbc", - "futures-util", - "generic-array", - "hkdf", - "num", - "once_cell", - "rand 0.8.6", - "serde", - "sha2 0.10.9", - "zbus 4.4.0", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.13.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -9088,7 +9040,7 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cssparser", "derive_more", "log", @@ -9131,9 +9083,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -9163,22 +9115,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -9189,14 +9141,25 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "serde_derive_internals" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", ] [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -9218,13 +9181,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -9270,7 +9233,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.14.0", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.2.2", "serde_core", "serde_json", "serde_with_macros", @@ -9286,7 +9249,7 @@ dependencies = [ "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -9342,7 +9305,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -9356,9 +9319,9 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.2.17", @@ -9391,7 +9354,6 @@ dependencies = [ "cfg-if 1.0.4", "cpufeatures 0.2.17", "digest 0.10.7", - "sha2-asm", ] [[package]] @@ -9405,15 +9367,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "sha2-asm" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" -dependencies = [ - "cc", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -9527,15 +9480,15 @@ checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -9553,7 +9506,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a75cbde1bf934313596a004973e462f9a82caa814dcf1a5f507bdf51597eeb4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -9565,7 +9518,7 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "skippy-cache" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "blake3", @@ -9575,15 +9528,15 @@ dependencies = [ [[package]] name = "skippy-coordinator" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] name = "skippy-ffi" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "libloading 0.8.9", ] @@ -9591,12 +9544,12 @@ dependencies = [ [[package]] name = "skippy-metrics" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" [[package]] name = "skippy-protocol" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "prost 0.14.4", "prost-build 0.14.4", @@ -9607,7 +9560,7 @@ dependencies = [ [[package]] name = "skippy-runtime" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "anyhow", "libc", @@ -9621,7 +9574,7 @@ dependencies = [ [[package]] name = "skippy-server" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "ahash", "anyhow", @@ -9650,7 +9603,7 @@ dependencies = [ [[package]] name = "skippy-topology" version = "0.74.0" -source = "git+https://github.com/Mesh-LLM/mesh-llm.git?tag=v0.74.0#e60b2fe43aa05271569fbeff2a457133aef456a1" +source = "git+https://github.com/darrenoakey/mesh-llm.git?rev=9a8590d2791f7f5f91d4779b4259ff0491ecbfe6#9a8590d2791f7f5f91d4779b4259ff0491ecbfe6" dependencies = [ "serde", "serde_json", @@ -9681,9 +9634,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -9751,23 +9704,23 @@ checksum = "c87e960f4dca2788eeb86bbdde8dd246be8948790b7618d656e68f9b720a86e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "spin" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" dependencies = [ "lock_api", ] [[package]] name = "spin" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" [[package]] name = "spki" @@ -9793,9 +9746,9 @@ dependencies = [ [[package]] name = "sse-stream" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f24a9b78c40b90817bbcd1821c74ddfd74916aadd29403d001532a9195532d" +checksum = "c123f296ade4ec4b8b0f6162116e6629f5146922ca5ab40ca9d3c2e73ab4761e" dependencies = [ "bytes", "futures-util", @@ -9889,7 +9842,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -10086,9 +10039,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -10112,7 +10076,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -10149,7 +10113,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -10198,7 +10162,7 @@ version = "0.35.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2", "core-foundation 0.10.1", "core-graphics", @@ -10234,13 +10198,13 @@ dependencies = [ [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -10301,7 +10265,7 @@ dependencies = [ "tauri-runtime", "tauri-runtime-wry", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tray-icon", "url", @@ -10350,9 +10314,9 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "syn 2.0.118", + "syn 2.0.119", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "url", "uuid", @@ -10368,7 +10332,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "tauri-codegen", "tauri-utils", ] @@ -10403,7 +10367,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "tracing", "url", "windows-registry 0.5.3", @@ -10412,9 +10376,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65981abb771e74e571a38196c3baa11c459379164791eba0e67abc1a5fac9884" +checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940" dependencies = [ "log", "raw-window-handle", @@ -10424,7 +10388,7 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-plugin-fs", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", ] @@ -10447,8 +10411,8 @@ dependencies = [ "tauri", "tauri-plugin", "tauri-utils", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.19", + "toml 1.1.4+spec-1.1.0", "url", ] @@ -10464,7 +10428,7 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -10475,13 +10439,13 @@ checksum = "01fc2c5ff41105bd1f7242d8201fdf3efd70749b82fa013a17f2126357d194cc" dependencies = [ "log", "notify-rust", - "rand 0.9.4", + "rand 0.9.5", "serde", "serde_json", "serde_repr", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "url", ] @@ -10502,10 +10466,10 @@ dependencies = [ "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "windows 0.61.3", - "zbus 5.17.0", + "zbus", ] [[package]] @@ -10520,18 +10484,19 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" -version = "2.4.2" +version = "2.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8f29386f5e9fdc699182388a33ee80a56de436d91b67459e86afef426282af" +checksum = "b3214becf9ef5783c0ae99a3bb25adf5353a7a16ebf53e74b909e29205735c6c" dependencies = [ "serde", "serde_json", "tauri", "tauri-plugin-deep-link", - "thiserror 2.0.18", + "thiserror 2.0.19", + "tokio", "tracing", "windows-sys 0.60.2", - "zbus 5.17.0", + "zbus", ] [[package]] @@ -10559,7 +10524,7 @@ dependencies = [ "tauri", "tauri-plugin", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "tokio", "url", @@ -10573,13 +10538,13 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73736611e14142408d15353e21e3cca2f12a3cfb523ad0ce85999b6d2ef1a704" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "log", "serde", "serde_json", "tauri", "tauri-plugin", - "thiserror 2.0.18", + "thiserror 2.0.19", ] [[package]] @@ -10600,7 +10565,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "webkit2gtk", "webview2-com", @@ -10663,8 +10628,8 @@ dependencies = [ "serde_json", "serde_with", "swift-rs", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.19", + "toml 1.1.4+spec-1.1.0", "url", "urlpattern", "uuid", @@ -10679,7 +10644,7 @@ checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ "dunce", "embed-resource", - "toml 1.1.2+spec-1.1.0", + "toml 1.1.4+spec-1.1.0", ] [[package]] @@ -10688,7 +10653,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed071c670382e85fc2f48ae706492d8c338f4f89bf72520d32f8abfe880aade" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", "windows 0.61.3", "windows-version", ] @@ -10721,7 +10686,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "parking_lot", "rustix 1.1.4", "signal-hook 0.3.18", @@ -10757,7 +10722,7 @@ checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", "base64 0.22.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "fancy-regex 0.11.0", "filedescriptor", "finl_unicode", @@ -10802,11 +10767,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.19", ] [[package]] @@ -10817,25 +10782,25 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if 1.0.4", ] @@ -10856,9 +10821,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.53" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "js-sys", @@ -10879,9 +10844,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -10908,9 +10873,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" dependencies = [ "tinyvec_macros", ] @@ -10940,7 +10905,7 @@ dependencies = [ "macro_rules_attribute", "monostate", "paste", - "rand 0.9.4", + "rand 0.9.5", "rayon", "rayon-cond", "regex", @@ -10948,7 +10913,7 @@ dependencies = [ "serde", "serde_json", "spm_precompiled", - "thiserror 2.0.18", + "thiserror 2.0.19", "unicode-normalization-alignments", "unicode-segmentation", "unicode_categories", @@ -10956,9 +10921,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.52.3" +version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ "bytes", "libc", @@ -10973,13 +10938,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -11027,9 +10992,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" dependencies = [ "futures-core", "pin-project-lite", @@ -11071,14 +11036,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" dependencies = [ "bytes", "futures-core", "futures-sink", "futures-util", + "libc", "pin-project-lite", "tokio", ] @@ -11127,7 +11093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d01145a2c788d6aae4cd653afec1e8332534d7d783d01897cefcafe4428de992" dependencies = [ "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -11159,9 +11125,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap 2.14.0", "serde_core", @@ -11169,7 +11135,7 @@ dependencies = [ "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -11225,31 +11191,31 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap 2.14.0", "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tonic" @@ -11316,7 +11282,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bytes", "futures-util", "http", @@ -11360,7 +11326,7 @@ checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" dependencies = [ "crossbeam-channel", "symlink", - "thiserror 2.0.18", + "thiserror 2.0.19", "time", "tracing-subscriber", ] @@ -11373,7 +11339,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -11440,9 +11406,9 @@ dependencies = [ [[package]] name = "tray-icon" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ba1e5f6b9ef9fd87e21b9c6f351554dbd717960089168fcfdef854686961dc" +checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" dependencies = [ "crossbeam-channel", "dirs", @@ -11456,7 +11422,7 @@ dependencies = [ "once_cell", "png 0.18.1", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows-sys 0.61.2", ] @@ -11488,11 +11454,11 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.4", + "rand 0.9.5", "rustls", "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.18", + "sha1 0.10.7", + "thiserror 2.0.19", "utf-8", ] @@ -11507,18 +11473,18 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.4", + "rand 0.9.5", "rustls", "rustls-pki-types", - "sha1 0.10.6", - "thiserror 2.0.18", + "sha1 0.10.7", + "thiserror 2.0.19", ] [[package]] name = "twox-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +checksum = "8464ec13c3691491391d9fce00f6416c9a48e46972f72d7865688be2080192c9" [[package]] name = "typed-path" @@ -11567,7 +11533,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" dependencies = [ - "rand 0.9.4", + "rand 0.9.5", "web-time", ] @@ -11791,9 +11757,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.4" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" dependencies = [ "atomic", "getrandom 0.4.3", @@ -11815,43 +11781,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vergen" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "vergen-lib", -] - -[[package]] -name = "vergen-gitcl" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff3b5300a085d6bcd8fc96a507f706a28ae3814693236c9b409db71a1d15b9" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "time", - "vergen", - "vergen-lib", -] - -[[package]] -name = "vergen-lib" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", -] - [[package]] name = "version-compare" version = "0.2.1" @@ -11872,7 +11801,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -11911,7 +11840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd" dependencies = [ "arrayvec", - "bitflags 2.13.0", + "bitflags 2.13.1", "cursor-icon", "log", "memchr", @@ -12020,7 +11949,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "wasm-bindgen-shared", ] @@ -12078,7 +12007,7 @@ version = "0.31.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -12090,7 +12019,7 @@ version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -12102,7 +12031,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -12163,15 +12092,15 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.2.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" +checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" dependencies = [ - "core-foundation 0.10.1", "jni 0.22.4", "log", "ndk-context", "objc2", + "objc2-app-kit", "objc2-foundation", "url", "web-sys", @@ -12223,9 +12152,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" dependencies = [ "rustls-pki-types", ] @@ -12236,14 +12165,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.8", + "webpki-roots 1.0.9", ] [[package]] name = "webpki-roots" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -12270,7 +12199,7 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -12279,7 +12208,7 @@ version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.19", "windows 0.61.3", "windows-core 0.61.2", ] @@ -12535,7 +12464,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -12546,7 +12475,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -12581,6 +12510,16 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-permissions" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2ccdc3c6bf4d4a094e031b63fadd08d8e42abd259940eb8aa5fdc09d4bf9be" +dependencies = [ + "bitflags 1.3.2", + "winapi", +] + [[package]] name = "windows-registry" version = "0.5.3" @@ -12980,9 +12919,9 @@ checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -13022,7 +12961,7 @@ dependencies = [ "log", "os_pipe", "rustix 1.1.4", - "thiserror 2.0.18", + "thiserror 2.0.19", "tree_magic_mini", "wayland-backend", "wayland-client", @@ -13040,7 +12979,7 @@ dependencies = [ "futures", "log", "serde", - "thiserror 2.0.18", + "thiserror 2.0.19", "windows 0.62.2", "windows-core 0.62.2", ] @@ -13084,7 +13023,7 @@ dependencies = [ "sha2 0.10.9", "soup3", "tao-macros", - "thiserror 2.0.18", + "thiserror 2.0.19", "url", "webkit2gtk", "webkit2gtk-sys", @@ -13108,7 +13047,7 @@ dependencies = [ "pharos", "rustc_version", "send_wrapper", - "thiserror 2.0.18", + "thiserror 2.0.19", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -13162,21 +13101,11 @@ dependencies = [ "rustix 1.1.4", ] -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "xet-client" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45fc10a88b05d4824d7fc0f97d04c13eaea98da5e8032194b8a0cbdab942090" +checksum = "c3b8da8cc70aa2e3c500c0400e012df82c656ab9fca47f9f939fffc5afd89aca" dependencies = [ "anyhow", "async-trait", @@ -13186,7 +13115,6 @@ dependencies = [ "futures", "http", "hyper", - "lazy_static", "more-asserts", "rand 0.10.2", "redb", @@ -13197,7 +13125,7 @@ dependencies = [ "serde_repr", "statrs", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-retry", "tokio_with_wasm", @@ -13211,9 +13139,9 @@ dependencies = [ [[package]] name = "xet-core-structures" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb39bc5e0478e8f03e15f08b0a396f197fcfa2ef5027da666fd100c806bf0ea3" +checksum = "73503c223783dccc864abde22115e09d12f190448a0baf58ab2c54bc709e2f99" dependencies = [ "async-trait", "base64 0.22.1", @@ -13226,7 +13154,6 @@ dependencies = [ "getrandom 0.4.3", "heapify", "itertools", - "lazy_static", "lz4_flex", "more-asserts", "rand 0.10.2", @@ -13234,7 +13161,7 @@ dependencies = [ "safe-transmute", "serde", "static_assertions", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tracing", @@ -13245,9 +13172,9 @@ dependencies = [ [[package]] name = "xet-data" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e428a3b9667c1d0d335a4c77407c04d3a3e6c4f228aee364a1b56ed94cf861ca" +checksum = "c89052ec5dec2187cad30b86af92cc24fd61c4a57a795f1ff7ff5f38d49184eb" dependencies = [ "anyhow", "async-trait", @@ -13256,14 +13183,13 @@ dependencies = [ "gearhash", "http", "itertools", - "lazy_static", "more-asserts", "rand 0.10.2", "serde", "serde_json", - "sha2 0.10.9", + "sha2 0.11.0", "tempfile", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tokio_with_wasm", @@ -13278,9 +13204,9 @@ dependencies = [ [[package]] name = "xet-runtime" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e1f8cfa256029d1bba7860ca12bfd145f17aa7aede5d968e9c304047656be1" +checksum = "af5c60d5eed38ab4c576f4421bae835e7bd07631fb381705605529d2015c106b" dependencies = [ "anyhow", "async-trait", @@ -13288,13 +13214,12 @@ dependencies = [ "chrono", "colored", "const-str", - "ctor 1.0.8", + "ctor 1.0.12", "dirs", "futures", "git-version", "humantime", "konst", - "lazy_static", "libc", "more-asserts", "oneshot", @@ -13305,7 +13230,7 @@ dependencies = [ "serde_json", "shellexpand", "sysinfo 0.38.4", - "thiserror 2.0.18", + "thiserror 2.0.19", "tokio", "tokio-util", "tokio_with_wasm", @@ -13357,47 +13282,15 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "synstructure", ] [[package]] name = "zbus" -version = "4.4.0" +version = "5.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" -dependencies = [ - "async-broadcast", - "async-process", - "async-recursion", - "async-trait", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix 0.29.0", - "ordered-stream", - "rand 0.8.6", - "serde", - "serde_repr", - "sha1 0.10.6", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros 4.4.0", - "zbus_names 3.0.0", - "zvariant 4.2.0", -] - -[[package]] -name = "zbus" -version = "5.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28b97f866896a4be7aefd2b5a8e01bb6773d19a775d54ab28b4d094b9a4480e" +checksum = "fe18fb60dc696039e738717b76eaea21e7a4489bbb1885020b43c94236d7e98a" dependencies = [ "async-broadcast", "async-executor", @@ -13422,80 +13315,56 @@ dependencies = [ "uds_windows", "uuid", "windows-sys 0.61.2", - "winnow 1.0.3", - "zbus_macros 5.17.0", - "zbus_names 4.3.3", - "zvariant 5.13.0", + "winnow 1.0.4", + "zbus_macros", + "zbus_names", + "zvariant", ] [[package]] name = "zbus_macros" -version = "4.4.0" +version = "5.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119" dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.118", - "zvariant_utils 2.1.0", -] - -[[package]] -name = "zbus_macros" -version = "5.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e05ad887425eecf5e8384dc2406a4a9313eb73468712fc1cdea362eb4fe0469" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", - "zbus_names 4.3.3", - "zvariant 5.13.0", - "zvariant_utils 3.5.0", + "syn 2.0.119", + "zbus_names", + "zvariant", + "zvariant_utils", ] [[package]] name = "zbus_names" -version = "3.0.0" +version = "4.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" dependencies = [ "serde", - "static_assertions", - "zvariant 4.2.0", -] - -[[package]] -name = "zbus_names" -version = "4.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039ca249fee9559680f3a9f05b55e0761fee51af4f6c1e7d8c1f31e549721d2" -dependencies = [ - "serde", - "winnow 1.0.3", - "zvariant 5.13.0", + "winnow 1.0.4", + "zvariant", ] [[package]] name = "zerocopy" -version = "0.8.54" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" +checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.54" +version = "0.8.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" +checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -13515,7 +13384,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "synstructure", ] @@ -13536,7 +13405,7 @@ checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -13569,7 +13438,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -13585,7 +13454,7 @@ dependencies = [ "flate2", "indexmap 2.14.0", "memchr", - "thiserror 2.0.18", + "thiserror 2.0.19", "zopfli", ] @@ -13607,7 +13476,7 @@ version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" dependencies = [ - "aes 0.9.1", + "aes 0.9.2", "bzip2 0.6.1", "constant_time_eq", "crc32fast", @@ -13630,15 +13499,15 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b142a20ec14a91d5bc708c1dc21b080c550113d8aa77afa29635673a65dd02c5" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zopfli" @@ -13697,66 +13566,29 @@ dependencies = [ [[package]] name = "zvariant" -version = "4.2.0" +version = "5.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +checksum = "bee2a0bcd2a907786a456fff45aaaaf54c9ba5f50b71ae9ec1a4edd200c94911" dependencies = [ "endi", "enumflags2", "serde", - "static_assertions", - "zvariant_derive 4.2.0", -] - -[[package]] -name = "zvariant" -version = "5.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cf057bb00bf5c9ad77abb6147b0ca4818236a1858416e9d988e40d6322fefa7" -dependencies = [ - "endi", - "enumflags2", - "serde", - "winnow 1.0.3", - "zvariant_derive 5.13.0", - "zvariant_utils 3.5.0", -] - -[[package]] -name = "zvariant_derive" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" -dependencies = [ - "proc-macro-crate 3.5.0", - "proc-macro2", - "quote", - "syn 2.0.118", - "zvariant_utils 2.1.0", + "winnow 1.0.4", + "zvariant_derive", + "zvariant_utils", ] [[package]] name = "zvariant_derive" -version = "5.13.0" +version = "5.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8118ca6bda77bfc0ab51d660db0c955f2505eef854c9a449435bccb616933b31" +checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12" dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.118", - "zvariant_utils 3.5.0", -] - -[[package]] -name = "zvariant_utils" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", + "syn 2.0.119", + "zvariant_utils", ] [[package]] @@ -13768,6 +13600,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.118", - "winnow 1.0.3", + "syn 2.0.119", + "winnow 1.0.4", ] diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index bbf245e29a..a979d78c81 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -24,9 +24,10 @@ crate-type = ["staticlib", "cdylib", "rlib"] [features] default = ["system-keyring"] mesh-llm = ["dep:iroh", "dep:mesh-llm-sdk", "dep:mesh-llm-host-runtime", "dep:mesh-llm-client", "dep:mesh-llm-node", "dep:mesh-llm-system", "dep:mesh-llm-events"] -# OS keyring backing for desktop secret storage (nsec private keys). When -# disabled, secrets fall back to 0o600 files. On by default for real builds. -system-keyring = ["dep:keyring"] +# Process-isolated secret-provider backing for desktop nsec private keys. The +# historical feature name is retained for downstream build compatibility; it +# no longer links or calls an operating-system keyring. +system-keyring = ["dep:daz-secrets"] [build-dependencies] base64 = "0.22" @@ -39,7 +40,6 @@ libc = "0.2" ctrlc = { version = "3", features = ["termination"] } [target.'cfg(target_os = "linux")'.dependencies] -keyring = { version = "3.6.3", default-features = false, features = ["sync-secret-service", "vendored"], optional = true } # Used directly (alongside tauri-plugin-notification) so we can hold the posting # D-Bus connection open. GNOME 46+ dismisses a notification the moment that # connection is dropped, which the plugin does immediately. Default features @@ -56,20 +56,18 @@ objc2 = { version = "0.6.4", default-features = false } objc2-app-kit = { version = "0.3.2", default-features = false, features = ["NSEvent", "NSHapticFeedback", "NSMenu", "NSMenuItem", "NSStatusItem", "block2"] } objc2-foundation = { version = "0.3.2", default-features = false, features = ["NSDictionary", "NSError", "NSBundle", "NSObject", "NSProcessInfo", "NSString"] } objc2-user-notifications = { version = "0.3.2", default-features = false, features = ["block2", "UNNotification", "UNNotificationContent", "UNNotificationRequest", "UNNotificationResponse", "UNNotificationSettings", "UNNotificationTrigger", "UNUserNotificationCenter"] } -keyring = { version = "3.6.3", default-features = false, features = ["apple-native", "vendored"], optional = true } -security-framework = { version = "3.7.0", features = ["OSX_10_15"] } window-vibrancy = "0.6" user-idle = { version = "0.6", default-features = false } plist = "1" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.61", features = ["Win32_Security", "Win32_Storage_FileSystem", "Win32_System_JobObjects", "Win32_System_Registry", "Win32_System_Threading", "Win32_Foundation"] } -keyring = { version = "3.6.3", default-features = false, features = ["windows-native", "vendored"], optional = true } user-idle = { version = "0.6", default-features = false } [dependencies] atomic-write-file = "0.3" anyhow = "1" +daz-secrets = { git = "https://github.com/darrenoakey/daz-secrets", rev = "ef01d96a2fa8d661a6a2ad7dace77fce0f2f60aa", optional = true } dirs = "6" tauri = { version = "2", features = ["macos-private-api", "tray-icon"] } tauri-plugin-deep-link = "2" @@ -109,14 +107,14 @@ buzz_voice_pkg = { package = "buzz-voice", path = "../../crates/buzz-voice" } buzz_terminal = { package = "buzz-terminal", path = "crates/buzz-terminal" } portable-pty = "0.9" iroh = { version = "1.0.2", optional = true } -mesh-llm-sdk = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true } -mesh-llm-host-runtime = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true } +mesh-llm-sdk = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-sdk", default-features = false, features = ["client", "serving"], optional = true } +mesh-llm-host-runtime = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-host-runtime", default-features = false, features = ["dynamic-native-runtime"], optional = true } # Model catalog + hardware survey for the Share-compute model picker (same # diagnose pattern as mesh-console). Lib name of mesh-llm-client is mesh_client. -mesh-llm-client = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-client", optional = true } -mesh-llm-node = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-node", optional = true } -mesh-llm-system = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-system", optional = true } -mesh-llm-events = { git = "https://github.com/Mesh-LLM/mesh-llm.git", tag = "v0.74.0", package = "mesh-llm-events", optional = true } +mesh-llm-client = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-client", optional = true } +mesh-llm-node = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-node", optional = true } +mesh-llm-system = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-system", optional = true } +mesh-llm-events = { git = "https://github.com/darrenoakey/mesh-llm.git", rev = "9a8590d2791f7f5f91d4779b4259ff0491ecbfe6", package = "mesh-llm-events", optional = true } base64 = "0.22" sha2 = "0.11" tar = "0.4" diff --git a/desktop/src-tauri/src/app_state.rs b/desktop/src-tauri/src/app_state.rs index fc90e6ab14..4e8b3e6dea 100644 --- a/desktop/src-tauri/src/app_state.rs +++ b/desktop/src-tauri/src/app_state.rs @@ -135,28 +135,6 @@ pub struct AppState { pub pending_owned_channels: Mutex>, } -/// Parse the `BUZZ_PRIVATE_KEY` env var into identity keys. `Some` means the -/// env var was present and valid and MUST win over any persisted/keyring key -/// (the dev/CI/harness override). `None` means absent or malformed — callers -/// fall through to persisted resolution. A malformed value is logged and -/// treated as absent rather than left on an ephemeral identity. -fn identity_from_env() -> Option { - match std::env::var("BUZZ_PRIVATE_KEY") { - Ok(nsec) => match Keys::parse(nsec.trim()) { - Ok(keys) => Some(keys), - Err(error) => { - eprintln!("buzz-desktop: invalid BUZZ_PRIVATE_KEY: {error}"); - None - } - }, - Err(std::env::VarError::NotUnicode(_)) => { - eprintln!("buzz-desktop: BUZZ_PRIVATE_KEY contains invalid UTF-8"); - None - } - Err(std::env::VarError::NotPresent) => None, - } -} - /// Build the no-redirect HTTP client used for authenticated relay media /// fetches (download / copy). /// @@ -179,22 +157,11 @@ pub fn build_media_fetch_client() -> reqwest::Result { } pub fn build_app_state() -> AppState { - // Env var takes precedence (dev/CI). If absent, resolve_persisted_identity() - // in setup() will replace the ephemeral placeholder with a persisted key. - let (keys, identity_storage) = match identity_from_env() { - Some(keys) => { - eprintln!( - "buzz-desktop: configured identity pubkey {}", - keys.public_key().to_hex() - ); - (keys, IdentityStorage::Environment) - } - None => (Keys::generate(), IdentityStorage::Ephemeral), - }; - AppState { - keys: Mutex::new(keys), - identity_storage: AtomicU8::new(identity_storage as u8), + // setup() replaces this non-persisted placeholder from the provider + // before identity-dependent work is enabled. + keys: Mutex::new(Keys::generate()), + identity_storage: AtomicU8::new(IdentityStorage::Ephemeral as u8), http_client: reqwest::Client::builder() .resolve("localhost", std::net::SocketAddr::from(([127, 0, 0, 1], 0))) .pool_idle_timeout(std::time::Duration::from_secs(10)) @@ -343,8 +310,8 @@ impl AppState { /// Resolve the user's identity key from the app data directory and wire /// the resulting [`RecoveryState`] into `AppState`. /// -/// Priority: `BUZZ_PRIVATE_KEY` env var (already handled in `build_app_state`) -/// → keyring → `{app_data_dir}/identity.key` file → generate + save. +/// Priority: configured secret provider, with a one-time migration from the +/// legacy `{app_data_dir}/identity.key` file when present. /// /// On success, writes the resolved keys into `state.keys` (with the mutex) /// before storing the recovery flags (Release), so any thread that reads @@ -356,13 +323,6 @@ impl AppState { /// but inaccessible this boot). Both states boot with an ephemeral key; the /// frontend shows different recovery screens for each. pub fn resolve_persisted_identity(app: &AppHandle, state: &AppState) -> Result<(), String> { - // Only skip file-based resolution if the env var was present AND parsed - // successfully. A malformed env var should fall through to the persisted - // key rather than leaving the app on an ephemeral identity. - if identity_from_env().is_some() { - return Ok(()); - } - let data_dir = app .path() .app_data_dir() @@ -447,14 +407,9 @@ impl IdentityKeyStore for crate::secret_store::SecretStore { fn load_or_create_identity(data_dir: &std::path::Path) -> Result { let legacy_path = data_dir.join("identity.key"); - // No keyring available in this build: the `0o600` file is the only store. + // Secrets must never fall back to a file in provider-disabled builds. if !cfg!(feature = "system-keyring") { - let keys = load_file_or_generate(&legacy_path, data_dir)?; - return Ok(ResolvedIdentity { - keys, - recovery: RecoveryState::None, - storage: IdentityStorage::LocalFile, - }); + return Err("secret-provider support is disabled".to_string()); } let store = crate::secret_store::SecretStore::shared(keyring_service()); @@ -496,31 +451,16 @@ fn resolve_identity_with_store( adopting imported key {}", file_keys.public_key().to_hex() ); - // Delegate the store→read-back-verify→marker→delete - // sequence to `persist_identity_to_keyring`, which owns - // the marker-before-delete invariant and the fallback - // logic that keeps identity.key when the marker write - // fails. A transient keyring failure must not abort - // boot — the file key is safe and adoption retries next - // boot when the keyring is reachable again. - let storage = if let Err(e) = persist_identity_to_keyring( + persist_identity_to_keyring( store, &file_keys, legacy_path, data_dir, - ) { - eprintln!( - "buzz-desktop: keyring adoption of identity.key \ - failed ({e}); using file key, will retry next boot" - ); - IdentityStorage::LocalFile - } else { - IdentityStorage::SystemKeyring - }; + )?; return Ok(ResolvedIdentity { keys: file_keys, recovery: RecoveryState::None, - storage, + storage: IdentityStorage::SystemKeyring, }); } // Corrupt file — keyring is authoritative. Log before @@ -614,41 +554,7 @@ fn resolve_identity_with_store( }); } } - KeyringProbe::Unreachable => { - // Keyring down this boot. If a recoverable file is present, use it - // (and do NOT migrate — re-importing later could resurrect a - // rotated key). With NO file, the marker disambiguates two states - // that are otherwise byte-identical (Unreachable + no file): - // - marker present → the key was migrated into the keyring and the - // file deleted. The real key is unreachable this boot but still - // exists in the keyring. Boot keyring-locked recovery (ephemeral - // key, all signing disabled) so the app can at least open; the - // frontend shows a "unlock the keyring and relaunch" screen. - // Fail-closed semantics are preserved: nothing is ever persisted - // under the ephemeral key, so no silent identity rotation occurs. - // - no marker → genuine first-ever launch with nothing to protect. - // Generate to the `0o600` file (legitimate first-run). - if !legacy_path.exists() && migration_marker_path(data_dir).exists() { - let ephemeral = Keys::generate(); - eprintln!( - "buzz-desktop: keyring unreachable but migration marker present; \ - booting keyring-locked recovery with ephemeral key {} — \ - unlock the keyring and relaunch", - ephemeral.public_key().to_hex() - ); - return Ok(ResolvedIdentity { - keys: ephemeral, - recovery: RecoveryState::KeyringLocked, - storage: IdentityStorage::Ephemeral, - }); - } - let keys = load_file_or_generate(legacy_path, data_dir)?; - return Ok(ResolvedIdentity { - keys, - recovery: RecoveryState::None, - storage: IdentityStorage::LocalFile, - }); - } + KeyringProbe::Unreachable => return Err("secret provider unavailable".to_string()), } let (keys, storage) = generate_and_persist(store, legacy_path, data_dir)?; @@ -711,33 +617,6 @@ fn recover_from_keyring( }) } -/// Load the `0o600` identity file, quarantining corruption, else generate and -/// save a fresh key to the file. Used when no keyring is available. -fn load_file_or_generate( - legacy_path: &std::path::Path, - data_dir: &std::path::Path, -) -> Result { - if legacy_path.exists() { - match load_key_file(legacy_path) { - Ok(keys) => { - eprintln!( - "buzz-desktop: persisted identity pubkey {}", - keys.public_key().to_hex() - ); - return Ok(keys); - } - Err(error) => quarantine_corrupt_key(legacy_path, data_dir, &error), - } - } - let keys = Keys::generate(); - save_key_file(legacy_path, &keys)?; - eprintln!( - "buzz-desktop: generated and saved identity pubkey {}", - keys.public_key().to_hex() - ); - Ok(keys) -} - /// Import the plaintext `identity.key` into the store, verify the round-trip, /// then delete the file. Returns `Ok(None)` if the file was corrupt (caller /// continues to generate-and-save). @@ -769,25 +648,13 @@ fn migrate_identity_file( if !verify_ok { return Err("keyring read-back verify failed for identity key".to_string()); } - // Crash-safe ordering: record that the key now lives in the keyring - // (marker write + fsync) BEFORE deleting the file. A crash between - // the two must never leave "file gone, no marker" — that state is - // indistinguishable from a fresh install and would silently rotate - // the identity on the next keyring-unreachable boot. If the marker - // cannot be written, keep the file so the key is never stranded. + // The provider read-back is the authoritative durability proof. The + // marker is nonsecret recovery metadata; write it before deleting the + // legacy file, and fail the migration if either operation fails. let marker_path = migration_marker_path(data_dir); - if let Err(e) = write_migration_marker(&marker_path) { - eprintln!( - "buzz-desktop: keyring import ok but failed to write migration marker ({e}); \ - keeping identity.key so the key is not stranded" - ); - return Ok(Some(keys)); - } - if let Err(e) = std::fs::remove_file(legacy_path) { - eprintln!("buzz-desktop: keyring import ok but failed to delete identity.key: {e}"); - } else { - eprintln!("buzz-desktop: migrated identity key into OS keyring"); - } + write_migration_marker(&marker_path)?; + std::fs::remove_file(legacy_path).map_err(|e| format!("remove migrated identity.key: {e}"))?; + eprintln!("buzz-desktop: migrated identity key into secret provider"); Ok(Some(keys)) } @@ -810,7 +677,7 @@ fn persist_identity_to_keyring( .to_bech32() .map_err(|e| format!("encode nsec: {e}"))?; - // Will error if the keyring is unavailable — caller falls back to the file. + // Provider failures propagate. Secret files are never a fallback. store.store(IDENTITY_KEY_NAME, &nsec)?; // Read-back verify before touching durable state. Uses verify_stored() @@ -824,37 +691,7 @@ fn persist_identity_to_keyring( // Write marker before deleting the file (crash-safe ordering). let marker_path = migration_marker_path(data_dir); - if let Err(e) = write_migration_marker(&marker_path) { - // Keyring holds the key but no marker exists. Preserve the invariant - // "keyring-only implies marker exists" by ensuring identity.key is - // present as a fallback: write it if absent, leave it if already there. - // This prevents a later keyring-unreachable + no-marker boot from - // treating this as a fresh install and silently rotating identity. - if !legacy_path.exists() { - if let Err(write_err) = save_key_file(legacy_path, keys) { - eprintln!( - "buzz-desktop: keyring ok but marker write failed ({e}) and \ - identity.key write also failed ({write_err}); key may be unrecoverable" - ); - return Err(format!( - "keyring ok but neither migration marker nor identity.key fallback \ - could be written (marker: {e}; file: {write_err}); \ - identity must not be treated as durably persisted — retry the import" - )); - } else { - eprintln!( - "buzz-desktop: keyring ok but marker write failed ({e}); \ - wrote identity.key as fallback so the key is not stranded" - ); - } - } else { - eprintln!( - "buzz-desktop: keyring ok but marker write failed ({e}); \ - keeping existing identity.key so the key is not stranded" - ); - } - return Ok(()); - } + write_migration_marker(&marker_path)?; if legacy_path.exists() { if let Err(e) = std::fs::remove_file(legacy_path) { @@ -865,27 +702,15 @@ fn persist_identity_to_keyring( Ok(()) } -/// Core implementation of imported-identity persistence. Tries the OS keyring -/// first via [`persist_identity_to_keyring`]; if the keyring is unavailable, -/// falls back to the `0o600` identity.key file. Returns `Err` only when both -/// the keyring write and the file fallback fail. +/// Core implementation of provider-only imported-identity persistence. fn persist_imported_identity_impl( store: &impl IdentityKeyStore, keys: &Keys, legacy_path: &std::path::Path, data_dir: &std::path::Path, ) -> Result { - match persist_identity_to_keyring(store, keys, legacy_path, data_dir) { - Ok(()) => Ok(IdentityStorage::SystemKeyring), - Err(e) => { - eprintln!( - "buzz-desktop: keyring write failed during import ({e}), \ - falling back to identity.key" - ); - save_key_file(legacy_path, keys)?; - Ok(IdentityStorage::LocalFile) - } - } + persist_identity_to_keyring(store, keys, legacy_path, data_dir)?; + Ok(IdentityStorage::SystemKeyring) } /// Public entry point binding [`persist_imported_identity_impl`] to the shared @@ -937,16 +762,7 @@ fn generate_and_persist( ) -> Result<(Keys, IdentityStorage), String> { let keys = Keys::generate(); let storage = store_key_preferring_keyring(store, &keys, legacy_path)?; - if storage == IdentityStorage::SystemKeyring { - let marker_path = migration_marker_path(data_dir); - if let Err(e) = write_migration_marker(&marker_path) { - eprintln!( - "buzz-desktop: stored identity in keyring but failed to write migration marker \ - ({e}); saving identity.key fallback so the key is not stranded" - ); - save_key_file(legacy_path, &keys)?; - } - } + write_migration_marker(&migration_marker_path(data_dir))?; eprintln!( "buzz-desktop: generated and saved identity pubkey {}", keys.public_key().to_hex() @@ -954,11 +770,7 @@ fn generate_and_persist( Ok((keys, storage)) } -/// Persist `keys` through the store, silently falling back to the `0o600` file -/// when the keyring write fails on an availability error. Reports which backend -/// held the key (no verify/marker/delete — those belong to callers that own the -/// full migration contract) so the caller can write the migration marker only on -/// keyring success. +/// Persist `keys` through the configured provider without a file fallback. fn store_key_preferring_keyring( store: &impl IdentityKeyStore, keys: &Keys, @@ -968,14 +780,9 @@ fn store_key_preferring_keyring( .secret_key() .to_bech32() .map_err(|e| format!("encode nsec: {e}"))?; - match store.store(IDENTITY_KEY_NAME, &nsec) { - Ok(()) => Ok(IdentityStorage::SystemKeyring), - Err(keyring_err) => { - eprintln!("buzz-desktop: keyring write failed ({keyring_err}), using file fallback"); - save_key_file(legacy_path, keys)?; - Ok(IdentityStorage::LocalFile) - } - } + let _ = legacy_path; + store.store(IDENTITY_KEY_NAME, &nsec)?; + Ok(IdentityStorage::SystemKeyring) } /// Ensure the migration marker exists (writing it if absent), then remove the @@ -1013,24 +820,6 @@ fn cleanup_leftover_identity_file(legacy_path: &std::path::Path) { } } -/// Quarantine a corrupt `identity.key` with a timestamp so prior backups are -/// never overwritten. -fn quarantine_corrupt_key(key_path: &std::path::Path, data_dir: &std::path::Path, error: &str) { - if !key_path.exists() { - return; - } - let ts = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .map(|d| d.as_secs()) - .unwrap_or(0); - let bad_name = format!("identity.key.bad.{ts}"); - eprintln!("buzz-desktop: corrupt identity.key ({error}), quarantining to {bad_name}"); - let bad_path = data_dir.join(bad_name); - if std::fs::rename(key_path, &bad_path).is_err() { - let _ = std::fs::remove_file(key_path); - } -} - fn load_key_file(path: &std::path::Path) -> Result { let content = std::fs::read_to_string(path).map_err(|e| format!("read identity.key: {e}"))?; let trimmed = content.trim(); @@ -1049,6 +838,7 @@ fn load_key_file(path: &std::path::Path) -> Result { /// On Unix, the file is created with mode 0600 (owner read/write only). /// On Windows, default ACLs apply — the app data directory is already /// per-user, so the key is not world-readable in practice. +#[cfg(test)] pub(crate) fn save_key_file(path: &std::path::Path, keys: &Keys) -> Result<(), String> { use atomic_write_file::AtomicWriteFile; diff --git a/desktop/src-tauri/src/app_state_keyring.rs b/desktop/src-tauri/src/app_state_keyring.rs index 68d24e87f5..70126a8087 100644 --- a/desktop/src-tauri/src/app_state_keyring.rs +++ b/desktop/src-tauri/src/app_state_keyring.rs @@ -1,5 +1,5 @@ -/// Service name for the desktop OS keyring. Debug builds default to a distinct -/// service, while standalone worktree launches may request a scoped dev service. +/// Namespace for the configured secret provider. Debug builds default to a +/// distinct namespace, while standalone worktrees may request a scoped one. fn dev_keyring_service(configured: Option) -> String { configured .filter(|service| service.starts_with("buzz-desktop-dev.")) diff --git a/desktop/src-tauri/src/app_state_tests.rs b/desktop/src-tauri/src/app_state_tests.rs index 751bcf22e5..8a9f470bc6 100644 --- a/desktop/src-tauri/src/app_state_tests.rs +++ b/desktop/src-tauri/src/app_state_tests.rs @@ -4,50 +4,6 @@ fn assert_key_eq(a: &Keys, b: &Keys) { assert_eq!(a.public_key().to_hex(), b.public_key().to_hex()); } -/// `BUZZ_PRIVATE_KEY` is process-global; serialize the env-mutating tests -/// so they don't race each other under the parallel test runner. -static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); - -/// Run `body` with `BUZZ_PRIVATE_KEY` set to `value` (or unset when `None`), -/// restoring the prior value afterward. -fn with_env_key(value: Option<&str>, body: impl FnOnce() -> T) -> T { - let _guard = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner()); - let prior = std::env::var("BUZZ_PRIVATE_KEY").ok(); - match value { - Some(v) => std::env::set_var("BUZZ_PRIVATE_KEY", v), - None => std::env::remove_var("BUZZ_PRIVATE_KEY"), - } - let out = body(); - match prior { - Some(v) => std::env::set_var("BUZZ_PRIVATE_KEY", v), - None => std::env::remove_var("BUZZ_PRIVATE_KEY"), - } - out -} - -#[test] -fn identity_from_env_wins_when_valid() { - let configured = Keys::generate(); - let nsec = configured.secret_key().to_bech32().unwrap(); - - let resolved = - with_env_key(Some(&nsec), identity_from_env).expect("valid env key must resolve"); - - assert_key_eq(&configured, &resolved); -} - -#[test] -fn identity_from_env_none_when_absent() { - assert!(with_env_key(None, identity_from_env).is_none()); -} - -#[test] -fn identity_from_env_none_when_malformed() { - // A malformed env var falls through to persisted resolution rather than - // winning — otherwise a typo'd key would silently shadow the real one. - assert!(with_env_key(Some("not-a-valid-nsec"), identity_from_env).is_none()); -} - #[test] fn save_and_load_round_trip() { let dir = tempfile::tempdir().unwrap(); @@ -403,50 +359,29 @@ fn valid_keyring_is_used_and_matching_leftover_file_cleaned_up() { } #[test] -fn unreachable_post_migration_boots_keyring_locked_recovery() { - // After a migration the file is gone and the marker exists. A later boot - // with the keyring unreachable must NOT generate a fresh key (that would - // silently rotate the identity), but must also allow the app to open - // instead of hard-aborting. The result is a keyring-locked recovery boot: - // ephemeral key held in memory only, nothing persisted anywhere. - // - // Fail-closed semantics are preserved: no identity is ever written to disk - // or the keyring under the ephemeral key, so no silent rotation occurs. - // The abort is replaced by a graceful recovery screen. +fn unreachable_post_migration_fails_closed() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); write_migration_marker(&migration_marker_path(dir.path())).unwrap(); assert!(!legacy_path.exists()); let store = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - // KeyringLocked recovery: ephemeral key returned, nothing persisted. - assert_eq!(resolved.recovery, RecoveryState::KeyringLocked); - // No identity.key was written. + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); assert!(!legacy_path.exists()); - // Keyring store was never called (it is unreachable). assert!(store.slot.borrow().is_empty()); assert!(store.deleted.borrow().is_empty()); } #[test] -fn unreachable_first_run_generates_to_file_when_no_marker() { - // Genuine first-EVER launch on a machine whose keyring is down: no file, - // no marker. There is no prior identity to protect, so generating to the - // `0o600` file is correct — fail-closed here would block a legitimate - // first launch. +fn unreachable_first_run_fails_without_creating_secret_file() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); assert!(!legacy_path.exists()); assert!(!migration_marker_path(dir.path()).exists()); let store = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - // A fresh key was generated and persisted to the file (keyring is down). - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&resolved.keys, &from_file); + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); + assert!(!legacy_path.exists()); } #[test] @@ -497,7 +432,7 @@ fn fresh_keyring_generate_writes_marker() { } #[test] -fn fresh_keyring_generate_then_unreachable_boots_locked_recovery() { +fn fresh_provider_generate_then_unreachable_boot_fails_closed() { // End-to-end guard for Fix 1: after a fresh keyring-created identity // (marker written, no file), a later boot with the keyring unreachable // must NOT generate a new key and rotate identity. Instead it boots @@ -511,40 +446,21 @@ fn fresh_keyring_generate_then_unreachable_boots_locked_recovery() { assert!(!legacy_path.exists()); assert!(migration_marker_path(dir.path()).exists()); - // Second boot: keyring is down. No file + marker present → locked recovery. + // Second boot: provider is down. No secret fallback may be created. let unreachable = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&unreachable, &legacy_path, dir.path()).unwrap(); - - assert_eq!( - resolved.recovery, - RecoveryState::KeyringLocked, - "second boot must boot keyring-locked, not generate a fresh key" - ); - // No identity.key was written — nothing new persisted. + assert!(resolve_identity_with_store(&unreachable, &legacy_path, dir.path()).is_err()); assert!(!legacy_path.exists()); } #[test] -fn fresh_generate_keyring_failure_falls_back_to_file_without_marker() { - // Fix 1 correctness on the file-fallback arm: when the keyring write - // FAILS during a fresh generate, the key must land in the `0o600` file - // and the marker must NOT be written — a marker here would wrongly trip - // the next Unreachable boot into failing closed even though the key is - // sitting in the file. +fn fresh_generate_provider_failure_creates_no_secret_file() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); let store = FakeIdentityStore::store_failing(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - // Key persisted to the file (fallback), and recoverable from it. - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&resolved.keys, &from_file); - // No marker: the file is the authoritative store, not the keyring. - assert!( - !migration_marker_path(dir.path()).exists() - && resolved.storage == IdentityStorage::LocalFile - ); + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); + assert!(!legacy_path.exists()); + assert!(!migration_marker_path(dir.path()).exists()); } // ── New tests for the three defects fixed in this PR ───────────────────── @@ -639,12 +555,7 @@ fn present_keyring_with_mismatched_file_adopts_file_key() { } #[test] -fn present_keyring_mismatched_file_adoption_store_failure_boots_with_file_key() { - // Present + mismatched identity.key + keyring write fails during adoption. - // Boot must succeed with the FILE's key (the user's intent). The file must - // survive on disk because the write was rejected — adoption retries on the - // next boot when the keyring is reachable. The keyring slot must be - // unchanged (shadow nsec still present, not overwritten). +fn present_provider_mismatched_file_adoption_failure_fails_closed() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); @@ -656,17 +567,10 @@ fn present_keyring_mismatched_file_adoption_store_failure_boots_with_file_key() save_key_file(&legacy_path, &file_keys).unwrap(); let store = FakeIdentityStore::present_with_store_failing(&keyring_nsec); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - // File key (user's explicit import) is returned. - assert_key_eq(&file_keys, &resolved.keys); - assert_eq!(resolved.recovery, RecoveryState::None); - - // identity.key must survive — adoption write failed, so it is the only - // durable copy of the imported key until the next-boot retry. + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); assert!( legacy_path.exists(), - "identity.key must be kept when keyring adoption write fails" + "legacy source must remain available for a later verified migration" ); // Keyring slot unchanged — write was rejected, no overwrite occurred. @@ -775,11 +679,7 @@ fn reachable_but_empty_with_marker_and_no_file_returns_lost() { } #[test] -fn persist_imported_identity_falls_back_to_file_on_keyring_failure() { - // `persist_imported_identity_impl` with a failing store returns Ok and - // writes identity.key as a fallback. No migration marker is written — a - // marker here would cause fail-closed on a later Unreachable boot even - // though the key is in the file, not the keyring. +fn persist_imported_identity_provider_failure_creates_no_file_fallback() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); let imported_keys = Keys::generate(); @@ -788,14 +688,8 @@ fn persist_imported_identity_falls_back_to_file_on_keyring_failure() { let result = persist_imported_identity_impl(&store, &imported_keys, &legacy_path, dir.path()); - // The policy core handles the keyring failure — Ok, not Err. - assert_eq!(result.unwrap(), IdentityStorage::LocalFile); - - // Key is recoverable from the file on next boot. - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&imported_keys, &from_file); - - // No marker written — the file is the authoritative store, not the keyring. + assert!(result.is_err()); + assert!(!legacy_path.exists()); assert!(!migration_marker_path(dir.path()).exists()); // The underlying kernel still propagates keyring failure (low-level @@ -809,13 +703,7 @@ fn persist_imported_identity_falls_back_to_file_on_keyring_failure() { } #[test] -fn persist_to_keyring_marker_failure_writes_file_when_absent_preserves_invariant() { - // (f) Marker-write failure after a verified keyring write when no - // identity.key exists (e.g. import from a lost state where the file - // was already deleted). The invariant "keyring-only implies marker - // exists" must be preserved: persist_identity_to_keyring must write - // identity.key as a fallback so a later keyring-unreachable boot does - // NOT treat the machine as a fresh install and silently rotate identity. +fn persist_to_provider_marker_failure_creates_no_secret_file() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); assert!(!legacy_path.exists()); // no file — simulates import from lost state @@ -829,24 +717,9 @@ fn persist_to_keyring_marker_failure_writes_file_when_absent_preserves_invariant let marker_path = migration_marker_path(dir.path()); std::fs::create_dir_all(&marker_path).unwrap(); - // persist_identity_to_keyring will: store to keyring (succeeds), read- - // back verify (succeeds), attempt write_migration_marker (fails because - // marker_path is a directory), then write identity.key as a fallback. let result = persist_identity_to_keyring(&store, &imported_keys, &legacy_path, dir.path()); - - // The function returns Ok — the error is handled, not propagated. - assert!( - result.is_ok(), - "persist_identity_to_keyring must not propagate marker failure" - ); - - // identity.key was written as a fallback — invariant preserved. - assert!( - legacy_path.exists(), - "identity.key must exist as fallback when marker write failed and file was absent" - ); - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&imported_keys, &from_file); + assert!(result.is_err()); + assert!(!legacy_path.exists()); } #[test] @@ -1001,50 +874,31 @@ fn signing_keys_identity_lost_takes_priority_over_keyring_locked() { // ── Keyring-locked recovery mode tests ─────────────────────────────────── #[test] -fn keyring_locked_recovery_ephemeral_never_persisted() { - // Unreachable + marker + no file → KeyringLocked recovery. The ephemeral - // key is held in memory only; no identity.key is created, no keyring - // slot is touched. Fail-closed semantics: no identity is ever rotated. +fn unavailable_provider_returns_error_without_persisting() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); write_migration_marker(&migration_marker_path(dir.path())).unwrap(); assert!(!legacy_path.exists()); let store = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - assert_eq!(resolved.recovery, RecoveryState::KeyringLocked); - // Nothing written to disk — ephemeral key is transient. + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); assert!(!legacy_path.exists()); - // Keyring was never contacted (it is unreachable). assert!(store.slot.borrow().is_empty()); assert!(store.deleted.borrow().is_empty()); } #[test] -fn keyring_locked_recovery_distinct_ephemeral_per_boot() { - // Each locked-state boot produces a distinct ephemeral key and persists - // nothing — mirroring the lost-state guarantee. +fn repeated_unavailable_provider_boots_both_fail_closed() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); write_migration_marker(&migration_marker_path(dir.path())).unwrap(); assert!(!legacy_path.exists()); let store1 = FakeIdentityStore::unreachable(); - let resolved1 = resolve_identity_with_store(&store1, &legacy_path, dir.path()).unwrap(); - assert_eq!(resolved1.recovery, RecoveryState::KeyringLocked); + assert!(resolve_identity_with_store(&store1, &legacy_path, dir.path()).is_err()); let store2 = FakeIdentityStore::unreachable(); - let resolved2 = resolve_identity_with_store(&store2, &legacy_path, dir.path()).unwrap(); - assert_eq!(resolved2.recovery, RecoveryState::KeyringLocked); - - // Two ephemeral keys are different (probabilistic — collision negligible). - assert_ne!( - resolved1.keys.public_key().to_hex(), - resolved2.keys.public_key().to_hex(), - "each locked-state boot produces a distinct ephemeral key" - ); - // Neither boot persisted anything. + assert!(resolve_identity_with_store(&store2, &legacy_path, dir.path()).is_err()); assert!(!legacy_path.exists()); } @@ -1076,9 +930,7 @@ fn persist_identity_to_keyring_readback_corrupt_returns_err() { } #[test] -fn persist_imported_identity_impl_readback_corrupt_falls_back_to_file() { - // B1.2: persist_imported_identity_impl with a readback-corrupt store returns - // Ok and writes identity.key as a fallback, and the file holds the original key. +fn persist_imported_identity_readback_corrupt_fails_without_file() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); @@ -1089,17 +941,8 @@ fn persist_imported_identity_impl_readback_corrupt_falls_back_to_file() { let result = persist_imported_identity_impl(&store, &imported_keys, &legacy_path, dir.path()); - assert!( - result.is_ok(), - "must return Ok when file fallback succeeds after readback corruption: {:?}", - result.err() - ); - assert!( - legacy_path.exists(), - "identity.key must be written as fallback" - ); - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&imported_keys, &from_file); + assert!(result.is_err()); + assert!(!legacy_path.exists()); } // ── B2: corrupt key material recovery ──────────────────────────────────── @@ -1164,20 +1007,14 @@ fn present_corrupt_keyring_and_corrupt_file_generates_fresh() { // ── B3: Unreachable probe branches ─────────────────────────────────────── #[test] -fn unreachable_with_valid_file_resolves_to_file_key() { - // B3.a+b (inputs are indistinguishable at this level): Unreachable + valid - // identity.key → resolves to the file's key. The keyring is never contacted - // and the file is kept on disk (no migration when keyring is down). +fn unreachable_with_valid_legacy_file_fails_closed() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); let file_keys = Keys::generate(); save_key_file(&legacy_path, &file_keys).unwrap(); let store = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - assert_key_eq(&file_keys, &resolved.keys); - assert_eq!(resolved.recovery, RecoveryState::None); + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); assert!( legacy_path.exists(), "identity.key must not be deleted when keyring is unreachable" @@ -1189,11 +1026,7 @@ fn unreachable_with_valid_file_resolves_to_file_key() { } #[test] -fn unreachable_valid_file_with_marker_resolves_to_file_not_locked_recovery() { - // Unreachable + valid identity.key + marker present → resolves to the file - // key, NOT KeyringLocked recovery. The locked-recovery branch only fires - // when the file is ABSENT; a present file is always used as a direct - // fallback regardless of the marker. +fn unreachable_valid_legacy_file_with_marker_still_fails_closed() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); let file_keys = Keys::generate(); @@ -1201,45 +1034,29 @@ fn unreachable_valid_file_with_marker_resolves_to_file_not_locked_recovery() { write_migration_marker(&migration_marker_path(dir.path())).unwrap(); let store = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - assert_key_eq(&file_keys, &resolved.keys); - assert_eq!( - resolved.recovery, - RecoveryState::None, - "must not enter locked-recovery when a valid file is present" - ); + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); + assert!(legacy_path.exists()); } #[test] -fn unreachable_corrupt_file_generates_fresh() { - // B3.c: Unreachable + corrupt identity.key → load_file_or_generate quarantines - // the corrupt file, generates a fresh key, and saves it to identity.key. +fn unreachable_corrupt_legacy_file_fails_closed_without_rewrite() { let dir = tempfile::tempdir().unwrap(); let legacy_path = dir.path().join("identity.key"); std::fs::write(&legacy_path, b"this-is-not-a-valid-nsec").unwrap(); assert!(!migration_marker_path(dir.path()).exists()); let store = FakeIdentityStore::unreachable(); - let resolved = resolve_identity_with_store(&store, &legacy_path, dir.path()).unwrap(); - - assert_eq!(resolved.recovery, RecoveryState::None); - // A fresh key was saved to identity.key (quarantine renames the corrupt file). - assert!( - legacy_path.exists(), - "fresh key must be saved to identity.key" + assert!(resolve_identity_with_store(&store, &legacy_path, dir.path()).is_err()); + assert_eq!( + std::fs::read(&legacy_path).unwrap(), + b"this-is-not-a-valid-nsec" ); - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&resolved.keys, &from_file); } // ── B4: marker-write failure variants ──────────────────────────────────── #[test] -fn persist_identity_to_keyring_marker_failure_file_fallback_returns_ok() { - // B4.1: marker write fails (data_dir is an existing file, so the marker - // path cannot be created), but the file fallback succeeds — returns Ok and - // identity.key exists and holds the original key. +fn persist_identity_marker_failure_returns_error_without_file_fallback() { let dir = tempfile::tempdir().unwrap(); let key_dir = tempfile::tempdir().unwrap(); let legacy_path = key_dir.path().join("identity.key"); @@ -1254,17 +1071,8 @@ fn persist_identity_to_keyring_marker_failure_file_fallback_returns_ok() { let result = persist_identity_to_keyring(&store, &imported_keys, &legacy_path, &data_dir_file); - assert!( - result.is_ok(), - "must return Ok when file fallback succeeds despite marker failure: {:?}", - result.err() - ); - assert!( - legacy_path.exists(), - "identity.key must be written as fallback" - ); - let from_file = load_key_file(&legacy_path).unwrap(); - assert_key_eq(&imported_keys, &from_file); + assert!(result.is_err()); + assert!(!legacy_path.exists()); } #[test] diff --git a/desktop/src-tauri/src/commands/agent_discovery/install_report_redaction_tests.rs b/desktop/src-tauri/src/commands/agent_discovery/install_report_redaction_tests.rs index ce97559616..ea7b96b57d 100644 --- a/desktop/src-tauri/src/commands/agent_discovery/install_report_redaction_tests.rs +++ b/desktop/src-tauri/src/commands/agent_discovery/install_report_redaction_tests.rs @@ -285,7 +285,7 @@ fn test_key_and_auth_inside_a_variable_name_do_not_make_it_secret() { ("GIT_AUTHOR_NAME".to_string(), "Ada Lovelace".to_string()), ( "KEYCHAIN".to_string(), - "/Users/dev/Library/login.keychain".to_string(), + "/Users/dev/Library/credential-index.db".to_string(), ), ( "NPM_CONFIG_KEYFILE".to_string(), diff --git a/desktop/src-tauri/src/commands/identity.rs b/desktop/src-tauri/src/commands/identity.rs index bddf2e725a..746de72e26 100644 --- a/desktop/src-tauri/src/commands/identity.rs +++ b/desktop/src-tauri/src/commands/identity.rs @@ -78,12 +78,15 @@ mod auto_connect_default_relay_tests { #[tauri::command] pub fn is_shared_identity() -> bool { - std::env::var("BUZZ_SHARE_IDENTITY") + let enabled = std::env::var("BUZZ_SHARE_IDENTITY") .map(|v| v == "1") - .unwrap_or(false) - && std::env::var("BUZZ_PRIVATE_KEY") + .unwrap_or(false); + enabled + && crate::secret_store::SecretStore::shared(crate::app_state::keyring_service()) + .load("identity") .ok() - .and_then(|k| Keys::parse(k.trim()).ok()) + .flatten() + .and_then(|key| Keys::parse(key.trim()).ok()) .is_some() } @@ -530,14 +533,14 @@ pub async fn persist_current_identity( /// restart is safe — the sentinel persists and the wipe completes on the next /// open. /// -/// Not available in shared-identity mode (`BUZZ_SHARE_IDENTITY=1`): the key -/// comes from an env var, not the keychain, so wiping would have no effect and -/// would be confusing. +/// Not available in shared-identity mode (`BUZZ_SHARE_IDENTITY=1`): the same +/// provider namespace may be in use by sibling worktrees, so wiping it would +/// break those sessions. #[tauri::command] pub async fn sign_out(app: tauri::AppHandle) -> Result<(), String> { if is_shared_identity() { return Err( - "Sign out isn't available while BUZZ_SHARE_IDENTITY provides your identity. Unset BUZZ_SHARE_IDENTITY and BUZZ_PRIVATE_KEY, then relaunch to sign out." + "Sign out isn't available while BUZZ_SHARE_IDENTITY shares this provider identity. Disable shared-identity mode, then relaunch to sign out." .to_string(), ); } diff --git a/desktop/src-tauri/src/commands/project_git_exec.rs b/desktop/src-tauri/src/commands/project_git_exec.rs index c616d39db1..f9d159131f 100644 --- a/desktop/src-tauri/src/commands/project_git_exec.rs +++ b/desktop/src-tauri/src/commands/project_git_exec.rs @@ -1,11 +1,10 @@ //! Shared git subprocess plumbing for the project commands. //! -//! Runs the system `git` with an ephemeral, env-only auth configuration: -//! the identity nsec is handed to `git-credential-nostr` via environment -//! variables so nothing key-related ever touches disk or global git config. +//! Runs the system `git` with an ephemeral, nonsecret auth configuration. +//! `git-credential-nostr` reads the identity directly from daz-secrets, so +//! private key bytes never enter git's environment, argv, or config. use crate::{app_state::AppState, managed_agents::resolve_command}; -use nostr::{Keys, ToBech32}; use std::io::Read; use std::process::{Command, Stdio}; use std::time::{Duration, Instant}; @@ -47,7 +46,8 @@ fn git_needs_credentials(args: &[&str]) -> bool { pub(crate) struct GitAuthConfig { git_path: std::path::PathBuf, credential_helper: Option, - nsec: String, + secret_service: String, + secret_account: String, allow_file_transport: bool, } @@ -147,9 +147,7 @@ fn configure_git_auth(command: &mut Command, auth: &GitAuthConfig, needs_credent command.env("GIT_CONFIG_GLOBAL", "/dev/null"); // Base entries: disable any inherited credential helper, and neutralize - // repo-local hooks — every process git spawns inherits our environment - // (including NOSTR_PRIVATE_KEY below), and a cloned repository's hooks - // must never run with the identity key in reach. + // repo-local hooks. No child receives the identity key itself. let mut entries: Vec<(&str, String)> = vec![ ("credential.helper", String::new()), ("core.hooksPath", "/dev/null".to_string()), @@ -172,12 +170,13 @@ fn configure_git_auth(command: &mut Command, auth: &GitAuthConfig, needs_credent let Some(cred_helper) = &auth.credential_helper else { return apply_git_config(command, &entries); }; - command.env("NOSTR_PRIVATE_KEY", &auth.nsec); entries.push(( "credential.helper", credential_helper_config_value(cred_helper), )); entries.push(("credential.useHttpPath", "true".to_string())); + entries.push(("nostr.secretService", auth.secret_service.clone())); + entries.push(("nostr.secretAccount", auth.secret_account.clone())); } apply_git_config(command, &entries); } @@ -199,8 +198,8 @@ fn apply_git_config(command: &mut Command, entries: &[(&str, String)]) { } pub(crate) fn build_git_auth_config(state: &AppState) -> Result { - let keys = state.signing_keys()?; - build_git_auth_config_for_keys(&keys) + state.signing_keys()?; + build_git_auth_config_for_account("identity") } pub(crate) fn build_git_clone_auth_config( @@ -212,31 +211,31 @@ pub(crate) fn build_git_clone_auth_config( git_path: resolve_command("git") .ok_or_else(|| "git was not found on PATH".to_string())?, credential_helper: None, - nsec: String::new(), + secret_service: crate::app_state::keyring_service().to_string(), + secret_account: "identity".to_string(), allow_file_transport: false, }); } build_git_auth_config(state) } -pub(crate) fn build_git_auth_config_for_keys(keys: &Keys) -> Result { +pub(crate) fn build_git_auth_config_for_account( + secret_account: &str, +) -> Result { let git_path = resolve_command("git").ok_or_else(|| "git was not found on PATH".to_string())?; let credential_helper = resolve_command("git-credential-nostr"); - let nsec = keys - .secret_key() - .to_bech32() - .map_err(|error| format!("encode identity key: {error}"))?; Ok(GitAuthConfig { git_path, credential_helper, - nsec, + secret_service: crate::app_state::keyring_service().to_string(), + secret_account: secret_account.to_string(), allow_file_transport: false, }) } #[cfg(test)] pub(crate) fn build_test_git_auth_config() -> Result { - let mut auth = build_git_auth_config_for_keys(&Keys::generate())?; + let mut auth = build_git_auth_config_for_account("identity")?; auth.allow_file_transport = true; Ok(auth) } diff --git a/desktop/src-tauri/src/commands/project_git_workflow.rs b/desktop/src-tauri/src/commands/project_git_workflow.rs index 9e06852762..c13401c1bf 100644 --- a/desktop/src-tauri/src/commands/project_git_workflow.rs +++ b/desktop/src-tauri/src/commands/project_git_workflow.rs @@ -3,7 +3,7 @@ use super::project_git::{first_output_line, normalize_branch_option}; use super::project_git_diff::clean_commit; use super::project_git_exec::{ - build_git_auth_config_for_keys, build_git_clone_auth_config, clone_url_owner, run_git, + build_git_auth_config_for_account, build_git_clone_auth_config, clone_url_owner, run_git, validate_local_clone_url, validate_local_clone_url_for_workspace, validate_workspace_clone_url, GitAuthConfig, }; @@ -102,6 +102,7 @@ fn normalize_event_id(value: &str) -> Option { struct ProjectOwnerIdentity { keys: Keys, auth_tag: Option, + secret_account: String, } fn project_owner_identity( @@ -114,6 +115,7 @@ fn project_owner_identity( return Ok(ProjectOwnerIdentity { keys: viewer_keys, auth_tag: None, + secret_account: "identity".to_string(), }); } @@ -140,6 +142,7 @@ fn project_owner_identity( Ok(ProjectOwnerIdentity { keys, auth_tag: record.auth_tag.clone(), + secret_account: crate::managed_agents::storage::agent_keyring_name(&record.pubkey), }) } @@ -548,7 +551,7 @@ pub async fn merge_project_pull_request( &pull_request_id, &pull_request_author, )?; - let auth = build_git_auth_config_for_keys(&owner_identity.keys)?; + let auth = build_git_auth_config_for_account(&owner_identity.secret_account)?; let git_result = tauri::async_runtime::spawn_blocking( move || -> Result { diff --git a/desktop/src-tauri/src/managed_agents/runtime.rs b/desktop/src-tauri/src/managed_agents/runtime.rs index 7afd80d1d6..a232ce0df4 100644 --- a/desktop/src-tauri/src/managed_agents/runtime.rs +++ b/desktop/src-tauri/src/managed_agents/runtime.rs @@ -567,7 +567,14 @@ pub fn spawn_agent_child( command.env("PATH", path); } command.env("RUST_LOG", child_rust_log_filter()); - command.env("BUZZ_PRIVATE_KEY", &record.private_key_nsec); + let secret_service = crate::app_state::keyring_service(); + let secret_account = super::storage::agent_keyring_name(&record.pubkey); + command.args([ + "--secret-service", + secret_service, + "--secret-account", + &secret_account, + ]); command.env("BUZZ_RELAY_URL", &effective_relay_url); command.env("BUZZ_ACP_LAZY_POOL", if lazy { "true" } else { "false" }); command.env("BUZZ_ACP_AGENT_COMMAND", &resolved_agent_command); @@ -801,24 +808,13 @@ pub fn spawn_agent_child( } command.env("BUZZ_ACP_RELAY_OBSERVER", "true"); - - // ── Git credential helper for Buzz relay ────────────────────────── - // - // Agents need to clone/push repos hosted on the Buzz relay's git - // server, which authenticates via NIP-98. The `git-credential-nostr` - // binary signs auth events using the agent's nostr key. - // - // We configure git via GIT_CONFIG_COUNT env vars (ephemeral, no - // filesystem writes) scoped to the relay's git URL so we don't - // interfere with other remotes (e.g. GitHub). - // - // NOSTR_PRIVATE_KEY mirrors BUZZ_PRIVATE_KEY — keep in sync. + // Git's nonsecret process-local config points the NIP-98 helper at the key + // in daz-secrets. if let Some(cred_helper) = resolve_command("git-credential-nostr") { let relay_http_url = crate::relay::relay_http_base_url(&effective_relay_url); - command.env("NOSTR_PRIVATE_KEY", &record.private_key_nsec); command.env("GIT_TERMINAL_PROMPT", "0"); - command.env("GIT_CONFIG_COUNT", "2"); + command.env("GIT_CONFIG_COUNT", "4"); command.env( "GIT_CONFIG_KEY_0", format!("credential.{relay_http_url}/git.helper"), @@ -830,6 +826,10 @@ pub fn spawn_agent_child( format!("credential.{relay_http_url}/git.useHttpPath"), ); command.env("GIT_CONFIG_VALUE_1", "true"); + command.env("GIT_CONFIG_KEY_2", "nostr.secretService"); + command.env("GIT_CONFIG_VALUE_2", secret_service); + command.env("GIT_CONFIG_KEY_3", "nostr.secretAccount"); + command.env("GIT_CONFIG_VALUE_3", &secret_account); } else { eprintln!( "buzz-desktop: git-credential-nostr not found — agent {} will not have automatic Buzz git auth", diff --git a/desktop/src-tauri/src/managed_agents/storage.rs b/desktop/src-tauri/src/managed_agents/storage.rs index 652bb9b9ea..01337dd182 100644 --- a/desktop/src-tauri/src/managed_agents/storage.rs +++ b/desktop/src-tauri/src/managed_agents/storage.rs @@ -15,7 +15,7 @@ use crate::secret_store::{KeyringProbe, SecretStore}; /// Keyring key name for an agent's nsec, namespaced from the human identity /// key (`"identity"`) which shares the service. -fn agent_keyring_name(pubkey: &str) -> String { +pub(crate) fn agent_keyring_name(pubkey: &str) -> String { format!("agent:{pubkey}") } @@ -262,7 +262,7 @@ fn load_agent_store(app: &AppHandle) -> Result, String> pub fn load_managed_agents(app: &AppHandle) -> Result, String> { let mut records = load_agent_store(app)?; records.retain(|record| !record.pubkey.is_empty()); - hydrate_keys(&mut records); + hydrate_keys(&mut records)?; Ok(records) } @@ -302,11 +302,10 @@ pub(crate) fn backup_invalid_store(path: &Path) { /// writes clean JSON and plaintext stops lingering on disk; if still /// unreachable, leave it inline. This makes the strip deterministic on the /// next reachable boot rather than waiting for a non-deterministic save. -fn hydrate_keys(records: &mut [ManagedAgentRecord]) { - let Some(store) = agent_secret_store() else { - return; - }; - hydrate_keys_with(store, records); +fn hydrate_keys(records: &mut [ManagedAgentRecord]) -> Result<(), String> { + let store = + agent_secret_store().ok_or_else(|| "secret-provider support is disabled".to_string())?; + hydrate_keys_with(store, records) } /// Testable core of [`hydrate_keys`], generic over the [`KeyStore`] seam. @@ -317,7 +316,10 @@ fn hydrate_keys(records: &mut [ManagedAgentRecord]) { /// to spawn an agent whose key could not be read (see the empty-key bail in /// `spawn_agent_child`). Empty here never means "fine" — it means "no usable /// key this boot." -fn hydrate_keys_with(store: &impl KeyStore, records: &mut [ManagedAgentRecord]) { +fn hydrate_keys_with( + store: &impl KeyStore, + records: &mut [ManagedAgentRecord], +) -> Result<(), String> { for record in records.iter_mut() { // A key-less definition (no pubkey yet — unified agent model) has no // keyring entry by construction; keys are minted on first start. @@ -337,11 +339,10 @@ fn hydrate_keys_with(store: &impl KeyStore, records: &mut [ManagedAgentRecord]) // unreadable this boot. Leave it empty so the spawn path // refuses rather than launching with no identity. Err(e) => { - eprintln!( - "buzz-desktop: agent {} key unavailable — keyring read failed ({e}); \ - agent will be refused until the keyring is reachable", + return Err(format!( + "agent {} key unavailable from secret provider: {e}", record.pubkey - ); + )); } } } else { @@ -350,9 +351,15 @@ fn hydrate_keys_with(store: &impl KeyStore, records: &mut [ManagedAgentRecord]) // returned record must carry the key for readers. The next save // then strips it from JSON. Outcome is intentionally ignored: // on failure the key simply stays inline until a later boot. - let _ = migrate_inline_key(store, record); + if migrate_inline_key(store, record) == KeyMigration::KeptInline { + return Err(format!( + "failed to migrate legacy inline key for agent {}", + record.pubkey + )); + } } } + Ok(()) } /// Save the keyed agent *instances*, preserving the key-less definitions that @@ -376,7 +383,7 @@ pub fn save_managed_agents(app: &AppHandle, records: &[ManagedAgentRecord]) -> R // Persist each key to the keyring; on success blank the inline copy so it // is skipped from JSON (`skip_serializing_if = "String::is_empty"`). If the // keyring is unreachable, the key stays inline. - persist_agent_keys(&mut sorted); + persist_agent_keys(&mut sorted)?; write_agent_store(app, definitions, sorted) } @@ -421,26 +428,35 @@ fn write_agent_store( /// on success. Keys that cannot be persisted (keyring unreachable) stay inline /// in the JSON. Mutates `records` (a save-local clone) — the caller's in-memory /// records keep their keys. -fn persist_agent_keys(records: &mut [ManagedAgentRecord]) { - let Some(store) = agent_secret_store() else { - // No keyring backend: keys stay inline. - return; - }; - persist_agent_keys_with(store, records); +fn persist_agent_keys(records: &mut [ManagedAgentRecord]) -> Result<(), String> { + let store = + agent_secret_store().ok_or_else(|| "secret-provider support is disabled".to_string())?; + persist_agent_keys_with(store, records) } /// Testable core of [`persist_agent_keys`], generic over the [`KeyStore`] seam. -fn persist_agent_keys_with(store: &impl KeyStore, records: &mut [ManagedAgentRecord]) { +fn persist_agent_keys_with( + store: &impl KeyStore, + records: &mut [ManagedAgentRecord], +) -> Result<(), String> { for record in records.iter_mut() { // Only a verified keyring entry lets us drop the inline copy. Both // other outcomes keep the key inline: `KeptInline` (keyring // unreachable) so it is not lost, and `Nothing` (empty key) because // there is no verified entry to claim. This is a save-local clone, so // callers keep their keys regardless. - if migrate_inline_key(store, record) == KeyMigration::Persisted { - record.private_key_nsec.clear(); + match migrate_inline_key(store, record) { + KeyMigration::Persisted => record.private_key_nsec.clear(), + KeyMigration::Nothing => {} + KeyMigration::KeptInline => { + return Err(format!( + "failed to persist agent {} key in secret provider", + record.pubkey + )); + } } } + Ok(()) } /// One-time migration of agent keys from the production keyring service diff --git a/desktop/src-tauri/src/managed_agents/storage_tests.rs b/desktop/src-tauri/src/managed_agents/storage_tests.rs index 9943c6b3ac..663a9e2301 100644 --- a/desktop/src-tauri/src/managed_agents/storage_tests.rs +++ b/desktop/src-tauri/src/managed_agents/storage_tests.rs @@ -211,20 +211,20 @@ fn hydrate_fills_key_from_keyring_when_reachable() { FakeKeyStore::reachable().with_key(&agent_keyring_name("agent-pubkey"), "nsec1stored"); let mut records = vec![record_with_key("")]; - hydrate_keys_with(&store, &mut records); + hydrate_keys_with(&store, &mut records).unwrap(); assert_eq!(records[0].private_key_nsec, "nsec1stored"); } #[test] -fn hydrate_leaves_key_empty_on_keyring_outage() { +fn hydrate_returns_error_on_provider_outage() { // Outage edge (Wes storage.rs:158): when the keyring read ERRORS, the // key must be left empty — never silently treated as resolved — so the // spawn path refuses rather than launching the agent with no identity. let store = FakeKeyStore::unreachable(); let mut records = vec![record_with_key("")]; - hydrate_keys_with(&store, &mut records); + assert!(hydrate_keys_with(&store, &mut records).is_err()); assert!( records[0].private_key_nsec.is_empty(), @@ -262,7 +262,7 @@ fn persist_agent_keys_issues_zero_writes_when_inline_keys_already_cleared() { // Records whose inline key is already blank (key lives in the keyring). let mut records = vec![record_with_key(""), record_with_key("")]; - persist_agent_keys_with(&store, &mut records); + persist_agent_keys_with(&store, &mut records).unwrap(); assert_eq!( *store.write_count.borrow(), @@ -284,7 +284,7 @@ fn persist_agent_keys_writes_once_per_record_with_inline_key() { record_with_pubkey_and_key("pubkey-agent-beta", "nsec1key_b"), ]; - persist_agent_keys_with(&store, &mut records); + persist_agent_keys_with(&store, &mut records).unwrap(); assert_eq!( *store.write_count.borrow(), diff --git a/desktop/src-tauri/src/migration.rs b/desktop/src-tauri/src/migration.rs index b3e613621e..9fe8657d85 100644 --- a/desktop/src-tauri/src/migration.rs +++ b/desktop/src-tauri/src/migration.rs @@ -3,7 +3,7 @@ //! **Worktree sync** (`sync_shared_agent_data`): Per-launch symlink creation //! from the current worktree data directory to the canonical dev data //! directory (`xyz.block.buzz.app.dev`). Only runs when -//! `BUZZ_SHARE_IDENTITY=1` and `BUZZ_PRIVATE_KEY` is set. All dev +//! `BUZZ_SHARE_IDENTITY=1` and the configured provider identity exists. All dev //! instances share the same physical files — edits in any worktree are //! immediately visible to all others. //! @@ -27,8 +27,8 @@ const LEGACY_RELEASE_IDENTIFIER: &str = "xyz.block.sprout.app"; /// JSON files symlinked from worktree data directories to the canonical /// dev data directory. Only data files — never `agent-pids/` or `logs/`. -/// `identity.key` is deliberately excluded because worktree instances -/// receive their identity via the `BUZZ_PRIVATE_KEY` env var. +/// `identity.key` is deliberately excluded because worktree instances resolve +/// their identity from the configured secret provider. const SHARED_AGENT_FILES: &[&str] = &[ "agents/managed-agents.json", "agents/personas.json", @@ -760,25 +760,14 @@ fn replace_builtin_avatar(record: &mut serde_json::Value, persona_id: &str, now: /// /// Guards: /// - `BUZZ_SHARE_IDENTITY` must be `"1"` -/// - `BUZZ_PRIVATE_KEY` must parse as valid `nostr::Keys` +/// - The configured provider identity must parse as valid `nostr::Keys` /// - The canonical dir must differ from the current dir (skip if we ARE canonical) /// - The canonical dir must exist pub fn sync_shared_agent_data(app: &tauri::AppHandle) { - // Guard: only runs when sharing identity with a worktree. - let is_shared = std::env::var("BUZZ_SHARE_IDENTITY") - .map(|v| v == "1") - .unwrap_or(false); - if !is_shared { - return; - } - - // Guard: BUZZ_PRIVATE_KEY must be a valid nostr key. - let has_valid_key = std::env::var("BUZZ_PRIVATE_KEY") - .ok() - .and_then(|k| k.parse::().ok()) - .is_some(); - if !has_valid_key { - eprintln!("buzz-desktop: shared-agent-sync: BUZZ_PRIVATE_KEY missing or invalid, skipping"); + if !crate::commands::is_shared_identity() { + eprintln!( + "buzz-desktop: shared-agent-sync: provider identity missing or invalid, skipping" + ); return; } diff --git a/desktop/src-tauri/src/relay_admission.rs b/desktop/src-tauri/src/relay_admission.rs index 15222f8590..c3fe4fbdfb 100644 --- a/desktop/src-tauri/src/relay_admission.rs +++ b/desktop/src-tauri/src/relay_admission.rs @@ -101,17 +101,18 @@ pub fn reset_rate_limit_gate() { } #[cfg(test)] +#[allow(clippy::await_holding_lock)] mod tests { use super::*; // The gate is a process-wide static shared by every test in this binary, // so all gate tests serialize on one async lock to keep armed expiries // from bleeding between parallel test threads. - pub(crate) static TEST_SERIAL: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(()); + pub(crate) static TEST_SERIAL: std::sync::Mutex<()> = std::sync::Mutex::new(()); #[tokio::test(start_paused = true)] async fn wait_returns_immediately_when_gate_is_inactive() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); let start = Instant::now(); wait_for_rate_limit().await; @@ -124,7 +125,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn hintless_429_arms_the_ten_second_default() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); activate_rate_limit(None); let start = Instant::now(); @@ -135,7 +136,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn shorter_hint_never_shrinks_an_active_window() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); activate_rate_limit(Some(8)); activate_rate_limit(Some(1)); @@ -151,7 +152,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn concurrent_429_extends_the_window_for_parked_waiters() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); activate_rate_limit(Some(2)); let start = Instant::now(); @@ -174,7 +175,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn hint_zero_uses_default() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); activate_rate_limit(Some(0)); let start = Instant::now(); @@ -189,7 +190,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn hint_at_max_is_honoured() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); activate_rate_limit(Some(MAX_HINT_SECONDS)); let start = Instant::now(); @@ -204,7 +205,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn oversize_hint_is_clamped_to_max() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); // An oversize hint (including u64::MAX) must clamp rather than panic. activate_rate_limit(Some(u64::MAX)); @@ -222,7 +223,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn workspace_change_clears_armed_gate() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); activate_rate_limit(Some(60)); // Switch workspace — gate for community A must not stall community B. @@ -238,7 +239,7 @@ mod tests { #[tokio::test(start_paused = true)] async fn community_a_gate_does_not_block_community_b() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); // Community A gets a 429 with a 30s window. activate_rate_limit(Some(30)); @@ -264,7 +265,7 @@ mod tests { async fn gate_armed_by_one_path_withholds_another_path() { use std::io::{Read, Write}; - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); // The loopback server answers every request with 200 []. @@ -326,7 +327,7 @@ mod tests { /// is the same bound as if the workspace had not changed. #[tokio::test(start_paused = true)] async fn parked_waiter_does_not_wake_early_after_workspace_reset() { - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); // Arm a 5s gate for community A. @@ -375,7 +376,7 @@ mod tests { use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _}; use serde::Deserialize; - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); // Arm the gate for 1s (real time — NIP-98 uses SystemTime, not Tokio clock). @@ -435,7 +436,7 @@ mod tests { async fn http_429_withholds_next_relay_command_until_expiry_then_resumes() { use std::io::{Read, Write}; - let _serial = TEST_SERIAL.lock().await; + let _serial = TEST_SERIAL.lock().unwrap_or_else(|e| e.into_inner()); reset_rate_limit_gate(); let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); diff --git a/desktop/src-tauri/src/secret_store.rs b/desktop/src-tauri/src/secret_store.rs index 43854761b5..fd761ac6fa 100644 --- a/desktop/src-tauri/src/secret_store.rs +++ b/desktop/src-tauri/src/secret_store.rs @@ -1,1306 +1,215 @@ -//! OS keyring access for desktop nsec private keys. +//! Process-isolated secret storage for desktop nsec private keys. //! -//! All secrets are stored as a single JSON blob under one keychain entry -//! (service = the store's service name, username = `"secrets"`). This means -//! exactly one OS prompt per process lifetime regardless of how many keys are -//! stored — the same pattern used by Goose. -//! -//! The chosen backend is selected at compile time by the per-target feature in -//! `Cargo.toml`. On macOS the legacy `keyring` crate (SecKeychain API) is used -//! for the blob entry so that signed release builds and unsigned dev builds -//! share the same store. DPK (Data Protection Keychain) is used only by the -//! one-time migration path that reads old per-key entries written by #1264. -//! Windows and Linux use the `keyring` crate directly. The `system-keyring` -//! feature gates the whole store; when it is off, [`SecretStore`] is unusable -//! and callers fall back to their own `0o600` file storage. -//! -//! The store is deliberately NOT on any env-read path. `BUZZ_PRIVATE_KEY` -//! resolution for harnessed agents and CI is handled upstream (an env -//! short-circuit for the human key, child-process env injection for agents); -//! adding an env tier here would duplicate that precedence and create a -//! divergent-behavior trap. - +//! Buzz never calls a platform keyring. Every operation uses the public +//! `daz-secrets` client, which starts the provider configured in the current +//! OS account's owner-only `~/.config/daz-secrets/provider.toml`. Darren's +//! machine selects a private encrypted provider; other installations may +//! select any conforming provider, including an optional OS-keyring adapter. +//! Secret bytes travel only through anonymous child-process pipes. + +use daz_secrets::{BlockingClient, ErrorCode, Metadata, Secret}; use std::collections::HashMap; -use std::path::PathBuf; -use std::sync::Mutex; +use std::sync::OnceLock; -/// Result of probing the keyring before a migration: distinguishes "reachable -/// but holds no entry" (safe to migrate into) from "unreachable this boot" -/// (must NOT migrate — re-importing from a leftover plaintext file could -/// resurrect a rotated/stale key). +/// Result of probing the configured provider before a migration. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum KeyringProbe { - /// Keyring is reachable and an entry for the key already exists. + /// The provider contains the requested item. Present, - /// Keyring is reachable but has no entry for the key. + /// The provider is reachable but the requested item is absent. ReachableButEmpty, - /// Keyring backend is unavailable this boot (no Secret Service, dbus - /// failure, etc.). Migration must be skipped. + /// The provider is unavailable or returned an unverifiable result. Unreachable, } -/// Username used for the single blob keychain entry. All secrets are stored -/// as a JSON map under this name within the service. -const BLOB_KEY: &str = "secrets"; - -// ── Interprocess advisory lock ───────────────────────────────────────────── -// -// Two concurrent Buzz processes (e.g. the signed DMG build and an unsigned dev -// build via `just staging`) share the same OS keychain blob because the -// service name `"buzz-desktop"` is a constant — it does not key off the bundle -// identifier. Each process holds its own in-memory cache, so without an -// interprocess lock a warm-cache write in process A drops keys added by process -// B between A's last cache-warming read and A's write. -// -// The fix: `mutate_blob` acquires an exclusive advisory file lock, then always -// performs a fresh `read_blob_raw()` inside the lock, applies the mutation, -// writes back, and releases. The cache is still updated after a successful -// write, so same-process reads remain fast. The lock is file-based at a fixed -// per-user path `/tmp/buzz-keychain--.lock` on Unix — a path -// that is invariant to `$TMPDIR`/process environment, so both the GUI-launched -// signed DMG and a terminal-launched dev build always take the same lock. - -/// Return the path of the advisory lockfile for `service`. -/// -/// The path is `/tmp/buzz-keychain--.lock` on Unix — a -/// deterministic per-user path that is invariant to `$TMPDIR`/process -/// environment. Both a GUI-launched signed DMG (`launchd`, env-stripped) and a -/// terminal-launched dev build resolve `/tmp` to the same inode, so they -/// contend on the same lockfile and achieve mutual exclusion. -/// -/// On Windows the same name used for the kernel mutex is derived from the -/// lockfile path, so the service-keyed uniqueness is preserved. -fn blob_lockfile_path(service: &str) -> PathBuf { - #[cfg(unix)] - { - // Use the real UID so distinct users get distinct lockfiles. - // SAFETY: getuid() is always safe on Unix — it never fails. - let uid = unsafe { libc::getuid() }; - PathBuf::from(format!("/tmp/buzz-keychain-{uid}-{service}.lock")) - } - #[cfg(not(unix))] - { - // Windows: no lockfile used (named mutex instead); this path is only - // used to derive the mutex name and for test assertions. - std::env::temp_dir().join(format!("buzz-keychain-{service}.lock")) - } -} - -/// Acquire an exclusive advisory file lock for the blob identified by `service`. -/// -/// Opens (or creates) the lockfile and blocks until the lock is acquired. -/// Returns the open `File`; the lock is released when the file is dropped. -/// -/// On non-Unix/non-Windows platforms this is a no-op that returns a stub. -#[cfg(feature = "system-keyring")] -fn acquire_blob_lock(service: &str) -> Result { - let path = blob_lockfile_path(service); - BlobLockGuard::acquire(&path) -} - -/// RAII guard that holds an exclusive advisory file lock. -/// -/// On Unix, implemented via `flock(2)` on a lockfile in the system temp dir. -/// On Windows, implemented via a named kernel mutex (cross-process, no file I/O -/// needed). The Windows mutex handle is released on drop. -#[cfg(feature = "system-keyring")] -struct BlobLockGuard { - /// The open lockfile. Never read — held purely for RAII: closing the fd - /// releases the `flock(LOCK_EX)` on Unix. - #[cfg(unix)] - #[allow(dead_code)] - file: std::fs::File, - #[cfg(windows)] - mutex_handle: windows_sys::Win32::Foundation::HANDLE, -} - -#[cfg(feature = "system-keyring")] -impl BlobLockGuard { - fn acquire(path: &std::path::Path) -> Result { - #[cfg(unix)] - { - let file = std::fs::OpenOptions::new() - .create(true) - .truncate(false) - .write(true) - .open(path) - .map_err(|e| format!("blob lock open {}: {e}", path.display()))?; - use std::os::unix::io::AsRawFd; - // LOCK_EX blocks until the lock is acquired (no LOCK_NB). - let ret = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX) }; - if ret != 0 { - let err = std::io::Error::last_os_error(); - return Err(format!("blob lock flock: {err}")); - } - return Ok(BlobLockGuard { file }); - } - - #[cfg(windows)] - { - // Named kernel mutexes are cross-process on Windows — no lockfile - // needed. Derive a unique mutex name from the lockfile path so - // distinct services get distinct mutexes. - let name_str = format!( - "Local\\BuzzKeychain-{}", - path.file_stem() - .and_then(|s| s.to_str()) - .unwrap_or("default") - ); - // Encode as null-terminated UTF-16. - let name_wide: Vec = name_str - .encode_utf16() - .chain(std::iter::once(0u16)) - .collect(); - use windows_sys::Win32::Foundation::WAIT_OBJECT_0; - use windows_sys::Win32::Security::SECURITY_ATTRIBUTES; - use windows_sys::Win32::System::Threading::{ - CreateMutexW, WaitForSingleObject, INFINITE, - }; - // CreateMutexW: lpMutexAttributes = null (default security), - // bInitialOwner = FALSE (0), lpName = our mutex name. - let handle = unsafe { - CreateMutexW( - std::ptr::null::(), - 0, - name_wide.as_ptr(), - ) - }; - // HANDLE = *mut c_void; null means creation failed. - if handle.is_null() { - let err = std::io::Error::last_os_error(); - return Err(format!("blob lock CreateMutexW: {err}")); - } - let wait_result = unsafe { WaitForSingleObject(handle, INFINITE) }; - if wait_result != WAIT_OBJECT_0 { - // Also accept WAIT_ABANDONED (0x80) — previous holder crashed; - // the mutex is still acquired and we own it. - if wait_result != windows_sys::Win32::Foundation::WAIT_ABANDONED { - let err = std::io::Error::last_os_error(); - unsafe { windows_sys::Win32::Foundation::CloseHandle(handle) }; - return Err(format!( - "blob lock WaitForSingleObject: {wait_result} / {err}" - )); - } - } - return Ok(BlobLockGuard { - mutex_handle: handle, - }); - } - - // Fallback for exotic platforms: no-op lock (only Unix/Windows ship). - #[allow(unreachable_code)] - Err("blob lock: unsupported platform".to_string()) - } -} - -#[cfg(feature = "system-keyring")] -impl Drop for BlobLockGuard { - fn drop(&mut self) { - #[cfg(unix)] - { - // Dropping `self.file` closes the fd, which releases flock on Unix. - // Nothing explicit needed. - } - #[cfg(windows)] - { - unsafe { - windows_sys::Win32::System::Threading::ReleaseMutex(self.mutex_handle); - windows_sys::Win32::Foundation::CloseHandle(self.mutex_handle); - } - } - } -} - -// ── End interprocess advisory lock ──────────────────────────────────────── - -/// An OS keyring, addressed by service name. All secrets are stored in a -/// single JSON blob entry (one OS prompt per process lifetime). +/// Secret storage namespace backed by the configured daz-secrets provider. pub struct SecretStore { service: String, - /// In-memory cache of the deserialized blob. `None` means "not yet loaded". - cache: Mutex>>, } impl SecretStore { - /// Keyring-backed store under `service`. The active platform backend - /// (apple-native / windows-native / sync-secret-service) is chosen at - /// compile time. + /// Construct a provider-backed store. + /// + /// The method name is retained for source compatibility with older Buzz + /// code; it does not access an operating-system keyring. pub fn keyring(service: impl Into) -> Self { - SecretStore { + Self { service: service.into(), - cache: Mutex::new(None), } } - /// Return a process-global `SecretStore` for `service`. All callers with - /// the same service name share one instance — and therefore one in-memory - /// cache and one mutex — so concurrent blob read-modify-write operations - /// see each other's writes and the last-writer-wins race is closed. - /// - /// Only one service name (`"buzz-desktop"`) is used in practice. If a - /// second service name is ever needed, this can be extended to a registry. - pub fn shared(service: &'static str) -> &'static SecretStore { - use std::sync::OnceLock; + /// Return the process-global store for the configured service. + pub fn shared(service: &'static str) -> &'static Self { static INSTANCE: OnceLock = OnceLock::new(); - INSTANCE.get_or_init(|| SecretStore::keyring(service)) + INSTANCE.get_or_init(|| Self::keyring(service)) } -} - -/// Whether a keyring error string indicates the backend itself is unavailable -/// (vs. a per-entry error like "not found"). Mirrors goose's discriminator -/// (`crates/goose/src/config/base.rs`): treat dbus / Secret Service / platform -/// secure-storage failures as "keyring unavailable, fall back to file". -#[cfg(feature = "system-keyring")] -fn is_keyring_availability_error(error_str: &str) -> bool { - let lower = error_str.to_lowercase(); - lower.contains("keyring") - || lower.contains("dbus") - || lower.contains("org.freedesktop.secrets") - || lower.contains("platform secure storage") - || lower.contains("no secret service") -} - -#[cfg(feature = "system-keyring")] -fn keyring_entry(service: &str, key: &str) -> Result { - keyring::Entry::new(service, key) -} - -// macOS-specific imports for the Data Protection Keychain backend. -#[cfg(all(feature = "system-keyring", target_os = "macos"))] -use security_framework::base::Error as SFError; -#[cfg(all(feature = "system-keyring", target_os = "macos"))] -use security_framework::passwords::{ - delete_generic_password_options, generic_password, PasswordOptions, -}; - -/// Returns true when the security-framework error is "item not found" (-25300). -#[cfg(all(feature = "system-keyring", target_os = "macos"))] -fn is_not_found(e: &SFError) -> bool { - e.code() == -25300 -} - -/// Returns true when DPK is unavailable because the binary lacks the required -/// entitlement (`errSecMissingEntitlement`, -34018). This happens for unsigned -/// dev builds (`tauri dev` / `cargo run`). The caller should fall back to the -/// legacy `keyring` crate path, which uses the old-style keychain and does not -/// require hardened-runtime entitlements. -#[cfg(all(feature = "system-keyring", target_os = "macos"))] -fn is_dpk_unavailable(e: &SFError) -> bool { - e.code() == -34018 -} - -/// Build a `PasswordOptions` for the Data Protection Keychain. -#[cfg(all(feature = "system-keyring", target_os = "macos"))] -fn dpk_opts(service: &str, key: &str) -> PasswordOptions { - let mut opts = PasswordOptions::new_generic_password(service, key); - opts.use_protected_keychain(); - opts -} - -impl SecretStore { - /// Read the blob from the keychain and return the deserialized map. - /// - /// Returns `Ok(None)` when no blob entry exists yet (first launch or - /// fresh install). Returns `Err` when the backend is unavailable or the - /// stored JSON is corrupt. - /// - /// On success the result is stored in `self.cache` so subsequent calls - /// within the same process return immediately without a keychain round-trip. - #[cfg(feature = "system-keyring")] - fn load_blob(&self) -> Result>, String> { - { - let guard = self.cache.lock().unwrap_or_else(|e| e.into_inner()); - if let Some(ref map) = *guard { - return Ok(Some(map.clone())); - } - } - let raw = self.read_blob_raw()?; - let map = match raw { - None => return Ok(None), - Some(bytes) => { - let json = String::from_utf8(bytes).map_err(|e| format!("blob utf8: {e}"))?; - serde_json::from_str::>(&json) - .map_err(|e| format!("blob json: {e}"))? - } - }; - - // Only populate the cache if it is still empty — a concurrent - // mutate_blob() may have written a newer value while we were reading. - let mut guard = self.cache.lock().unwrap_or_else(|e| e.into_inner()); - if guard.is_none() { - *guard = Some(map.clone()); - } - Ok(Some(map)) - } - - /// Read the raw blob bytes from the keychain. `Ok(None)` = not found. - /// - /// Always uses the legacy keyring crate on macOS so that signed and - /// unsigned (dev) builds share the same store. DPK is only used by - /// `migrate_legacy_key` to read old per-key entries written by #1264. - #[cfg(all(feature = "system-keyring", target_os = "macos"))] - fn read_blob_raw(&self) -> Result>, String> { - self.read_blob_raw_keyring() - } - - #[cfg(all(feature = "system-keyring", not(target_os = "macos")))] - fn read_blob_raw(&self) -> Result>, String> { - self.read_blob_raw_keyring() - } - - /// Read blob via the legacy `keyring` crate (Windows, Linux, or macOS dev - /// builds that lack hardened-runtime entitlements). - #[cfg(feature = "system-keyring")] - fn read_blob_raw_keyring(&self) -> Result>, String> { - let entry = - keyring_entry(&self.service, BLOB_KEY).map_err(|e| format!("keyring entry: {e}"))?; - match entry.get_password() { - Ok(s) => Ok(Some(s.into_bytes())), - Err(keyring::Error::NoEntry) => Ok(None), - Err(e) if is_keyring_availability_error(&e.to_string()) => { - Err(format!("keyring unavailable: {e}")) - } - Err(e) => Err(format!("keyring read: {e}")), - } - } - - /// Atomically load the blob, apply `f` to a candidate map, write back if - /// changed, and only then advance the cache. - /// - /// **Cross-process safety**: acquires an exclusive advisory file lock - /// (`flock(2)` on Unix, `LockFileEx` on Windows) before reading, mutating, - /// and writing. The lock is keyed by service name and stored in the system - /// temp directory, making it reachable from both the signed DMG build and - /// unsigned dev builds. Inside the lock a fresh `read_blob_raw()` is always - /// performed (even when the cache is warm) so a concurrent process's write - /// is never silently dropped. - /// - /// **Idempotent**: when `f` leaves the candidate equal to the freshly-read - /// map, `write_blob_raw` is skipped entirely. On macOS the legacy - /// `SecKeychain` API treats a write as a distinct ACL operation from the - /// "Always Allow"-ed read, so skipping no-op writes eliminates the keychain - /// prompt that fires when saving an agent whose model changed but whose key - /// did not. - /// - /// **Copy-on-write**: the candidate `next` is a separate allocation from - /// `current`. The cache is only replaced with `next` after `write_blob_raw` - /// succeeds. On write failure the cache is cleared to `None` so the next - /// caller re-reads from the keychain rather than building on a stale state. - /// - /// Deadlock-free: `read_blob_raw` and `write_blob_raw` do not acquire the - /// cache mutex. `load_blob` does acquire it, but `mutate_blob` does not call - /// `load_blob` — it reads from the keyring directly inside the file lock. - #[cfg(feature = "system-keyring")] - fn mutate_blob(&self, f: F) -> Result<(), String> - where - F: FnOnce(&mut HashMap), - { - // Acquire the interprocess advisory lock first. All Buzz processes - // using the same service name contend on the same lockfile at - // /tmp/buzz-keychain--.lock (a deterministic per-user - // path invariant to $TMPDIR), so only one process performs a - // read-modify-write at a time. - let _lock = acquire_blob_lock(&self.service)?; - - // Always do a fresh read from the keychain while holding the lock — - // this is the critical correction over the prior warm-cache path. A - // stale warm cache would make us build our candidate on an outdated - // baseline and drop keys written by another process. - let raw = self.read_blob_raw()?; - let current: HashMap = match raw { - None => HashMap::new(), - Some(bytes) => { - let json = String::from_utf8(bytes).map_err(|e| format!("blob utf8: {e}"))?; - serde_json::from_str::>(&json) - .map_err(|e| format!("blob json: {e}"))? - } - }; - - // Build the candidate state in a separate allocation so that a write - // failure below cannot leave the cache ahead of durable storage. - let mut next = current.clone(); - f(&mut next); - - // Skip the keychain write when the candidate equals the freshly-read - // durable state — no I/O needed and no keychain ACL prompt on macOS. - if next == current { - // Update the cache to the fresh read even on no-op so subsequent - // reads in this process see any keys another process may have added. - let mut guard = self.cache.lock().unwrap_or_else(|e| e.into_inner()); - *guard = Some(current); - return Ok(()); - } - - // Write to keyring while still holding the file lock. - let json = serde_json::to_string(&next).map_err(|e| format!("blob serialize: {e}"))?; - match self.write_blob_raw(json.as_bytes()) { - Ok(()) => { - // Advance the cache to `next` only after the durable write succeeds. - let mut guard = self.cache.lock().unwrap_or_else(|e| e.into_inner()); - *guard = Some(next); - Ok(()) - } - Err(e) => { - // On write failure, clear the cache so the next caller re-reads - // from the keychain rather than building on a stale state. - let mut guard = self.cache.lock().unwrap_or_else(|e| e.into_inner()); - *guard = None; - Err(e) - } - } - } - - /// Always uses the legacy keyring crate on macOS — see `read_blob_raw`. - #[cfg(all(feature = "system-keyring", target_os = "macos"))] - fn write_blob_raw(&self, bytes: &[u8]) -> Result<(), String> { - self.write_blob_raw_keyring(bytes) - } - - #[cfg(all(feature = "system-keyring", not(target_os = "macos")))] - fn write_blob_raw(&self, bytes: &[u8]) -> Result<(), String> { - self.write_blob_raw_keyring(bytes) - } - - #[cfg(feature = "system-keyring")] - fn write_blob_raw_keyring(&self, bytes: &[u8]) -> Result<(), String> { - let value = std::str::from_utf8(bytes).map_err(|e| format!("blob utf8 encode: {e}"))?; - let entry = - keyring_entry(&self.service, BLOB_KEY).map_err(|e| format!("keyring entry: {e}"))?; - entry - .set_password(value) - .map_err(|e| format!("keyring write: {e}")) - } - - /// Probe whether `key` exists and whether the backend is reachable. + /// Probe whether `key` is present without displaying authentication UI. pub fn probe(&self, key: &str) -> KeyringProbe { - #[cfg(feature = "system-keyring")] - { - match self.load_blob() { - Ok(Some(map)) => { - if map.contains_key(key) { - KeyringProbe::Present - } else { - // Blob exists but key absent — still check old per-key - // entries so a partial migration (e.g. identity migrated - // first) doesn't silently drop agent keys. - self.probe_legacy_key(key) - } - } - // No blob yet — check old per-key entries so callers that - // gate `load()` on `Present` still trigger migration. - Ok(None) => self.probe_legacy_key(key), - Err(e) if is_keyring_availability_error(&e) => KeyringProbe::Unreachable, - Err(_) => KeyringProbe::Unreachable, // corrupt blob — fail closed - } - } - #[cfg(not(feature = "system-keyring"))] - { - let _ = key; - KeyringProbe::Unreachable - } - } - - /// Check old per-key DPK/keyring entries for `key`. Used by `probe()` when - /// the blob doesn't exist yet (first launch after upgrade). - #[cfg(all(feature = "system-keyring", target_os = "macos"))] - fn probe_legacy_key(&self, key: &str) -> KeyringProbe { - match generic_password(dpk_opts(&self.service, key)) { + match provider_get(self.service.clone(), key.to_string()) { Ok(_) => KeyringProbe::Present, - Err(ref e) if is_not_found(e) => self.probe_legacy_key_keyring(key), - Err(ref e) if is_dpk_unavailable(e) => self.probe_legacy_key_keyring(key), - Err(ref e) if is_keyring_availability_error(&e.to_string()) => { - KeyringProbe::Unreachable - } - Err(_) => KeyringProbe::ReachableButEmpty, - } - } - - #[cfg(all(feature = "system-keyring", not(target_os = "macos")))] - fn probe_legacy_key(&self, key: &str) -> KeyringProbe { - self.probe_legacy_key_keyring(key) - } - - #[cfg(feature = "system-keyring")] - fn probe_legacy_key_keyring(&self, key: &str) -> KeyringProbe { - match keyring_entry(&self.service, key) { - Ok(entry) => match entry.get_password() { - Ok(_) => KeyringProbe::Present, - Err(keyring::Error::NoEntry) => KeyringProbe::ReachableButEmpty, - Err(e) if is_keyring_availability_error(&e.to_string()) => { - KeyringProbe::Unreachable - } - Err(_) => KeyringProbe::ReachableButEmpty, - }, - Err(e) if is_keyring_availability_error(&e.to_string()) => KeyringProbe::Unreachable, - Err(_) => KeyringProbe::Unreachable, + Err(ProviderFailure::NotFound) => KeyringProbe::ReachableButEmpty, + Err(ProviderFailure::Other) => KeyringProbe::Unreachable, } } - /// Load the secret for `key`. `Ok(None)` when there is no entry; `Err` only - /// when the backend errored in a way that is not "missing". - /// - /// On first launch after an upgrade from the per-key DPK format, the blob - /// will not exist yet. In that case the macOS path falls back to reading the - /// old per-key DPK entry for `key` specifically, writes it into a new blob, - /// and deletes the old item — a one-time migration per key. The same - /// migration fires when the blob exists but the key is absent, covering - /// partial-migration scenarios (e.g. identity migrated first, agents not yet). + /// Load a UTF-8 secret. Missing items return `Ok(None)`. pub fn load(&self, key: &str) -> Result, String> { - #[cfg(feature = "system-keyring")] - { - match self.load_blob() { - Ok(Some(map)) => { - if let Some(value) = map.get(key) { - Ok(Some(value.clone())) - } else { - // Blob exists but key absent — attempt migration from old - // per-key entry. migrate_legacy_key writes the result into - // the blob if found, so subsequent loads hit the cache. - self.migrate_legacy_key(key) - } - } - Ok(None) => { - // No blob yet — attempt one-time migration from old per-key - // DPK entry (macOS) or return Ok(None) (other platforms). - self.migrate_legacy_key(key) - } - Err(e) => Err(e), - } - } - #[cfg(not(feature = "system-keyring"))] - { - let _ = key; - Err("system-keyring feature disabled".to_string()) + match provider_get(self.service.clone(), key.to_string()) { + Ok(secret) => String::from_utf8(secret.value) + .map(Some) + .map_err(|_| "secret provider returned non-UTF-8 data".to_string()), + Err(ProviderFailure::NotFound) => Ok(None), + Err(ProviderFailure::Other) => Err("secret provider unavailable".to_string()), } } - /// Read the secret for `key` without any legacy-migration side effects. - /// - /// Read the entire blob without any legacy-migration side effects. - /// - /// Returns the full key→value map when a blob exists, `Ok(None)` when no - /// blob has been written yet, and `Err` only when the backend is - /// unavailable. Never calls `migrate_legacy_key`. + /// Load every UTF-8 secret in this store's namespace. pub fn load_all_readonly(&self) -> Result>, String> { - #[cfg(feature = "system-keyring")] - { - self.load_blob() + let rows = provider_list(self.service.clone()) + .map_err(|_| "secret provider unavailable".to_string())?; + if rows.is_empty() { + return Ok(None); } - #[cfg(not(feature = "system-keyring"))] - { - Err("system-keyring feature disabled".to_string()) + let mut result = HashMap::with_capacity(rows.len()); + for (account, value) in rows { + let value = String::from_utf8(value) + .map_err(|_| "secret provider returned non-UTF-8 data".to_string())?; + result.insert(account, value); } + Ok(Some(result)) } - /// Insert all entries from `entries` into the blob in a single mutation. - /// - /// Entries that already exist in the blob are overwritten; entries not - /// present in `entries` are left unchanged. If the resulting blob is - /// identical to what is already stored, no keychain write occurs. + /// Store every supplied entry in this store's namespace. pub fn store_all(&self, entries: &HashMap) -> Result<(), String> { - #[cfg(feature = "system-keyring")] - { - self.mutate_blob(|map| { - for (k, v) in entries { - map.insert(k.clone(), v.clone()); - } - }) - } - #[cfg(not(feature = "system-keyring"))] - { - let _ = entries; - Err("system-keyring feature disabled".to_string()) - } - } - - /// On first launch after upgrading from the per-key DPK format, read the - /// old DPK entry for `key`, write it into a new blob, and delete the old - /// item. Returns `Ok(None)` when no old entry exists. - /// - /// Also handles a one-time migration from the DPK blob format written by - /// #1267 (before the dev/release split was fixed). Anyone who ran main - /// while #1267 was present has a DPK blob instead of per-key entries; this - /// reads it, merges all keys into the legacy blob, and deletes the DPK blob. - #[cfg(all(feature = "system-keyring", target_os = "macos"))] - fn migrate_legacy_key(&self, key: &str) -> Result, String> { - // One-time migration: check for a DPK blob (key = BLOB_KEY = "secrets") - // written by #1267 before the dev/release split was fixed. - match generic_password(dpk_opts(&self.service, BLOB_KEY)) { - Ok(bytes) => { - let json = String::from_utf8(bytes).map_err(|e| format!("dpk blob utf8: {e}"))?; - let dpk_map = serde_json::from_str::>(&json) - .map_err(|e| format!("dpk blob json: {e}"))?; - // Merge all keys from the DPK blob into the legacy blob. - self.mutate_blob(|map| { - for (k, v) in &dpk_map { - map.entry(k.clone()).or_insert_with(|| v.clone()); - } - })?; - // Best-effort delete the DPK blob. - let _ = delete_generic_password_options(dpk_opts(&self.service, BLOB_KEY)); - return Ok(dpk_map.get(key).cloned()); - } - Err(ref e) if is_not_found(e) => { - // No DPK blob — fall through to per-key migration. - } - Err(ref e) if is_dpk_unavailable(e) => { - // Unsigned dev build — DPK inaccessible, fall through. - } - Err(e) => return Err(format!("dpk blob read: {e}")), - } - - // Try the old per-key DPK entry. - match generic_password(dpk_opts(&self.service, key)) { - Ok(bytes) => { - let value = String::from_utf8(bytes).map_err(|e| format!("keyring utf8: {e}"))?; - // Write into blob (creates the blob if it doesn't exist). - self.store(key, &value)?; - // Best-effort cleanup of the old per-key entry. - let _ = delete_generic_password_options(dpk_opts(&self.service, key)); - Ok(Some(value)) - } - Err(ref e) if is_not_found(e) => { - // Also check the old keyring-crate entry (pre-#1264 installs). - self.migrate_legacy_key_keyring(key) - } - Err(ref e) if is_dpk_unavailable(e) => { - // Unsigned dev build — check old keyring-crate entry only. - self.migrate_legacy_key_keyring(key) - } - Err(e) => Err(format!("keyring get: {e}")), - } - } - - #[cfg(all(feature = "system-keyring", not(target_os = "macos")))] - fn migrate_legacy_key(&self, key: &str) -> Result, String> { - // Non-macOS: no DPK, just check the old keyring-crate per-key entry. - self.migrate_legacy_key_keyring(key) - } - - /// Check the old per-key `keyring` crate entry (pre-#1264 format) and - /// migrate it into the blob if found. - #[cfg(feature = "system-keyring")] - fn migrate_legacy_key_keyring(&self, key: &str) -> Result, String> { - let entry = keyring_entry(&self.service, key).map_err(|e| format!("keyring entry: {e}"))?; - match entry.get_password() { - Ok(value) => { - self.store(key, &value)?; - let _ = entry.delete_credential(); - Ok(Some(value)) - } - Err(keyring::Error::NoEntry) => Ok(None), - Err(e) => Err(format!("keyring get: {e}")), - } + provider_set_all(self.service.clone(), entries.clone()) + .map_err(|_| "secret provider unavailable".to_string()) } - /// Verify that `key` holds `expected` by reading directly from the OS - /// backend, bypassing the in-process cache. This is the key innovation for - /// read-back verification: it proves the OS keyring round-trip, not just - /// that the in-process cache was updated. - /// - /// Returns `Ok(true)` when the stored value matches `expected`, `Ok(false)` - /// when the entry is absent or holds a different value, and `Err` when the - /// backend is unavailable. + /// Verify a value by reading it back from the provider. pub fn verify_stored_raw(&self, key: &str, expected: &str) -> Result { - #[cfg(feature = "system-keyring")] - { - let raw = self.read_blob_raw()?; - match raw { - None => Ok(false), - Some(bytes) => { - let json = String::from_utf8(bytes).map_err(|e| format!("blob utf8: {e}"))?; - let map = - serde_json::from_str::>(&json) - .map_err(|e| format!("blob json: {e}"))?; - Ok(map.get(key).is_some_and(|v| v == expected)) - } - } - } - #[cfg(not(feature = "system-keyring"))] - { - let _ = (key, expected); - Err("system-keyring feature disabled".to_string()) + match provider_get(self.service.clone(), key.to_string()) { + Ok(secret) => Ok(secret.value == expected.as_bytes()), + Err(ProviderFailure::NotFound) => Ok(false), + Err(ProviderFailure::Other) => Err("secret provider unavailable".to_string()), } } - /// Store `value` for `key`. Reports `Err` on availability failures — callers - /// decide whether to fall back to file storage. + /// Store a UTF-8 value in the provider. pub fn store(&self, key: &str, value: &str) -> Result<(), String> { - #[cfg(feature = "system-keyring")] - { - self.mutate_blob(|map| { - map.insert(key.to_string(), value.to_string()); - }) - } - #[cfg(not(feature = "system-keyring"))] - { - let _ = (key, value); - Err("system-keyring feature disabled".to_string()) - } + provider_set( + self.service.clone(), + key.to_string(), + value.as_bytes().to_vec(), + ) + .map_err(|_| "secret provider unavailable".to_string()) } - /// Delete the entire keychain blob for this service, plus all legacy per-key - /// entries that could resurrect an identity on next boot. + /// Delete every provider item in this store's namespace. /// - /// Order of operations: - /// 1. Read the blob to collect every key name (e.g. `identity`, agent keys). - /// 2. Delete legacy per-key DPK entries for every key + the DPK blob itself. - /// 3. Delete legacy per-key keyring entries for every key. - /// 4. Delete the blob entry. - /// 5. Clear the in-memory cache. - /// - /// This is the correct wipe path for sign-out: the old `delete_all` skipped - /// step 1–3 so stale per-key entries could be re-imported on the next launch - /// via `migrate_legacy_key`. This method prevents that resurrection. + /// Legacy Keychain cleanup is deliberately excluded: reading or deleting + /// those entries from a rebuilt app could itself prompt. The standalone + /// one-time migration tool performs exact legacy cleanup after verifying + /// that the provider holds identical bytes. pub fn delete_all_with_legacy_cleanup(&self) -> Result<(), String> { - #[cfg(feature = "system-keyring")] - { - let _lock = acquire_blob_lock(&self.service)?; - - // Step 1: read current blob keys (best-effort; no entry = empty set). - let blob_keys: Vec = match self.read_blob_raw() { - Ok(Some(bytes)) => { - let json = String::from_utf8(bytes).unwrap_or_default(); - serde_json::from_str::>(&json) - .map(|m| m.into_keys().collect()) - .unwrap_or_default() - } - _ => vec![], - }; - - // Always include "identity" even if the blob is empty or absent — - // it may exist only as a legacy per-key entry. - let mut all_keys = blob_keys; - if !all_keys.contains(&"identity".to_string()) { - all_keys.push("identity".to_string()); - } - - // Steps 2 & 3: delete legacy per-key entries for every key. - for key in &all_keys { - #[cfg(target_os = "macos")] - { - match delete_generic_password_options(dpk_opts(&self.service, key)) { - Ok(()) => {} - Err(ref e) if is_not_found(e) => {} - Err(ref e) if is_dpk_unavailable(e) => {} - Err(e) => return Err(format!("dpk per-key delete {key}: {e}")), - } - } - { - let entry = keyring_entry(&self.service, key) - .map_err(|e| format!("keyring entry constructor {key}: {e}"))?; - match entry.delete_credential() { - Ok(()) | Err(keyring::Error::NoEntry) => {} - Err(e) if is_keyring_availability_error(&e.to_string()) => { - return Err(format!("keyring unavailable deleting {key}: {e}")); - } - Err(e) => { - return Err(format!("keyring per-key delete {key}: {e}")); - } - } - } - } - // Step 2 (cont.): also delete the legacy DPK blob written by #1267. - #[cfg(target_os = "macos")] - { - match delete_generic_password_options(dpk_opts(&self.service, BLOB_KEY)) { - Ok(()) => {} - Err(ref e) if is_not_found(e) => {} - Err(ref e) if is_dpk_unavailable(e) => {} - Err(e) => return Err(format!("dpk blob delete: {e}")), - } - } - - // Step 4: delete the main blob entry. - { - let entry = keyring_entry(&self.service, BLOB_KEY) - .map_err(|e| format!("keyring entry constructor blob: {e}"))?; - match entry.delete_credential() { - Ok(()) | Err(keyring::Error::NoEntry) => {} - Err(e) if is_keyring_availability_error(&e.to_string()) => { - return Err(format!("keyring unavailable: {e}")); - } - Err(e) => { - return Err(format!("keyring blob delete: {e}")); - } - } - } - - // Step 5: clear the in-memory cache. - let mut guard = self.cache.lock().unwrap_or_else(|e| e.into_inner()); - *guard = None; - Ok(()) - } - #[cfg(not(feature = "system-keyring"))] - { - Ok(()) // No-op: no keyring, nothing to delete. - } + provider_delete_all(self.service.clone()) + .map_err(|_| "secret provider unavailable".to_string()) } - /// Verify no identity-bearing keychain entry survives in any shape - /// that `load("identity")` → `migrate_legacy_key` can consume: - /// main blob, DPK blob (`BLOB_KEY`), and per-key `"identity"`. - /// - /// Returns `true` when all three shapes are absent (or inaccessible in an - /// expected way), `false` when any entry is found or the keychain is - /// unavailable (fail-closed). + /// Verify that this namespace contains no provider items. pub fn verify_fully_wiped(&self) -> bool { - #[cfg(feature = "system-keyring")] - { - // 1. Main blob must be absent. - match self.read_blob_raw() { - Ok(None) => {} - Ok(Some(_)) => return false, - Err(_) => return false, - } - // 2. Per-key "identity" via legacy keyring must be absent. - match keyring_entry(&self.service, "identity") { - Ok(entry) => match entry.get_password() { - Err(keyring::Error::NoEntry) => {} - Ok(_) => return false, - // Any other error (availability, unknown, transient) → fail closed. - // Only explicit NoEntry is proof of absence. - Err(_) => return false, - }, - // Constructor failure → cannot verify → fail closed. - Err(_) => return false, - } - // 3. DPK blob (macOS only). - #[cfg(target_os = "macos")] - { - match generic_password(dpk_opts(&self.service, BLOB_KEY)) { - Err(ref e) if is_not_found(e) => {} - // dpk-unavailable is symmetric with load(): if load() can't - // consume DPK in this state, a surviving entry is harmless. - Err(ref e) if is_dpk_unavailable(e) => {} - Ok(_) => return false, - // Any other error → fail closed (not proof of absence). - Err(_) => return false, - } - // 4. Per-key DPK "identity" (macOS only). - match generic_password(dpk_opts(&self.service, "identity")) { - Err(ref e) if is_not_found(e) => {} - // dpk-unavailable: symmetric with load() — if load() can't - // read DPK, a surviving entry can't resurrect identity. - Err(ref e) if is_dpk_unavailable(e) => {} - Ok(_) => return false, - // Any other error → fail closed. - Err(_) => return false, - } - } - true - } - #[cfg(not(feature = "system-keyring"))] - { - true // No keyring = nothing to verify. - } + provider_metadata() + .map(|items| items.iter().all(|item| item.service != self.service)) + .unwrap_or(false) } - /// Delete the secret for `key`. A missing entry is not an error. + /// Delete one item. A missing item is not an error. pub fn delete(&self, key: &str) -> Result<(), String> { - #[cfg(feature = "system-keyring")] - { - self.mutate_blob(|map| { - map.remove(key); - })?; - // Best-effort: also delete any old per-key entry for this key to - // prevent resurrection on the next probe/load (migration path). - #[cfg(target_os = "macos")] - let _ = delete_generic_password_options(dpk_opts(&self.service, key)); - if let Ok(entry) = keyring_entry(&self.service, key) { - let _ = entry.delete_credential(); - } - Ok(()) - } - #[cfg(not(feature = "system-keyring"))] - { - let _ = key; - Err("system-keyring feature disabled".to_string()) - } + provider_delete(self.service.clone(), key.to_string()) + .map_err(|_| "secret provider unavailable".to_string()) } } -#[cfg(all(test, feature = "system-keyring"))] -mod tests { - use super::*; - - // Test-only constructor: pre-seed the cache without touching the OS keychain. - impl SecretStore { - fn with_cache(service: &str, cache: Option>) -> Self { - SecretStore { - service: service.to_string(), - cache: Mutex::new(cache), - } - } - } - - #[test] - fn probe_returns_present_when_key_in_cache() { - let mut map = HashMap::new(); - map.insert("identity".to_string(), "nsec1test".to_string()); - let store = SecretStore::with_cache("buzz-test-cache-hit", Some(map)); - // Cache is warm and contains "identity" — probe must return Present - // without touching the keychain. - assert_eq!(store.probe("identity"), KeyringProbe::Present); - } - - #[test] - fn load_returns_value_when_key_in_cache() { - let mut map = HashMap::new(); - map.insert("identity".to_string(), "nsec1test".to_string()); - let store = SecretStore::with_cache("buzz-test-load-cache-hit", Some(map)); - // Cache is warm and contains "identity" — load must return the value - // without touching the keychain. - assert_eq!( - store.load("identity").unwrap(), - Some("nsec1test".to_string()) - ); - } - - // ── Cross-process race tests (require real OS keychain) ──────────────── - - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn test_stale_warm_cache_add_observes_prior_write() { - // Simulates the cross-process race that stranded Will's agent keys. - // - // Setup: two SecretStore instances for the same service (= two - // "processes" with separate caches). Process A warms its cache to - // {k1}. Process B then writes {k1, k2}. Without the fix, A's next - // mutate_blob would build from its stale {k1} cache and write - // {k1, k3}, silently dropping k2. With the fix, A always re-reads - // from the keychain inside the lock, so the result is {k1, k2, k3}. - let svc = "buzz-test-race-stale-cache"; - - // Clean state. - let setup = SecretStore::keyring(svc); - let _ = setup.delete("k1"); - let _ = setup.delete("k2"); - let _ = setup.delete("k3"); - - // Process A: write k1, warming its cache. - let store_a = SecretStore::keyring(svc); - store_a.store("k1", "v1").unwrap(); - - // Process B: write k2 (separate instance = separate cache). - let store_b = SecretStore::keyring(svc); - store_b.store("k2", "v2").unwrap(); - - // Process A: write k3. With the fix, A re-reads inside the lock and - // sees {k1, k2} before appending k3 — result must be {k1, k2, k3}. - store_a.store("k3", "v3").unwrap(); - - // Verify via a third reader (clean cache). - let reader = SecretStore::keyring(svc); - assert_eq!( - reader.load("k1").unwrap(), - Some("v1".to_string()), - "k1 must survive" - ); - assert_eq!( - reader.load("k2").unwrap(), - Some("v2".to_string()), - "k2 must not be dropped" - ); - assert_eq!( - reader.load("k3").unwrap(), - Some("v3".to_string()), - "k3 must be written" - ); +#[derive(Clone, Copy)] +enum ProviderFailure { + NotFound, + Other, +} - // Cleanup. - let _ = reader.delete("k1"); - let _ = reader.delete("k2"); - let _ = reader.delete("k3"); +fn classify_error(error: daz_secrets::Error) -> ProviderFailure { + if error.code() == ErrorCode::NotFound { + ProviderFailure::NotFound + } else { + ProviderFailure::Other } +} - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn test_concurrent_adds_neither_key_dropped() { - // Two sequential stores from distinct instances (simulating two - // processes each adding one key) must both be durably visible. - let svc = "buzz-test-race-concurrent-add"; - - let setup = SecretStore::keyring(svc); - let _ = setup.delete("agent_a"); - let _ = setup.delete("agent_b"); - - let store1 = SecretStore::keyring(svc); - store1.store("agent_a", "nsec1aaa").unwrap(); +fn provider_get(service: String, account: String) -> Result { + BlockingClient::from_default_config() + .map_err(classify_error)? + .get(&service, &account) + .map_err(classify_error) +} - let store2 = SecretStore::keyring(svc); - store2.store("agent_b", "nsec1bbb").unwrap(); +fn provider_set(service: String, account: String, value: Vec) -> Result<(), ProviderFailure> { + BlockingClient::from_default_config() + .map_err(classify_error)? + .set(&service, &account, &value, None) + .map(|_| ()) + .map_err(classify_error) +} - let reader = SecretStore::keyring(svc); - assert_eq!( - reader.load("agent_a").unwrap(), - Some("nsec1aaa".to_string()), - "agent_a must not be dropped" - ); - assert_eq!( - reader.load("agent_b").unwrap(), - Some("nsec1bbb".to_string()), - "agent_b must not be dropped" - ); +fn provider_metadata() -> Result, ProviderFailure> { + BlockingClient::from_default_config() + .map_err(classify_error)? + .list_metadata() + .map_err(classify_error) +} - // Cleanup. - let _ = reader.delete("agent_a"); - let _ = reader.delete("agent_b"); - } +fn provider_list(service: String) -> Result)>, ProviderFailure> { + let client = BlockingClient::from_default_config().map_err(classify_error)?; + let metadata = client.list_metadata().map_err(classify_error)?; + let mut rows = Vec::new(); + for item in metadata.into_iter().filter(|item| item.service == service) { + let secret = client + .get(&item.service, &item.account) + .map_err(classify_error)?; + rows.push((item.account, secret.value)); + } + Ok(rows) +} - #[test] - fn test_blob_lockfile_path_is_in_tmp_with_uid() { - // The lockfile must be at a deterministic per-user path under /tmp — - // invariant to $TMPDIR — so both a GUI-launched DMG (env-stripped by - // launchd) and a terminal-launched dev build resolve the same inode and - // achieve mutual exclusion. - let path = blob_lockfile_path("buzz-desktop"); - #[cfg(unix)] - { - let uid = unsafe { libc::getuid() }; - assert!( - path.starts_with("/tmp"), - "lockfile {path:?} must start with /tmp (not $TMPDIR)" - ); - let name = path - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or_default(); - assert!( - name.contains(&uid.to_string()), - "lockfile {path:?} must contain uid {uid}" - ); - assert!( - name.contains("buzz-keychain"), - "lockfile name must contain 'buzz-keychain'" - ); - } - #[cfg(not(unix))] - { - assert!( - path.file_name() - .and_then(|n| n.to_str()) - .is_some_and(|n| n.contains("buzz-keychain")), - "lockfile name must contain 'buzz-keychain'" - ); - } - } +fn provider_set_all( + service: String, + entries: HashMap, +) -> Result<(), ProviderFailure> { + let client = BlockingClient::from_default_config().map_err(classify_error)?; + for (account, value) in entries { + client + .set(&service, &account, value.as_bytes(), None) + .map_err(classify_error)?; + } + Ok(()) +} - #[test] - fn test_blob_lock_acquire_and_release() { - // Verify the advisory lock can be acquired and released without errors. - // This exercises the real flock/mutex path on the current platform. - let guard = acquire_blob_lock("buzz-test-lock-smoke"); - assert!( - guard.is_ok(), - "advisory lock acquire must succeed: {:?}", - guard.err() - ); - // Drop the guard — lock is released. A second acquire must succeed. - drop(guard); - let guard2 = acquire_blob_lock("buzz-test-lock-smoke"); - assert!( - guard2.is_ok(), - "advisory lock re-acquire after release must succeed: {:?}", - guard2.err() - ); +fn provider_delete(service: String, account: String) -> Result<(), ProviderFailure> { + let client = BlockingClient::from_default_config().map_err(classify_error)?; + match client.delete(&service, &account, None) { + Ok(()) => Ok(()), + Err(error) if error.code() == ErrorCode::NotFound => Ok(()), + Err(error) => Err(classify_error(error)), } +} - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn mutate_blob_does_not_advance_cache_on_write_failure() { - // Copy-on-write safety: if `write_blob_raw` fails (denied prompt, - // transient outage, ACL rejection), the cache must stay at the last - // known durable state. A subsequent `store()` for the same key/value - // must NOT be skipped as a no-op — the equality check must compare - // against the durable cache, not an unpersisted candidate. - // - // This is a real-keychain integration test. Run locally with: - // cargo test -p buzz-desktop -- --ignored mutate_blob_does_not_advance - // - // On a machine with a reachable keychain the `store()` call succeeds - // (result.is_ok()) and the write-failure branch is skipped — the test - // still passes. On a machine where the write is denied (e.g., user - // clicks Deny in the macOS prompt) result.is_err() and the assertions - // below verify the cache invariant. We verify that after an error: - // 1. The cache is not advanced (the previously cached key is intact). - // 2. The failed key is not present (the dirty candidate was discarded). - let mut map = HashMap::new(); - map.insert("existing".to_string(), "durable_val".to_string()); - let store = SecretStore::with_cache("buzz-test-cow-write-fail", Some(map)); - - // Attempt to add a new key — this calls write_blob_raw against the - // real keychain; with copy-on-write the cache must remain at {existing} - // if the write fails. - let result = store.store("new_key", "new_val"); - - if result.is_err() { - // Write failed (e.g., user denied the keychain prompt): confirm - // cache was not advanced — the existing key is still intact and - // the new key was never committed to the in-memory state. - assert_eq!( - store.load("existing").unwrap(), - Some("durable_val".to_string()), - "cache must remain at last durable state after write failure" - ); - // load("new_key") goes through the unchanged cache (no entry), - // then attempts migrate_legacy_key which also fails on a denied - // keychain, returning either Ok(None) or Err — either is correct - // since the key was never durably stored. - let after = store.load("new_key"); - assert!( - matches!(after, Ok(None) | Err(_)), - "a key whose write failed must not be visible via load: {after:?}" - ); +fn provider_delete_all(service: String) -> Result<(), ProviderFailure> { + let client = BlockingClient::from_default_config().map_err(classify_error)?; + let metadata = client.list_metadata().map_err(classify_error)?; + for item in metadata.into_iter().filter(|item| item.service == service) { + match client.delete(&item.service, &item.account, None) { + Ok(()) => {} + Err(error) if error.code() == ErrorCode::NotFound => {} + Err(error) => return Err(classify_error(error)), } - // If result.is_ok() the write succeeded — the cache-integrity invariant - // does not apply to the success path; no assertion needed here. - } - - #[test] - fn availability_error_discriminator() { - assert!(is_keyring_availability_error("dbus connection failed")); - assert!(is_keyring_availability_error( - "org.freedesktop.secrets not provided" - )); - assert!(is_keyring_availability_error("No Secret Service")); - assert!(is_keyring_availability_error( - "Platform secure storage failure" - )); - // A plain "not found" is per-entry, not an availability failure. - assert!(!is_keyring_availability_error("entry not found")); - } - - #[cfg(target_os = "macos")] - #[test] - fn dpk_error_discriminators() { - // errSecMissingEntitlement = -34018 signals unsigned dev build. - let e = SFError::from_code(-34018); - assert!(is_dpk_unavailable(&e)); - assert!(!is_not_found(&e)); - // errSecItemNotFound = -25300 is not a DPK-unavailable error. - let e = SFError::from_code(-25300); - assert!(is_not_found(&e)); - assert!(!is_dpk_unavailable(&e)); - } - - // Integration tests that exercise the real OS keychain. Skipped in CI - // (unsigned builds lack keychain entitlements); run locally with: - // cargo test -p buzz-desktop -- --ignored blob_ - // - // Each test uses a unique service name to avoid cross-test pollution. - - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn blob_stores_and_retrieves_multiple_keys() { - let store = SecretStore::keyring("buzz-test-blob-multi"); - store.store("key_a", "val_a").unwrap(); - store.store("key_b", "val_b").unwrap(); - assert_eq!(store.load("key_a").unwrap(), Some("val_a".to_string())); - assert_eq!(store.load("key_b").unwrap(), Some("val_b".to_string())); - assert_eq!(store.load("key_c").unwrap(), None); - // Cleanup. - let _ = store.delete("key_a"); - let _ = store.delete("key_b"); - } - - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn blob_probe_present_absent_unreachable() { - let store = SecretStore::keyring("buzz-test-blob-probe"); - // No blob yet — key absent, backend reachable. - assert_eq!(store.probe("identity"), KeyringProbe::ReachableButEmpty); - store.store("identity", "nsec1test").unwrap(); - // Key now present. - assert_eq!(store.probe("identity"), KeyringProbe::Present); - // Different key — blob exists but key absent. - assert_eq!(store.probe("other"), KeyringProbe::ReachableButEmpty); - // Cleanup. - let _ = store.delete("identity"); - } - - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn blob_delete_removes_key_not_others() { - let store = SecretStore::keyring("buzz-test-blob-delete"); - store.store("keep", "keep_val").unwrap(); - store.store("remove", "remove_val").unwrap(); - store.delete("remove").unwrap(); - assert_eq!(store.load("keep").unwrap(), Some("keep_val".to_string())); - assert_eq!(store.load("remove").unwrap(), None); - // Cleanup. - let _ = store.delete("keep"); - } - - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn blob_migration_from_per_key_entry() { - let svc = "buzz-test-blob-migration"; - let key = "identity"; - let value = "nsec1migrationtest"; - - // Seed a per-key entry (old format) — no blob exists. - let entry = keyring_entry(svc, key).unwrap(); - entry.set_password(value).unwrap(); - - // Fresh store — no blob in the keychain yet. - let store = SecretStore::keyring(svc); - - // probe should find the legacy key. - assert_eq!(store.probe(key), KeyringProbe::Present); - - // load should migrate it into the blob and return the value. - assert_eq!(store.load(key).unwrap(), Some(value.to_string())); - - // Old per-key entry should be cleaned up. - let entry = keyring_entry(svc, key).unwrap(); - assert!(matches!(entry.get_password(), Err(keyring::Error::NoEntry))); - - // Key is now in the blob — probe confirms. - let store2 = SecretStore::keyring(svc); - assert_eq!(store2.probe(key), KeyringProbe::Present); - assert_eq!(store2.load(key).unwrap(), Some(value.to_string())); - - // Cleanup. - let _ = store2.delete(key); - } - - #[ignore = "requires real OS keychain (run locally)"] - #[test] - fn delete_all_with_legacy_cleanup_removes_per_key_identity() { - let svc = "buzz-test-delete-all-legacy"; - let key = "identity"; - let value = "nsec1legacytest"; - - // Seed a legacy per-key entry (old format, pre-blob migration). - let entry = keyring_entry(svc, key).unwrap(); - entry.set_password(value).unwrap(); - - // Also seed a blob with a different key to exercise the full path. - let store = SecretStore::keyring(svc); - store.store("agent:abc123", "nsec1agent").unwrap(); - - // Legacy per-key identity should be discoverable via probe. - let store2 = SecretStore::keyring(svc); - assert_eq!(store2.probe(key), KeyringProbe::Present); - - // Wipe everything via the sign-out path. - store2.delete_all_with_legacy_cleanup().unwrap(); - - // Fresh store — neither the blob nor the per-key entry should remain. - let store3 = SecretStore::keyring(svc); - assert_eq!( - store3.probe(key), - KeyringProbe::ReachableButEmpty, - "per-key identity must not survive delete_all_with_legacy_cleanup" - ); - assert_eq!( - store3.load(key).unwrap(), - None, - "load must not resurrect the legacy per-key identity" - ); - // Agent key should also be gone. - assert_eq!(store3.load("agent:abc123").unwrap(), None); } + Ok(()) } diff --git a/desktop/src/app/AppShellOverlays.tsx b/desktop/src/app/AppShellOverlays.tsx index 9a856ba6b0..38d3f99c5e 100644 --- a/desktop/src/app/AppShellOverlays.tsx +++ b/desktop/src/app/AppShellOverlays.tsx @@ -1,6 +1,7 @@ export { TerminalBootstrap } from "@/features/terminal/TerminalBootstrap"; import * as React from "react"; +import { ChannelManagementSheet } from "@/features/channels/ui/ChannelManagementSheet"; import type { Channel } from "@/shared/api/types"; import type { CreateChannelInput } from "@/features/sidebar/lib/useCreateChannelForm"; import { useDeferredModalOpen } from "@/shared/ui/deferredModalOpen"; @@ -10,11 +11,6 @@ const ChannelBrowserDialog = React.lazy(async () => { return { default: module.ChannelBrowserDialog }; }); -const ChannelManagementSheet = React.lazy(async () => { - const module = await import("@/features/channels/ui/ChannelManagementSheet"); - return { default: module.ChannelManagementSheet }; -}); - export type BrowseDialogType = "stream" | "forum" | null; type AppShellOverlaysProps = { diff --git a/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs b/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs index fbaf1f5274..f3727598c0 100644 --- a/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs +++ b/desktop/src/features/agents/lib/personaCatalogRelay.test.mjs @@ -356,7 +356,7 @@ test("test_foreign_entry_with_no_local_copy_stays_unselected", () => { BOB, ); - assert.equal(personas[0].id, "catalog:" + ALICE + ":reviewer"); + assert.equal(personas[0].id, `catalog:${ALICE}:reviewer`); assert.equal(personas[0].isActive, false); }); @@ -377,7 +377,7 @@ test("test_catalog_source_match_is_scoped_to_the_publishing_owner", () => { ALICE, ); - assert.equal(personas[0].id, "catalog:" + BOB + ":reviewer"); + assert.equal(personas[0].id, `catalog:${BOB}:reviewer`); assert.equal(personas[0].isActive, false); }); diff --git a/desktop/src/features/onboarding/ui/BackupStep.tsx b/desktop/src/features/onboarding/ui/BackupStep.tsx index 99d9c6324d..7845e09762 100644 --- a/desktop/src/features/onboarding/ui/BackupStep.tsx +++ b/desktop/src/features/onboarding/ui/BackupStep.tsx @@ -162,21 +162,21 @@ export function BackupStep({ ); const storageDescription = identityStorage === "system-keyring" - ? "Buzz keeps your identity key in your system keychain. Your computer may ask for your password when Buzz needs to read the key." + ? "Buzz keeps your identity key in the configured machine-local secret provider. Buzz never asks the operating-system keychain to unlock it." : identityStorage === "local-file" - ? "Your system keychain wasn’t available, so Buzz keeps your identity key in a private file on this device." + ? "This legacy installation stores the identity in a private device file. Re-import it to migrate into the local secret provider." : "Buzz keeps your identity key protected on this device. Make a separate backup in case you lose access."; const storageTitle = identityStorage === "system-keyring" - ? "Protected by your system keychain" + ? "Protected by the local secret provider" : identityStorage === "local-file" ? "Stored in private device storage" : "Protected in private device storage"; const introStorageDescription = identityStorage === "system-keyring" - ? "Buzz keeps your identity key in your system keychain." + ? "Buzz keeps your identity key in the configured local secret provider." : identityStorage === "local-file" - ? "Buzz keeps your identity key in a private file on this device because the system keychain wasn’t available." + ? "This legacy installation keeps its identity key in a private device file until it is migrated." : "Your identity key is protected on this device."; if (optionsExpanded) { diff --git a/desktop/src/features/onboarding/ui/KeyringLockedScreen.tsx b/desktop/src/features/onboarding/ui/KeyringLockedScreen.tsx index a6a02f38c0..f0328a4e0c 100644 --- a/desktop/src/features/onboarding/ui/KeyringLockedScreen.tsx +++ b/desktop/src/features/onboarding/ui/KeyringLockedScreen.tsx @@ -14,7 +14,7 @@ export function KeyringLockedScreen() { const handleReimportClick = React.useCallback(() => { const confirmed = window.confirm( - "Importing a different nsec replaces the identity currently locked in the keyring for this install. The previous identity will no longer be accessible. Continue?", + "Importing a different nsec replaces the identity currently held by the local secret provider for this install. The previous identity will no longer be accessible. Continue?", ); if (confirmed) { setShowImport(true); @@ -41,12 +41,12 @@ export function KeyringLockedScreen() {

- Unlock your system keyring + Secret provider unavailable

- Your identity is safe in the OS keyring, but it's unreachable this - session. Unlock your keyring or sign into your desktop session, then - relaunch Buzz. + Buzz could not reach the machine-local secret provider. Your identity + was not replaced or copied to a file. Relaunch Buzz after the provider + is restored, or re-import your key to replace it deliberately.

{showImport ? ( diff --git a/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx b/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx index 693d1af058..94d0ad52a7 100644 --- a/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx @@ -284,7 +284,7 @@ export function MachineOnboardingFlow({ {keyImportStage === "backup-password" ? "Enter your backup password to unlock your key and restore your identity." : identityLost - ? "Your identity is no longer in the system keyring. Re-import your nsec to restore it." + ? "Your identity is no longer in the local secret provider. Re-import your nsec to restore it." : "If you already have a Buzz account, enter your private key below to get started."}

diff --git a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx index a3653f750f..e1fa892460 100644 --- a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx @@ -532,7 +532,7 @@ export function OnboardingFlow({ Re-import your key

- Your identity is no longer in the system keyring. + Your identity is no longer in the local secret provider. Re-import your nsec to restore it — Buzz will restart to finish recovery. Or go back to start a new identity with a fresh key. diff --git a/desktop/src/features/terminal/TerminalSubstrate.tsx b/desktop/src/features/terminal/TerminalSubstrate.tsx index 81ac91528a..8d5af8ac54 100644 --- a/desktop/src/features/terminal/TerminalSubstrate.tsx +++ b/desktop/src/features/terminal/TerminalSubstrate.tsx @@ -477,7 +477,7 @@ export function TerminalSubstrate({ data-terminal-visible={visible ? "true" : "false"} style={{ ...terminalStyle, - ...(mode === "docked" ? { height: dockHeight } : undefined), + ...(mode === "docked" && visible ? { height: dockHeight } : undefined), }} onWheel={(event) => { event.preventDefault(); diff --git a/desktop/src/shared/styles/globals/terminal.css b/desktop/src/shared/styles/globals/terminal.css index 26b5f42ba8..47a5a88925 100644 --- a/desktop/src/shared/styles/globals/terminal.css +++ b/desktop/src/shared/styles/globals/terminal.css @@ -248,7 +248,7 @@ } .buzz-terminal-substrate[data-terminal-visible="false"] { - height: 0 !important; + height: 0; min-height: 0; pointer-events: none; transform: translateY(16px); diff --git a/desktop/test-loader-hooks.mjs b/desktop/test-loader-hooks.mjs index 0cc99158ac..69b23cb0a0 100644 --- a/desktop/test-loader-hooks.mjs +++ b/desktop/test-loader-hooks.mjs @@ -113,18 +113,24 @@ export function resolve(specifier, context, nextResolve) { context.parentURL?.startsWith("file:") ) { const parentPath = fileURLToPath(context.parentURL); - const resolved = resolveSourcePath( - path.resolve(path.dirname(parentPath), specifier), - ); - if (resolved) { - return nextResolve(toFileSpecifier(resolved), context); + // Synchronous hooks also participate in CommonJS resolution. Restrict the + // bundler-style extension lookup to Buzz source files so a dependency's + // `require("./cjs/foo.js")` remains a native CommonJS path rather than + // being rewritten into an ESM file URL. + if (parentPath.startsWith(`${srcRoot}${path.sep}`)) { + const resolved = resolveSourcePath( + path.resolve(path.dirname(parentPath), specifier), + ); + if (resolved) { + return nextResolve(toFileSpecifier(resolved), context); + } } return nextResolve(specifier, context); } return nextResolve(specifier, context); } -export async function load(url, context, nextLoad) { +export function load(url, context, nextLoad) { if (url.startsWith(ASSET_URL_PREFIX)) { return { format: "module", diff --git a/desktop/test-loader.mjs b/desktop/test-loader.mjs index 0d846d8626..44e3d9cff4 100644 --- a/desktop/test-loader.mjs +++ b/desktop/test-loader.mjs @@ -1,3 +1,4 @@ -import { register } from "node:module"; +import { registerHooks } from "node:module"; +import { load, resolve } from "./test-loader-hooks.mjs"; -register("./test-loader-hooks.mjs", import.meta.url); +registerHooks({ load, resolve }); diff --git a/mobile/lib/shared/emoji/emoji_only.dart b/mobile/lib/shared/emoji/emoji_only.dart index e6994f0b9b..8a078434fb 100644 --- a/mobile/lib/shared/emoji/emoji_only.dart +++ b/mobile/lib/shared/emoji/emoji_only.dart @@ -21,13 +21,126 @@ const double kEmojiOnlyHeight = 1.25; /// at `1.45em` of the surrounding text. const double kEmojiOnlyCustomEmojiSize = kEmojiOnlyFontSize * 1.45; -/// Anything with `Extended_Pictographic` in it is emoji enough. Keycaps and -/// digit-based sequences don't match — those are covered by the dataset's own -/// native set instead, exactly as desktop does it. -final RegExp _pictographic = RegExp( - r'\p{Extended_Pictographic}', - unicode: true, -); +/// Whether a scalar is in Unicode's `Extended_Pictographic` property. +/// +/// Dart regular expressions do not support Unicode property escapes. Keep the +/// compact BMP ranges here and cover the contiguous supplementary emoji +/// blocks; keycaps deliberately remain dataset-only, matching desktop. +bool _isExtendedPictographic(int value) { + if (value >= 0x1F000 && value <= 0x1FAFF) return true; + + const singletons = { + 0x00A9, + 0x00AE, + 0x203C, + 0x2049, + 0x2122, + 0x2139, + 0x2328, + 0x2388, + 0x23CF, + 0x24C2, + 0x25B6, + 0x25C0, + 0x260E, + 0x2611, + 0x2618, + 0x261D, + 0x2620, + 0x2626, + 0x262A, + 0x262E, + 0x262F, + 0x2638, + 0x2640, + 0x2642, + 0x2660, + 0x2663, + 0x2665, + 0x2666, + 0x2668, + 0x267B, + 0x2699, + 0x269B, + 0x269C, + 0x26A0, + 0x26A1, + 0x26A7, + 0x26C8, + 0x26D1, + 0x26D3, + 0x26D4, + 0x26E9, + 0x26EA, + 0x26F0, + 0x26F1, + 0x26F4, + 0x26F5, + 0x26FD, + 0x2702, + 0x2705, + 0x270F, + 0x2712, + 0x2714, + 0x2716, + 0x271D, + 0x2721, + 0x2728, + 0x2744, + 0x2747, + 0x274C, + 0x274E, + 0x2757, + 0x2763, + 0x2764, + 0x27A1, + 0x27B0, + 0x27BF, + 0x2B50, + 0x2B55, + 0x3030, + 0x303D, + 0x3297, + 0x3299, + }; + if (singletons.contains(value)) return true; + + const ranges = [ + (0x2194, 0x2199), + (0x21A9, 0x21AA), + (0x231A, 0x231B), + (0x23E9, 0x23F3), + (0x23F8, 0x23FA), + (0x25AA, 0x25AB), + (0x25FB, 0x25FE), + (0x2600, 0x2604), + (0x2614, 0x2615), + (0x2622, 0x2623), + (0x2639, 0x263A), + (0x2648, 0x2653), + (0x265F, 0x2660), + (0x267E, 0x267F), + (0x2692, 0x2697), + (0x26AA, 0x26AB), + (0x26B0, 0x26B1), + (0x26BD, 0x26BE), + (0x26C4, 0x26C5), + (0x26CE, 0x26CF), + (0x26F2, 0x26F3), + (0x26F7, 0x26FA), + (0x2708, 0x270D), + (0x2733, 0x2734), + (0x2753, 0x2755), + (0x2795, 0x2797), + (0x2934, 0x2935), + (0x2B05, 0x2B07), + (0x2B1B, 0x2B1C), + ]; + return ranges.any((range) => value >= range.$1 && value <= range.$2); +} + +bool _containsExtendedPictographic(String cluster) => + cluster.runes.any(_isExtendedPictographic); /// Whether [content] is nothing but emoji — native glyphs, known custom /// `:shortcode:`s, and whitespace, with at least one emoji present. @@ -76,7 +189,8 @@ bool isEmojiOnlyMessage( continue; } - if (!nativeEmoji.contains(cluster) && !_pictographic.hasMatch(cluster)) { + if (!nativeEmoji.contains(cluster) && + !_containsExtendedPictographic(cluster)) { return false; } sawEmoji = true; diff --git a/scripts/_goose-env.sh b/scripts/_goose-env.sh index 844aa33c8b..d5fc1c9341 100755 --- a/scripts/_goose-env.sh +++ b/scripts/_goose-env.sh @@ -1,25 +1,26 @@ #!/usr/bin/env bash # Sourced by the goose and goose-bg just recipes to build shared agent env_args. -# Usage: source scripts/_goose-env.sh -# Sets: env_args (bash array), ready for: exec env "${env_args[@]}" +# Usage: source scripts/_goose-env.sh +# Sets: env_args and acp_args arrays. set -euo pipefail _relay="$1" -_key="$2" -_agents="$3" -_heartbeat="$4" -_prompt="${5:-}" +_service="$2" +_account="$3" +_agents="$4" +_heartbeat="$5" +_prompt="${6:-}" cargo build --release -p buzz-acp -p buzz-cli env_args=( BUZZ_RELAY_URL="$_relay" - BUZZ_PRIVATE_KEY="$_key" BUZZ_ACP_AGENT_COMMAND=goose BUZZ_ACP_AGENT_ARGS=acp BUZZ_ACP_AGENTS="$_agents" GOOSE_MODE=auto ) +acp_args=(--secret-service "$_service" --secret-account "$_account") [[ -n "$_prompt" ]] && env_args+=(BUZZ_ACP_SYSTEM_PROMPT="$_prompt") if [[ "$_heartbeat" != "0" ]]; then env_args+=(BUZZ_ACP_HEARTBEAT_INTERVAL="$_heartbeat") diff --git a/scripts/instance-env.sh b/scripts/instance-env.sh index bc185d98f1..178aac8d7f 100755 --- a/scripts/instance-env.sh +++ b/scripts/instance-env.sh @@ -5,7 +5,6 @@ # BUZZ_RELAY_PORT, BUZZ_RELAY_URL # BUZZ_INSTANCE_SLUG, BUZZ_WORKTREE_LABEL, VITE_DEV_BRANCH (worktrees only) # BUZZ_TAURI_CONFIG -# BUZZ_PRIVATE_KEY (worktrees only, when BUZZ_SHARE_IDENTITY=1) WORKTREE_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) @@ -42,43 +41,9 @@ if git rev-parse --is-inside-work-tree &>/dev/null; then export BUZZ_WORKTREE_LABEL="${BRANCH_NAME##*/}" export BUZZ_INSTANCE_SLUG=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//') - # BUZZ_SHARE_IDENTITY=1: reuse the main dev checkout's Nostr key so - # worktrees skip onboarding and share the same identity. The per-worktree - # identifier is kept so concurrent instances don't collide on - # tauri-plugin-single-instance or the app data directory. - if [[ "${BUZZ_SHARE_IDENTITY:-0}" == "1" ]]; then - KEYRING_SERVICE="buzz-desktop-dev" - KEYRING_BLOB="" - case "$(uname -s)" in - Darwin) - if command -v security &>/dev/null; then - KEYRING_BLOB="$(security find-generic-password -s "$KEYRING_SERVICE" -a secrets -w 2>/dev/null || true)" - fi - ;; - Linux) - if command -v secret-tool &>/dev/null; then - KEYRING_BLOB="$(secret-tool lookup service "$KEYRING_SERVICE" username secrets target default 2>/dev/null || true)" - fi - ;; - esac - - KEYRING_IDENTITY="$(printf '%s' "$KEYRING_BLOB" | python3 -c 'import json, sys; value = json.load(sys.stdin).get("identity", ""); print(value if isinstance(value, str) else "")' 2>/dev/null || true)" - CANONICAL_KEY="$HOME/Library/Application Support/xyz.block.buzz.app.dev/identity.key" - LEGACY_CANONICAL_KEY="$HOME/Library/Application Support/xyz.block.sprout.app.dev/identity.key" - - SHARED_IDENTITY="$KEYRING_IDENTITY" - if [[ -z "$SHARED_IDENTITY" && -f "$CANONICAL_KEY" ]]; then - SHARED_IDENTITY="$(cat "$CANONICAL_KEY")" - elif [[ -z "$SHARED_IDENTITY" && -f "$LEGACY_CANONICAL_KEY" ]]; then - SHARED_IDENTITY="$(cat "$LEGACY_CANONICAL_KEY")" - fi - - if [[ -n "$SHARED_IDENTITY" ]]; then - export BUZZ_PRIVATE_KEY="$SHARED_IDENTITY" - else - echo "⚠ BUZZ_SHARE_IDENTITY=1 but no identity found in keyring service $KEYRING_SERVICE, at $CANONICAL_KEY, or at $LEGACY_CANONICAL_KEY — run Buzz from repo root first" >&2 - fi - fi + # Worktrees use the same noninteractive secret-provider namespace as + # the main dev checkout. Secret material is never copied into the + # process environment or read from a platform keyring here. ICON_DIR="$WORKTREE_ROOT/desktop/src-tauri/target/dev-icons" mkdir -p "$ICON_DIR" diff --git a/scripts/reset-desktop-dev-state.sh b/scripts/reset-desktop-dev-state.sh index 7677d37ae6..f7b8527d59 100755 --- a/scripts/reset-desktop-dev-state.sh +++ b/scripts/reset-desktop-dev-state.sh @@ -14,6 +14,22 @@ remove_path() { fi } +delete_secret_namespace() { + local service="$1" + local cli + cli="$(command -v daz-secrets || true)" + if [[ -z "$cli" ]]; then + log "daz-secrets is required to remove the development secret namespace" + exit 1 + fi + python3 -c 'import json, subprocess, sys +cli, service = sys.argv[1:] +items = json.loads(subprocess.check_output([cli, "list"], text=True)) +for item in items: + if item["service"] == service: + subprocess.run([cli, "delete", service, item["account"]], check=True)' "$cli" "$service" +} + remove_bundle_state() { local base="$1" local suffix="${2:-}" @@ -41,12 +57,8 @@ case "$(uname -s)" in remove_bundle_state "$HOME/Library/Saved Application State" ".savedState" remove_bundle_state "$HOME/Library/Preferences" ".plist" - # SecretStore keeps all dev identity and agent keys in this dev-only item. - # Delete every matching item in case an older build used multiple accounts. - if command -v security >/dev/null 2>&1; then - while security delete-generic-password -s buzz-desktop-dev >/dev/null 2>&1; do :; done - while security delete-generic-password -s sprout-desktop-dev >/dev/null 2>&1; do :; done - fi + delete_secret_namespace buzz-desktop-dev + delete_secret_namespace sprout-desktop-dev ;; Linux) remove_bundle_state "${XDG_DATA_HOME:-$HOME/.local/share}" diff --git a/scripts/reset-desktop-standalone-state.sh b/scripts/reset-desktop-standalone-state.sh index 64c13f8f84..fa3f6ce40b 100755 --- a/scripts/reset-desktop-standalone-state.sh +++ b/scripts/reset-desktop-standalone-state.sh @@ -3,14 +3,15 @@ set -euo pipefail instance_id="${1:-}" -keyring_service="${2:-}" +secret_service="${2:-}" +state_home="${BUZZ_TEST_HOME:-$HOME}" if [[ "$instance_id" != "xyz.block.buzz.app.dev" && "$instance_id" != xyz.block.buzz.app.dev.* ]]; then echo "reset-desktop-standalone-state: refusing non-dev bundle identifier: $instance_id" >&2 exit 1 fi -if [[ "$keyring_service" != "buzz-desktop-dev" && "$keyring_service" != buzz-desktop-dev.* ]]; then - echo "reset-desktop-standalone-state: refusing non-dev keyring service: $keyring_service" >&2 +if [[ "$secret_service" != "buzz-desktop-dev" && "$secret_service" != buzz-desktop-dev.* ]]; then + echo "reset-desktop-standalone-state: refusing non-dev secret service: $secret_service" >&2 exit 1 fi @@ -22,22 +23,36 @@ remove_path() { fi } +delete_secret_namespace() { + local service="$1" + local cli + cli="$(command -v daz-secrets || true)" + if [[ -z "$cli" ]]; then + echo "reset-desktop-standalone-state: daz-secrets is required" >&2 + exit 1 + fi + python3 -c 'import json, subprocess, sys +cli, service = sys.argv[1:] +items = json.loads(subprocess.check_output([cli, "list"], text=True)) +for item in items: + if item["service"] == service: + subprocess.run([cli, "delete", service, item["account"]], check=True)' "$cli" "$service" +} + case "${BUZZ_TEST_PLATFORM:-$(uname -s)}" in Darwin) - remove_path "$HOME/Library/Application Support/$instance_id" - remove_path "$HOME/Library/Caches/$instance_id" - remove_path "$HOME/Library/WebKit/$instance_id" - remove_path "$HOME/Library/HTTPStorages/$instance_id" - remove_path "$HOME/Library/Saved Application State/$instance_id.savedState" - remove_path "$HOME/Library/Preferences/$instance_id.plist" - if command -v security >/dev/null 2>&1; then - while security delete-generic-password -s "$keyring_service" >/dev/null 2>&1; do :; done - fi + remove_path "$state_home/Library/Application Support/$instance_id" + remove_path "$state_home/Library/Caches/$instance_id" + remove_path "$state_home/Library/WebKit/$instance_id" + remove_path "$state_home/Library/HTTPStorages/$instance_id" + remove_path "$state_home/Library/Saved Application State/$instance_id.savedState" + remove_path "$state_home/Library/Preferences/$instance_id.plist" + delete_secret_namespace "$secret_service" ;; Linux) - remove_path "${XDG_DATA_HOME:-$HOME/.local/share}/$instance_id" - remove_path "${XDG_CONFIG_HOME:-$HOME/.config}/$instance_id" - remove_path "${XDG_CACHE_HOME:-$HOME/.cache}/$instance_id" + remove_path "${XDG_DATA_HOME:-$state_home/.local/share}/$instance_id" + remove_path "${XDG_CONFIG_HOME:-$state_home/.config}/$instance_id" + remove_path "${XDG_CACHE_HOME:-$state_home/.cache}/$instance_id" ;; *) echo "reset-desktop-standalone-state: unsupported platform" >&2 diff --git a/scripts/test-reset-desktop-standalone-state.sh b/scripts/test-reset-desktop-standalone-state.sh index 04decaa827..1b1b4da26b 100755 --- a/scripts/test-reset-desktop-standalone-state.sh +++ b/scripts/test-reset-desktop-standalone-state.sh @@ -3,31 +3,32 @@ set -euo pipefail repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) tmp=$(mktemp -d) -trap 'rm -rf "$tmp"' EXIT -export HOME="$tmp/home" +secret_service="buzz-desktop-dev.reset-test.$$" +cleanup() { + daz-secrets delete "$secret_service" integration-test >/dev/null 2>&1 || true + rm -rf "$tmp" +} +trap cleanup EXIT export BUZZ_TEST_PLATFORM=Darwin -mkdir -p "$HOME/Library/Application Support/xyz.block.buzz.app.dev.example" -mkdir -p "$HOME/Library/Application Support/xyz.block.buzz.app.dev.other" -mkdir -p "$HOME/Library/Application Support/xyz.block.buzz.app" -mkdir -p "$HOME/.buzz-dev" -touch "$HOME/.buzz-dev/keep" -mkdir -p "$tmp/bin" -cat > "$tmp/bin/security" <<'MOCK' -#!/usr/bin/env bash -printf '%s\n' "$*" >> "$HOME/security-calls" -exit 1 -MOCK -chmod +x "$tmp/bin/security" -export PATH="$tmp/bin:$PATH" +export BUZZ_TEST_HOME="$tmp/home" +mkdir -p "$BUZZ_TEST_HOME/Library/Application Support/xyz.block.buzz.app.dev.example" +mkdir -p "$BUZZ_TEST_HOME/Library/Application Support/xyz.block.buzz.app.dev.other" +mkdir -p "$BUZZ_TEST_HOME/Library/Application Support/xyz.block.buzz.app" +mkdir -p "$BUZZ_TEST_HOME/.buzz-dev" +touch "$BUZZ_TEST_HOME/.buzz-dev/keep" +printf '%s' 'integration-test-value' | daz-secrets set "$secret_service" integration-test >/dev/null "$repo_root/scripts/reset-desktop-standalone-state.sh" \ - xyz.block.buzz.app.dev.example buzz-desktop-dev.example + xyz.block.buzz.app.dev.example "$secret_service" -[[ ! -e "$HOME/Library/Application Support/xyz.block.buzz.app.dev.example" ]] -[[ -d "$HOME/Library/Application Support/xyz.block.buzz.app.dev.other" ]] -[[ -d "$HOME/Library/Application Support/xyz.block.buzz.app" ]] -[[ -f "$HOME/.buzz-dev/keep" ]] -grep -Fx -- "delete-generic-password -s buzz-desktop-dev.example" "$HOME/security-calls" >/dev/null +[[ ! -e "$BUZZ_TEST_HOME/Library/Application Support/xyz.block.buzz.app.dev.example" ]] +[[ -d "$BUZZ_TEST_HOME/Library/Application Support/xyz.block.buzz.app.dev.other" ]] +[[ -d "$BUZZ_TEST_HOME/Library/Application Support/xyz.block.buzz.app" ]] +[[ -f "$BUZZ_TEST_HOME/.buzz-dev/keep" ]] +if daz-secrets get "$secret_service" integration-test >/dev/null 2>&1; then + echo "expected standalone reset to remove the scoped provider secret" >&2 + exit 1 +fi if "$repo_root/scripts/reset-desktop-standalone-state.sh" \ xyz.block.buzz.app buzz-desktop >/dev/null 2>&1; then