git.delta.rocks / jrsonnet / refs/commits / 186c6450de9b

difftreelog

chore update dependencies

mzunztmnYaroslav Bolyukin2026-03-12parent: #b7ea190.patch.diff
in: trunk

4 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -117,6 +117,12 @@
 ]
 
 [[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
 name = "android_system_properties"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -197,6 +203,36 @@
 checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
 
 [[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",
+]
+
+[[package]]
+name = "async-io"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-io",
+ "futures-lite",
+ "parking",
+ "polling",
+ "rustix 1.1.4",
+ "slab",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
 name = "async-stream"
 version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -248,61 +284,24 @@
 checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
 dependencies = [
  "async-trait",
- "axum-core 0.4.5",
+ "axum-core",
  "bytes",
  "futures-util",
  "http",
  "http-body",
  "http-body-util",
  "itoa",
- "matchit 0.7.3",
+ "matchit",
  "memchr",
  "mime",
  "percent-encoding",
  "pin-project-lite",
  "rustversion",
  "serde",
- "sync_wrapper",
- "tower 0.5.3",
- "tower-layer",
- "tower-service",
-]
-
-[[package]]
-name = "axum"
-version = "0.8.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
-dependencies = [
- "axum-core 0.5.6",
- "axum-macros",
- "base64 0.22.1",
- "bytes",
- "form_urlencoded",
- "futures-util",
- "http",
- "http-body",
- "http-body-util",
- "hyper",
- "hyper-util",
- "itoa",
- "matchit 0.8.4",
- "memchr",
- "mime",
- "percent-encoding",
- "pin-project-lite",
- "serde_core",
- "serde_json",
- "serde_path_to_error",
- "serde_urlencoded",
- "sha1",
  "sync_wrapper",
- "tokio",
- "tokio-tungstenite",
  "tower 0.5.3",
  "tower-layer",
  "tower-service",
- "tracing",
 ]
 
 [[package]]
@@ -326,58 +325,6 @@
 ]
 
 [[package]]
-name = "axum-core"
-version = "0.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
-dependencies = [
- "bytes",
- "futures-core",
- "http",
- "http-body",
- "http-body-util",
- "mime",
- "pin-project-lite",
- "sync_wrapper",
- "tower-layer",
- "tower-service",
- "tracing",
-]
-
-[[package]]
-name = "axum-extra"
-version = "0.12.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fef252edff26ddba56bbcdf2ee3307b8129acb86f5749b68990c168a6fcc9c76"
-dependencies = [
- "axum 0.8.8",
- "axum-core 0.5.6",
- "bytes",
- "futures-core",
- "futures-util",
- "headers",
- "http",
- "http-body",
- "http-body-util",
- "mime",
- "pin-project-lite",
- "tower-layer",
- "tower-service",
- "tracing",
-]
-
-[[package]]
-name = "axum-macros"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
 name = "base64"
 version = "0.21.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -511,6 +458,15 @@
 checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
 
 [[package]]
+name = "castaway"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
 name = "cbc"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -691,6 +647,29 @@
 checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
 
 [[package]]
+name = "compact_str"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a"
+dependencies = [
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "rustversion",
+ "ryu",
+ "static_assertions",
+]
+
+[[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 = "console"
 version = "0.16.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -722,6 +701,15 @@
 checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
 
 [[package]]
+name = "convert_case"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
 name = "cookie-factory"
 version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -764,6 +752,55 @@
 ]
 
 [[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crossterm"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "derive_more",
+ "document-features",
+ "futures-core",
+ "mio",
+ "parking_lot",
+ "rustix 1.1.4",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "crosstermion"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6ae462f0b868614980d59df41e217a77648de7ad7cf8b2a407155659896d889"
+dependencies = [
+ "async-channel",
+ "crossterm",
+ "futures-channel",
+ "futures-core",
+ "futures-lite",
+ "ratatui",
+ "tui-react",
+]
+
+[[package]]
 name = "crypto-common"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -879,12 +916,40 @@
 ]
 
 [[package]]
-name = "data-encoding"
-version = "2.10.0"
+name = "darling"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
+checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
 
 [[package]]
+name = "darling_core"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
+dependencies = [
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "der"
 version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -905,6 +970,28 @@
 ]
 
 [[package]]
+name = "derive_more"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn",
+]
+
+[[package]]
 name = "digest"
 version = "0.10.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -928,6 +1015,15 @@
 ]
 
 [[package]]
+name = "document-features"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
+dependencies = [
+ "litrs",
+]
+
+[[package]]
 name = "ed25519"
 version = "2.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1001,6 +1097,27 @@
 ]
 
 [[package]]
+name = "event-listener"
+version = "5.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
+dependencies = [
+ "event-listener",
+ "pin-project-lite",
+]
+
+[[package]]
 name = "fastrand"
 version = "2.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1278,6 +1395,19 @@
 checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
 
 [[package]]
+name = "futures-lite"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
+dependencies = [
+ "fastrand",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
 name = "futures-macro"
 version = "0.3.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1419,29 +1549,10 @@
 version = "0.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
-
-[[package]]
-name = "headers"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb"
 dependencies = [
- "base64 0.22.1",
- "bytes",
- "headers-core",
- "http",
- "httpdate",
- "mime",
- "sha1",
-]
-
-[[package]]
-name = "headers-core"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
-dependencies = [
- "http",
+ "allocator-api2",
+ "equivalent",
+ "foldhash 0.2.0",
 ]
 
 [[package]]
@@ -1451,6 +1562,12 @@
 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
 name = "hex"
 version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1782,6 +1899,12 @@
 checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
 
 [[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
 name = "idna"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1858,6 +1981,19 @@
 ]
 
 [[package]]
+name = "instability"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971"
+dependencies = [
+ "darling",
+ "indoc",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "intl-memoizer"
 version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1929,6 +2065,47 @@
 checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
 
 [[package]]
+name = "jiff"
+version = "0.2.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
+dependencies = [
+ "jiff-static",
+ "jiff-tzdb-platform",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde_core",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "jiff-tzdb"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076"
+
+[[package]]
+name = "jiff-tzdb-platform"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
+dependencies = [
+ "jiff-tzdb",
+]
+
+[[package]]
 name = "js-sys"
 version = "0.3.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1939,6 +2116,17 @@
 ]
 
 [[package]]
+name = "kasuari"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899"
+dependencies = [
+ "hashbrown 0.16.1",
+ "portable-atomic",
+ "thiserror 2.0.18",
+]
+
+[[package]]
 name = "lazy_static"
 version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1976,6 +2164,15 @@
 checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
 
 [[package]]
+name = "line-clipping"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f4de44e98ddbf09375cbf4d17714d18f39195f4f4894e8524501726fd9a8a4a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
 name = "link-cplusplus"
 version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2009,6 +2206,12 @@
 checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
 
 [[package]]
+name = "litrs"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
+
+[[package]]
 name = "lock_api"
 version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2024,6 +2227,15 @@
 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
 
 [[package]]
+name = "lru"
+version = "0.16.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
+dependencies = [
+ "hashbrown 0.16.1",
+]
+
+[[package]]
 name = "matchers"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2037,12 +2249,6 @@
 version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
-
-[[package]]
-name = "matchit"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
 
 [[package]]
 name = "memchr"
@@ -2079,6 +2285,7 @@
 checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
 dependencies = [
  "libc",
+ "log",
  "wasi",
  "windows-sys 0.61.2",
 ]
@@ -2216,6 +2423,15 @@
 ]
 
 [[package]]
+name = "num_threads"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
+dependencies = [
+ "libc",
+]
+
+[[package]]
 name = "once_cell"
 version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2347,6 +2563,12 @@
 ]
 
 [[package]]
+name = "parking"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+
+[[package]]
 name = "parking_lot"
 version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2492,6 +2714,20 @@
 checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
 
 [[package]]
+name = "polling"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
+dependencies = [
+ "cfg-if",
+ "concurrent-queue",
+ "hermit-abi",
+ "pin-project-lite",
+ "rustix 1.1.4",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
 name = "poly1305"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2521,6 +2757,15 @@
 checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
 
 [[package]]
+name = "portable-atomic-util"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
 name = "potential_utf"
 version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2586,6 +2831,36 @@
 ]
 
 [[package]]
+name = "prodash"
+version = "31.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "962200e2d7d551451297d9fdce85138374019ada198e30ea9ede38034e27604c"
+dependencies = [
+ "async-io",
+ "crosstermion",
+ "futures-core",
+ "futures-lite",
+ "jiff",
+ "parking_lot",
+ "ratatui",
+ "tui-react",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "prodash-layer"
+version = "0.1.0"
+dependencies = [
+ "futures",
+ "futures-core",
+ "prodash",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
 name = "proptest"
 version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2676,20 +2951,6 @@
 ]
 
 [[package]]
-name = "pusher"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "axum 0.8.8",
- "axum-extra",
- "futures-util",
- "hyper",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
 name = "quote"
 version = "1.0.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2796,6 +3057,69 @@
 ]
 
 [[package]]
+name = "ratatui"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1ce67fb8ba4446454d1c8dbaeda0557ff5e94d39d5e5ed7f10a65eb4c8266bc"
+dependencies = [
+ "instability",
+ "ratatui-core",
+ "ratatui-crossterm",
+ "ratatui-widgets",
+]
+
+[[package]]
+name = "ratatui-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293"
+dependencies = [
+ "bitflags",
+ "compact_str",
+ "hashbrown 0.16.1",
+ "indoc",
+ "itertools 0.14.0",
+ "kasuari",
+ "lru",
+ "strum",
+ "thiserror 2.0.18",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width",
+]
+
+[[package]]
+name = "ratatui-crossterm"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "577c9b9f652b4c121fb25c6a391dd06406d3b092ba68827e6d2f09550edc54b3"
+dependencies = [
+ "cfg-if",
+ "crossterm",
+ "instability",
+ "ratatui-core",
+]
+
+[[package]]
+name = "ratatui-widgets"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7dbfa023cd4e604c2553483820c5fe8aa9d71a42eea5aa77c6e7f35756612db"
+dependencies = [
+ "bitflags",
+ "hashbrown 0.16.1",
+ "indoc",
+ "instability",
+ "itertools 0.14.0",
+ "line-clipping",
+ "ratatui-core",
+ "strum",
+ "time",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
 name = "rcgen"
 version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3211,17 +3535,6 @@
 ]
 
 [[package]]
-name = "serde_path_to_error"
-version = "0.1.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
-dependencies = [
- "itoa",
- "serde",
- "serde_core",
-]
-
-[[package]]
 name = "serde_urlencoded"
 version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3231,17 +3544,6 @@
  "itoa",
  "ryu",
  "serde",
-]
-
-[[package]]
-name = "sha1"
-version = "0.10.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
-dependencies = [
- "cfg-if",
- "cpufeatures 0.2.17",
- "digest",
 ]
 
 [[package]]
@@ -3277,6 +3579,27 @@
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
+name = "signal-hook"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
 name = "signal-hook-registry"
 version = "1.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3357,12 +3680,39 @@
 checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
 
 [[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
 name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
+name = "strum"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "subtle"
 version = "2.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3581,7 +3931,9 @@
 checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
 dependencies = [
  "deranged",
+ "libc",
  "num-conv",
+ "num_threads",
  "powerfmt",
  "serde_core",
  "time-core",
@@ -3665,18 +4017,6 @@
 ]
 
 [[package]]
-name = "tokio-tungstenite"
-version = "0.28.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
-dependencies = [
- "futures-util",
- "log",
- "tokio",
- "tungstenite",
-]
-
-[[package]]
 name = "tokio-util"
 version = "0.7.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3743,7 +4083,7 @@
 dependencies = [
  "async-stream",
  "async-trait",
- "axum 0.7.9",
+ "axum",
  "base64 0.22.1",
  "bytes",
  "h2",
@@ -3911,7 +4251,6 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
 dependencies = [
- "log",
  "pin-project-lite",
  "tracing-attributes",
  "tracing-core",
@@ -4015,20 +4354,15 @@
 checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
 [[package]]
-name = "tungstenite"
-version = "0.28.0"
+name = "tui-react"
+version = "0.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
+checksum = "3c07031f0f4eb182785a8621967da6c75b9b21cfc7dfaaac78400b9a12492e66"
 dependencies = [
- "bytes",
- "data-encoding",
- "http",
- "httparse",
  "log",
- "rand 0.9.2",
- "sha1",
- "thiserror 2.0.18",
- "utf-8",
+ "ratatui",
+ "unicode-segmentation",
+ "unicode-width",
 ]
 
 [[package]]
@@ -4084,6 +4418,23 @@
 checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
 
 [[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-truncate"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b380a1238663e5f8a691f9039c73e1cdae598a30e9855f541d29b08b53e9a5"
+dependencies = [
+ "itertools 0.14.0",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
 name = "unicode-width"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4134,12 +4485,6 @@
  "percent-encoding",
  "serde",
 ]
-
-[[package]]
-name = "utf-8"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
 
 [[package]]
 name = "utf8_iter"
@@ -4358,6 +4703,22 @@
 ]
 
 [[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
 name = "winapi-util"
 version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4367,6 +4728,12 @@
 ]
 
 [[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
 name = "windows-core"
 version = "0.62.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
modifiedcmds/generator-helper/src/main.rsdiffbeforeafterboth
before · cmds/generator-helper/src/main.rs
1use std::{2	env,3	fs::{File, OpenOptions},4	io::{self, Read, Write, copy, stdin, stdout},5	str::FromStr,6};78use age::{9	Encryptor, Recipient,10	ssh::{ParseRecipientKeyError, Recipient as SshRecipient},11};12use anyhow::{Context, Result, anyhow, bail, ensure};13use clap::{Parser, ValueEnum};14use ed25519_dalek::SecretKey;15use fleet_shared::SecretData;16use rand::{17	RngCore,18	distr::{Alphanumeric, Distribution, SampleString, Uniform},19	rng,20};2122fn write_output_file(out: &str) -> Result<File> {23	let file = OpenOptions::new()24		.create_new(true)25		.write(true)26		.open(out)27		.with_context(|| format!("failed to open output {out:?}"))?;28	Ok(file)29}30fn write_public(out: &str, mut input: impl Read, encoding: OutputEncoding) -> Result<()> {31	let mut output = write_output_file(out)?;3233	let mut data = Vec::new();34	copy(&mut input, &mut wrap_encoder(&mut data, encoding))?;3536	output.write_all(37		SecretData {38			data,39			encrypted: false,40		}41		.to_string()42		.as_bytes(),43	)?;44	Ok(())45}46fn write_private(47	identities: &Identities,48	out: &str,49	mut input: impl Read,50	encoding: OutputEncoding,51) -> Result<()> {52	let mut output = write_output_file(out)?;53	let encryptor = make_encryptor(identities)?;5455	let mut data = Vec::new();56	{57		let mut encrypted_writer = encryptor.wrap_output(&mut data)?;58		copy(59			&mut input,60			&mut wrap_encoder(&mut encrypted_writer, encoding),61		)?;62		encrypted_writer.finish()?;63	};6465	output.write_all(66		SecretData {67			data,68			encrypted: true,69		}70		.to_string()71		.as_bytes(),72	)?;73	Ok(())74}7576type Identities = Vec<SshRecipient>;77fn load_identities() -> Result<Identities> {78	let list = env::var("GENERATOR_HELPER_IDENTITIES");79	let list = match list {80		Ok(v) => v,81		Err(env::VarError::NotPresent) => {82			bail!(83				"gh is only intended to be used from secret generator scripts, but if you really want to use it somewhere else - set GENERATOR_HELPER_IDENTITIES to list of newline-delimited ssh identities"84			);85		}86		Err(e) => bail!("somehow, identities list is not utf-8: {e}"),87	};88	let list = list.trim();89	ensure!(!list.is_empty(), "no identities passed, can't encrypt data");90	list.lines()91		.map(age::ssh::Recipient::from_str)92		.collect::<Result<Identities, ParseRecipientKeyError>>()93		.map_err(|e| anyhow!("parse recipients: {e:?}"))94}95fn make_encryptor(r: &Identities) -> Result<Encryptor> {96	Ok(97		Encryptor::with_recipients(r.iter().map(|v| v as &dyn Recipient))98			.expect("list is not empty"),99	)100}101fn wrap_encoder<'t>(w: impl Write + 't, encoding: OutputEncoding) -> impl Write + 't {102	fn coerce<'t>(w: impl Write + 't) -> Box<dyn Write + 't> {103		Box::new(w)104	}105	match encoding {106		OutputEncoding::Raw => coerce(w),107		OutputEncoding::Base64 => {108			use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};109110			let writer = EncoderWriter::new(w, &STANDARD);111			coerce(writer)112		}113		OutputEncoding::Hex => {114			struct HexWriter<W>(W);115			impl<W> Write for HexWriter<W>116			where117				W: Write,118			{119				fn write(&mut self, buf: &[u8]) -> io::Result<usize> {120					let encoded = hex::encode(buf);121					self.0.write_all(encoded.as_bytes())?;122					Ok(buf.len())123				}124125				fn flush(&mut self) -> io::Result<()> {126					self.0.flush()127				}128			}129			coerce(HexWriter(w))130		}131	}132}133134#[derive(Clone, Copy, ValueEnum, Default)]135enum OutputEncoding {136	/// Do not encode data, store as is.137	#[default]138	Raw,139	/// Encode as base64 (with padding).140	Base64,141	/// Encode as hex (without leading 0x)142	Hex,143}144145#[derive(Parser)]146enum Generate {147	/// Generate public, private keys without wrapping, in standard ed25519 schema148	/// (64 bytes private (due to merge with private), 32 bytes public)149	Ed25519 {150		#[arg(long, short = 'p')]151		public: String,152		#[arg(long, short = 's')]153		private: String,154		/// Private key should be just the private key (32 bytes), not standard private+public.155		#[arg(long)]156		no_embed_public: bool,157		#[arg(long, short = 'e', value_enum, default_value_t)]158		encoding: OutputEncoding,159	},160	/// Generate public, private keys without wrapping, in standard x25519 schema161	/// (32 bytes private, 32 bytes public)162	X25519 {163		#[arg(long, short = 'p')]164		public: String,165		#[arg(long, short = 's')]166		private: String,167		#[arg(long, short = 'e', value_enum, default_value_t)]168		encoding: OutputEncoding,169	},170	Password {171		#[arg(long, short = 'o')]172		output: String,173		#[arg(long)]174		size: usize,175		#[arg(long, short = 'n')]176		no_symbols: bool,177		#[arg(long, short = 'e', value_enum, default_value_t)]178		encoding: OutputEncoding,179	},180	Bytes {181		#[arg(long, short = 'o')]182		output: String,183		#[arg(long, short = 'c')]184		count: usize,185		/// Ensure there is no NULs in bytestring.186		#[arg(long)]187		no_nuls: bool,188		#[arg(long, short = 'e', value_enum, default_value_t)]189		encoding: OutputEncoding,190	},191}192193#[derive(Parser)]194enum Opts {195	/// Encode public part from stdin.196	Public {197		#[arg(long, short = 'o')]198		output: String,199		#[arg(long, short = 'e', value_enum, default_value_t)]200		encoding: OutputEncoding,201	},202	/// Encrypt private part from stdin.203	Private {204		#[arg(long, short = 'o')]205		output: String,206		#[arg(long, short = 'e', value_enum, default_value_t)]207		encoding: OutputEncoding,208	},209	/// Sometimes you also need to reencode secret, this command allows you to get raw data from210	/// secret encoded using `gh public`... I would like if I knew a better design for some sort of211	/// such thing. Ideally there should be no need to decode secrets back, but garage wants both212	/// raw pubkey and raw secret key, yet also requires node id which is hex-reencoded public key.213	Decode {214		#[arg(long, short = 'i')]215		input: String,216	},217	/// Generate keys in well-known schemas.218	///219	/// Note that this command is only intended to be used in fleet secret generator,220	/// otherwise you should ensure noone is able to read generated files, they don't have any mode set by default.221	///222	/// Fleet also doesn't zeroize memory/assumes good OsRng/makes other assumptions, which makes it only suitable to223	/// be used in nix sandbox.224	#[command(subcommand)]225	Generate(Generate),226}227228fn main() -> Result<()> {229	let opts = Opts::parse();230	// Assumed to be secure, seeded from secure OsRng+reseeded.231	let mut rng = rng();232233	match opts {234		Opts::Public { output, encoding } => {235			write_public(&output, stdin(), encoding)?;236		}237		Opts::Private { output, encoding } => {238			let recipients = load_identities()?;239			write_private(&recipients, &output, stdin(), encoding)?;240		}241		Opts::Generate(generate) => {242			match generate {243				Generate::Ed25519 {244					public,245					private,246					no_embed_public,247					encoding,248				} => {249					use ed25519_dalek::SigningKey;250251					let recipients = load_identities()?;252					let mut secret = SecretKey::default();253					rng.fill_bytes(&mut secret);254					// TODO: Use SigningKey::generate after https://github.com/dalek-cryptography/curve25519-dalek/pull/762255					let key = SigningKey::from_bytes(&secret).to_keypair_bytes();256					write_public(&public, &key[32..], encoding)?;257					write_private(258						&recipients,259						&private,260						&key[..{ if no_embed_public { 32 } else { 64 } }],261						encoding,262					)?;263				}264				Generate::X25519 {265					public,266					private,267					encoding,268				} => {269					use x25519_dalek::{PublicKey, StaticSecret};270271					let recipients = load_identities()?;272					// TODO: Use random_from_rng after https://github.com/dalek-cryptography/curve25519-dalek/pull/762273					let key = StaticSecret::random();274					let public_key: PublicKey = (&key).into();275					write_public(&public, public_key.as_bytes().as_slice(), encoding)?;276					write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;277				}278				Generate::Password {279					size,280					no_symbols,281					output,282					encoding,283				} => {284					ensure!(285						size >= 6,286						"misconfiguration? password is shorter than 6 chars"287					);288					let recipients = load_identities()?;289					let out = if no_symbols {290						Alphanumeric.sample_string(&mut rng, size)291					} else {292						// Alphabet of Alphanumberic + symbols293						const GEN_ASCII_SYMBOLS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";294						let uniform =295							Uniform::new(0, GEN_ASCII_SYMBOLS.len()).expect("range is valid");296						(0..size)297							.map(|_| uniform.sample(&mut rng))298							.map(|i| GEN_ASCII_SYMBOLS[i] as char)299							.collect::<String>()300					};301					write_private(&recipients, &output, out.as_bytes(), encoding)?;302				}303				Generate::Bytes {304					output,305					count,306					no_nuls,307					encoding,308				} => {309					ensure!(310						count >= 6,311						"misconfiguration? bytestring is shorter than 6 chars"312					);313					let recipients = load_identities()?;314					let mut bytes = vec![0u8; count];315					if no_nuls {316						let rand = Uniform::new_inclusive(0x1u8, 0xffu8)317							.expect("range is valid")318							.sample_iter(&mut rng);319						for (byte, rand) in bytes.iter_mut().zip(rand) {320							*byte = rand;321						}322					} else {323						rng.fill_bytes(&mut bytes);324					};325					write_private(&recipients, &output, bytes.as_slice(), encoding)?;326				}327			}328		}329		Opts::Decode { input } => {330			let mut data = Vec::new();331			File::open(input)?.read_to_end(&mut data)?;332			let data = String::from_utf8(data).context(333				"encoded data is always utf-8, you are trying to use decode the wrong way.",334			)?;335			let data =336				SecretData::from_str(&data).map_err(|e| anyhow!("failed to decode data: {e}"))?;337			ensure!(338				!data.encrypted,339				"you can not decrypt secret data, only decode public."340			);341			stdout().write_all(&data.data)?;342		}343	}344	Ok(())345}
after · cmds/generator-helper/src/main.rs
1use std::{2	env,3	fs::{File, OpenOptions},4	io::{self, Read, Write, copy, stdin, stdout},5	str::FromStr,6};78use age::{9	Encryptor, Recipient,10	ssh::{ParseRecipientKeyError, Recipient as SshRecipient},11};12use anyhow::{Context, Result, anyhow, bail, ensure};13use clap::{Parser, ValueEnum};14use ed25519_dalek::SecretKey;15use fleet_shared::SecretData;16use rand::{17	Rng as _,18	distr::{Alphanumeric, Distribution, SampleString, Uniform},19	rng,20};2122fn write_output_file(out: &str) -> Result<File> {23	let file = OpenOptions::new()24		.create_new(true)25		.write(true)26		.open(out)27		.with_context(|| format!("failed to open output {out:?}"))?;28	Ok(file)29}30fn write_public(out: &str, mut input: impl Read, encoding: OutputEncoding) -> Result<()> {31	let mut output = write_output_file(out)?;3233	let mut data = Vec::new();34	copy(&mut input, &mut wrap_encoder(&mut data, encoding))?;3536	output.write_all(37		SecretData {38			data,39			encrypted: false,40		}41		.to_string()42		.as_bytes(),43	)?;44	Ok(())45}46fn write_private(47	identities: &Identities,48	out: &str,49	mut input: impl Read,50	encoding: OutputEncoding,51) -> Result<()> {52	let mut output = write_output_file(out)?;53	let encryptor = make_encryptor(identities)?;5455	let mut data = Vec::new();56	{57		let mut encrypted_writer = encryptor.wrap_output(&mut data)?;58		copy(59			&mut input,60			&mut wrap_encoder(&mut encrypted_writer, encoding),61		)?;62		encrypted_writer.finish()?;63	};6465	output.write_all(66		SecretData {67			data,68			encrypted: true,69		}70		.to_string()71		.as_bytes(),72	)?;73	Ok(())74}7576type Identities = Vec<SshRecipient>;77fn load_identities() -> Result<Identities> {78	let list = env::var("GENERATOR_HELPER_IDENTITIES");79	let list = match list {80		Ok(v) => v,81		Err(env::VarError::NotPresent) => {82			bail!(83				"gh is only intended to be used from secret generator scripts, but if you really want to use it somewhere else - set GENERATOR_HELPER_IDENTITIES to list of newline-delimited ssh identities"84			);85		}86		Err(e) => bail!("somehow, identities list is not utf-8: {e}"),87	};88	let list = list.trim();89	ensure!(!list.is_empty(), "no identities passed, can't encrypt data");90	list.lines()91		.map(age::ssh::Recipient::from_str)92		.collect::<Result<Identities, ParseRecipientKeyError>>()93		.map_err(|e| anyhow!("parse recipients: {e:?}"))94}95fn make_encryptor(r: &Identities) -> Result<Encryptor> {96	Ok(97		Encryptor::with_recipients(r.iter().map(|v| v as &dyn Recipient))98			.expect("list is not empty"),99	)100}101fn wrap_encoder<'t>(w: impl Write + 't, encoding: OutputEncoding) -> impl Write + 't {102	fn coerce<'t>(w: impl Write + 't) -> Box<dyn Write + 't> {103		Box::new(w)104	}105	match encoding {106		OutputEncoding::Raw => coerce(w),107		OutputEncoding::Base64 => {108			use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};109110			let writer = EncoderWriter::new(w, &STANDARD);111			coerce(writer)112		}113		OutputEncoding::Hex => {114			struct HexWriter<W>(W);115			impl<W> Write for HexWriter<W>116			where117				W: Write,118			{119				fn write(&mut self, buf: &[u8]) -> io::Result<usize> {120					let encoded = hex::encode(buf);121					self.0.write_all(encoded.as_bytes())?;122					Ok(buf.len())123				}124125				fn flush(&mut self) -> io::Result<()> {126					self.0.flush()127				}128			}129			coerce(HexWriter(w))130		}131	}132}133134#[derive(Clone, Copy, ValueEnum, Default)]135enum OutputEncoding {136	/// Do not encode data, store as is.137	#[default]138	Raw,139	/// Encode as base64 (with padding).140	Base64,141	/// Encode as hex (without leading 0x)142	Hex,143}144145#[derive(Parser)]146enum Generate {147	/// Generate public, private keys without wrapping, in standard ed25519 schema148	/// (64 bytes private (due to merge with private), 32 bytes public)149	Ed25519 {150		#[arg(long, short = 'p')]151		public: String,152		#[arg(long, short = 's')]153		private: String,154		/// Private key should be just the private key (32 bytes), not standard private+public.155		#[arg(long)]156		no_embed_public: bool,157		#[arg(long, short = 'e', value_enum, default_value_t)]158		encoding: OutputEncoding,159	},160	/// Generate public, private keys without wrapping, in standard x25519 schema161	/// (32 bytes private, 32 bytes public)162	X25519 {163		#[arg(long, short = 'p')]164		public: String,165		#[arg(long, short = 's')]166		private: String,167		#[arg(long, short = 'e', value_enum, default_value_t)]168		encoding: OutputEncoding,169	},170	Password {171		#[arg(long, short = 'o')]172		output: String,173		#[arg(long)]174		size: usize,175		#[arg(long, short = 'n')]176		no_symbols: bool,177		#[arg(long, short = 'e', value_enum, default_value_t)]178		encoding: OutputEncoding,179	},180	Bytes {181		#[arg(long, short = 'o')]182		output: String,183		#[arg(long, short = 'c')]184		count: usize,185		/// Ensure there is no NULs in bytestring.186		#[arg(long)]187		no_nuls: bool,188		#[arg(long, short = 'e', value_enum, default_value_t)]189		encoding: OutputEncoding,190	},191}192193#[derive(Parser)]194enum Opts {195	/// Encode public part from stdin.196	Public {197		#[arg(long, short = 'o')]198		output: String,199		#[arg(long, short = 'e', value_enum, default_value_t)]200		encoding: OutputEncoding,201	},202	/// Encrypt private part from stdin.203	Private {204		#[arg(long, short = 'o')]205		output: String,206		#[arg(long, short = 'e', value_enum, default_value_t)]207		encoding: OutputEncoding,208	},209	/// Sometimes you also need to reencode secret, this command allows you to get raw data from210	/// secret encoded using `gh public`... I would like if I knew a better design for some sort of211	/// such thing. Ideally there should be no need to decode secrets back, but garage wants both212	/// raw pubkey and raw secret key, yet also requires node id which is hex-reencoded public key.213	Decode {214		#[arg(long, short = 'i')]215		input: String,216	},217	/// Generate keys in well-known schemas.218	///219	/// Note that this command is only intended to be used in fleet secret generator,220	/// otherwise you should ensure noone is able to read generated files, they don't have any mode set by default.221	///222	/// Fleet also doesn't zeroize memory/assumes good OsRng/makes other assumptions, which makes it only suitable to223	/// be used in nix sandbox.224	#[command(subcommand)]225	Generate(Generate),226}227228fn main() -> Result<()> {229	let opts = Opts::parse();230	// Assumed to be secure, seeded from secure OsRng+reseeded.231	let mut rng = rng();232233	match opts {234		Opts::Public { output, encoding } => {235			write_public(&output, stdin(), encoding)?;236		}237		Opts::Private { output, encoding } => {238			let recipients = load_identities()?;239			write_private(&recipients, &output, stdin(), encoding)?;240		}241		Opts::Generate(generate) => {242			match generate {243				Generate::Ed25519 {244					public,245					private,246					no_embed_public,247					encoding,248				} => {249					use ed25519_dalek::SigningKey;250251					let recipients = load_identities()?;252					let mut secret = SecretKey::default();253					rng.fill_bytes(&mut secret);254					// TODO: Use SigningKey::generate after https://github.com/dalek-cryptography/curve25519-dalek/pull/762255					let key = SigningKey::from_bytes(&secret).to_keypair_bytes();256					write_public(&public, &key[32..], encoding)?;257					write_private(258						&recipients,259						&private,260						&key[..{ if no_embed_public { 32 } else { 64 } }],261						encoding,262					)?;263				}264				Generate::X25519 {265					public,266					private,267					encoding,268				} => {269					use x25519_dalek::{PublicKey, StaticSecret};270271					let recipients = load_identities()?;272					// TODO: Use random_from_rng after https://github.com/dalek-cryptography/curve25519-dalek/pull/762273					let key = StaticSecret::random();274					let public_key: PublicKey = (&key).into();275					write_public(&public, public_key.as_bytes().as_slice(), encoding)?;276					write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;277				}278				Generate::Password {279					size,280					no_symbols,281					output,282					encoding,283				} => {284					ensure!(285						size >= 6,286						"misconfiguration? password is shorter than 6 chars"287					);288					let recipients = load_identities()?;289					let out = if no_symbols {290						Alphanumeric.sample_string(&mut rng, size)291					} else {292						// Alphabet of Alphanumberic + symbols293						const GEN_ASCII_SYMBOLS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";294						let uniform =295							Uniform::new(0, GEN_ASCII_SYMBOLS.len()).expect("range is valid");296						(0..size)297							.map(|_| uniform.sample(&mut rng))298							.map(|i| GEN_ASCII_SYMBOLS[i] as char)299							.collect::<String>()300					};301					write_private(&recipients, &output, out.as_bytes(), encoding)?;302				}303				Generate::Bytes {304					output,305					count,306					no_nuls,307					encoding,308				} => {309					ensure!(310						count >= 6,311						"misconfiguration? bytestring is shorter than 6 chars"312					);313					let recipients = load_identities()?;314					let mut bytes = vec![0u8; count];315					if no_nuls {316						let rand = Uniform::new_inclusive(0x1u8, 0xffu8)317							.expect("range is valid")318							.sample_iter(&mut rng);319						for (byte, rand) in bytes.iter_mut().zip(rand) {320							*byte = rand;321						}322					} else {323						rng.fill_bytes(&mut bytes);324					};325					write_private(&recipients, &output, bytes.as_slice(), encoding)?;326				}327			}328		}329		Opts::Decode { input } => {330			let mut data = Vec::new();331			File::open(input)?.read_to_end(&mut data)?;332			let data = String::from_utf8(data).context(333				"encoded data is always utf-8, you are trying to use decode the wrong way.",334			)?;335			let data =336				SecretData::from_str(&data).map_err(|e| anyhow!("failed to decode data: {e}"))?;337			ensure!(338				!data.encrypted,339				"you can not decrypt secret data, only decode public."340			);341			stdout().write_all(&data.data)?;342		}343	}344	Ok(())345}
modifiedcrates/fleet-base/src/primops.rsdiffbeforeafterboth
--- a/crates/fleet-base/src/primops.rs
+++ b/crates/fleet-base/src/primops.rs
@@ -325,9 +325,9 @@
 				generate(config, expectations_, &generator, &default_generator_drv).await
 			})?;
 
-			dists.extend(generated.clone(), format!("secret was generated"));
+			dists.extend(generated.clone(), "secret was generated".to_string());
 
-			return Ok(secret_to_parts(&secret, &generated.secret.parts, &expectations.parts));
+			Ok(secret_to_parts(&secret, &generated.secret.parts, &expectations.parts))
 		},
 	)
 	.register();
modifiedcrates/nix-eval/build.rsdiffbeforeafterboth
--- a/crates/nix-eval/build.rs
+++ b/crates/nix-eval/build.rs
@@ -37,12 +37,10 @@
 	cxx_build::bridge("src/logging.rs")
 		.file("src/logging.cc")
 		.std("c++23")
-		.shared_flag(true)
 		.compile("nix-eval-logging");
 	cxx_build::bridge("src/lib.rs")
 		.file("src/lib.cc")
 		.std("c++23")
-		.shared_flag(true)
 		.compile("nix-eval");
 
 	println!("cargo:rerun-if-changed=src/lib.cc");