git.delta.rocks / jrsonnet / refs/commits / b66f85717079

difftreelog

chore(deps) update to `age` version `0.11` (#9)

Petr Portnov | PROgrm_JARvis2024-11-17parent: #966948d.patch.diff
in: trunk
* chore(deps): update to `age` version `0.11`

* chore(deps): update the remaining dependencies

* chore: simplify `encrypt_secret_data` bounds

* chore: simplify `encrypt_secret_data` bounds even more

9 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -63,9 +63,9 @@
 
 [[package]]
 name = "age"
-version = "0.10.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edeef7d7b199195a2d7d7a8155d2d04aee736e60c5c7bdd7097d115369a8817d"
+checksum = "2020562e68d7a02c2743707b262c62484b340a296924a5e4146d5a0a96ca8103"
 dependencies = [
  "aes",
  "aes-gcm",
@@ -98,9 +98,9 @@
 
 [[package]]
 name = "age-core"
-version = "0.10.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5f11899bc2bbddd135edbc30c36b1924fa59d0746bb45beb5933fafe3fe509b"
+checksum = "e2bf6a89c984ca9d850913ece2da39e1d200563b0a94b002b253beee4c5acf99"
 dependencies = [
  "base64 0.21.7",
  "chacha20poly1305",
@@ -261,9 +261,9 @@
 
 [[package]]
 name = "axum"
-version = "0.7.7"
+version = "0.7.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
+checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
 dependencies = [
  "async-trait",
  "axum-core",
@@ -318,7 +318,7 @@
  "miniz_oxide",
  "object",
  "rustc-demangle",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -480,9 +480,9 @@
 
 [[package]]
 name = "cc"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
+checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
 dependencies = [
  "shlex",
 ]
@@ -544,7 +544,7 @@
  "num-traits",
  "serde",
  "wasm-bindgen",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -571,9 +571,9 @@
 
 [[package]]
 name = "clap"
-version = "4.5.20"
+version = "4.5.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
+checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -581,14 +581,14 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.5.20"
+version = "4.5.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
+checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
 dependencies = [
  "anstream",
  "anstyle",
  "clap_lex",
- "strsim 0.11.1",
+ "strsim",
  "terminal_size",
  "unicase",
  "unicode-width 0.2.0",
@@ -596,9 +596,9 @@
 
 [[package]]
 name = "clap_complete"
-version = "4.5.37"
+version = "4.5.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11611dca53440593f38e6b25ec629de50b14cdfa63adc0fb856115a2c6d97595"
+checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01"
 dependencies = [
  "clap",
 ]
@@ -617,9 +617,9 @@
 
 [[package]]
 name = "clap_lex"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
 
 [[package]]
 name = "colorchoice"
@@ -636,7 +636,7 @@
  "encode_unicode",
  "lazy_static",
  "libc",
- "unicode-width 0.1.14",
+ "unicode-width 0.1.11",
  "windows-sys 0.52.0",
 ]
 
@@ -677,17 +677,23 @@
 ]
 
 [[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
 name = "crossterm"
-version = "0.27.0"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
+checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
 dependencies = [
  "bitflags",
  "crossterm_winapi",
  "filedescriptor",
- "libc",
- "mio 0.8.11",
+ "mio",
  "parking_lot",
+ "rustix",
  "signal-hook",
  "signal-hook-mio",
  "winapi",
@@ -751,11 +757,12 @@
 
 [[package]]
 name = "dashmap"
-version = "5.5.3"
+version = "6.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
+checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
 dependencies = [
  "cfg-if",
+ "crossbeam-utils",
  "hashbrown 0.14.5",
  "lock_api",
  "once_cell",
@@ -921,7 +928,7 @@
  "nix-eval",
  "nixlike",
  "nom",
- "openssh 0.10.5",
+ "openssh",
  "owo-colors",
  "peg",
  "regex",
@@ -954,7 +961,7 @@
  "nix-eval",
  "nixlike",
  "nom",
- "openssh 0.11.3",
+ "openssh",
  "serde",
  "serde_json",
  "tempfile",
@@ -1418,9 +1425,9 @@
 
 [[package]]
 name = "i18n-embed"
-version = "0.14.1"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94205d95764f5bb9db9ea98fa77f89653365ca748e27161f5bbea2ffd50e459c"
+checksum = "a7839d8c7bb8da7bd58c1112d3a1aeb7f178ff3df4ae87783e758ca3bfb750b7"
 dependencies = [
  "arc-swap",
  "fluent",
@@ -1439,9 +1446,9 @@
 
 [[package]]
 name = "i18n-embed-fl"
-version = "0.7.0"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc1f8715195dffc4caddcf1cf3128da15fe5d8a137606ea8856c9300047d5a2"
+checksum = "f6e9571c3cba9eba538eaa5ee40031b26debe76f0c7e17bafc97ea57a76cd82e"
 dependencies = [
  "dashmap",
  "find-crate",
@@ -1450,10 +1457,10 @@
  "i18n-config",
  "i18n-embed",
  "lazy_static",
- "proc-macro-error",
+ "proc-macro-error2",
  "proc-macro2",
  "quote",
- "strsim 0.10.0",
+ "strsim",
  "syn 2.0.87",
  "unic-langid",
 ]
@@ -1636,9 +1643,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.162"
+version = "0.2.164"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
+checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
 
 [[package]]
 name = "libloading"
@@ -1647,7 +1654,7 @@
 checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -1752,18 +1759,6 @@
 checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
 dependencies = [
  "adler2",
-]
-
-[[package]]
-name = "mio"
-version = "0.8.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
-dependencies = [
- "libc",
- "log",
- "wasi",
- "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -1774,6 +1769,7 @@
 dependencies = [
  "hermit-abi 0.3.9",
  "libc",
+ "log",
  "wasi",
  "windows-sys 0.52.0",
 ]
@@ -1956,21 +1952,6 @@
 version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
-
-[[package]]
-name = "openssh"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "330f4b61092456dc0aaa0cf9a205d956cae07d8127a69ffeff6760a72549c77f"
-dependencies = [
- "libc",
- "once_cell",
- "shell-escape",
- "tempfile",
- "thiserror 1.0.69",
- "tokio",
- "tokio-pipe",
-]
 
 [[package]]
 name = "openssh"
@@ -2004,13 +1985,13 @@
 
 [[package]]
 name = "papergrid"
-version = "0.11.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb"
+checksum = "c7419ad52a7de9b60d33e11085a0fe3df1fbd5926aa3f93d3dd53afbc9e86725"
 dependencies = [
  "bytecount",
  "fnv",
- "unicode-width 0.1.14",
+ "unicode-width 0.1.11",
 ]
 
 [[package]]
@@ -2033,7 +2014,7 @@
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -2243,6 +2224,28 @@
 ]
 
 [[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
 name = "proc-macro2"
 version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2583,9 +2586,9 @@
 
 [[package]]
 name = "rustls"
-version = "0.23.16"
+version = "0.23.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
+checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e"
 dependencies = [
  "log",
  "once_cell",
@@ -2680,9 +2683,9 @@
 
 [[package]]
 name = "secrecy"
-version = "0.8.0"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
+checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a"
 dependencies = [
  "zeroize",
 ]
@@ -2748,9 +2751,9 @@
 
 [[package]]
 name = "serde_json"
-version = "1.0.132"
+version = "1.0.133"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
 dependencies = [
  "itoa",
  "memchr",
@@ -2807,7 +2810,7 @@
 checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
 dependencies = [
  "libc",
- "mio 0.8.11",
+ "mio",
  "signal-hook",
 ]
 
@@ -2882,12 +2885,6 @@
 
 [[package]]
 name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
@@ -2953,20 +2950,19 @@
 
 [[package]]
 name = "tabled"
-version = "0.15.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e"
+checksum = "77c9303ee60b9bedf722012ea29ae3711ba13a67c9b9ae28993838b63057cb1b"
 dependencies = [
  "papergrid",
  "tabled_derive",
- "unicode-width 0.1.14",
 ]
 
 [[package]]
 name = "tabled_derive"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c138f99377e5d653a371cdad263615634cfc8467685dfe8e73e2b8e98f44b17"
+checksum = "bf0fb8bfdc709786c154e24a66777493fb63ae97e3036d914c8666774c477069"
 dependencies = [
  "heck 0.4.1",
  "proc-macro-error",
@@ -3141,7 +3137,7 @@
  "backtrace",
  "bytes",
  "libc",
- "mio 1.0.2",
+ "mio",
  "pin-project-lite",
  "signal-hook-registry",
  "socket2",
@@ -3161,16 +3157,6 @@
 ]
 
 [[package]]
-name = "tokio-pipe"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f213a84bffbd61b8fa0ba8a044b4bbe35d471d0b518867181e82bd5c15542784"
-dependencies = [
- "libc",
- "tokio",
-]
-
-[[package]]
 name = "tokio-rustls"
 version = "0.26.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3464,9 +3450,9 @@
 
 [[package]]
 name = "unicode-width"
-version = "0.1.14"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
 
 [[package]]
 name = "unicode-width"
@@ -3528,7 +3514,7 @@
 dependencies = [
  "itoa",
  "log",
- "unicode-width 0.1.14",
+ "unicode-width 0.1.11",
  "vte",
 ]
 
@@ -3693,7 +3679,7 @@
 checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 dependencies = [
  "windows-core",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -3702,25 +3688,16 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
 name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -3729,22 +3706,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -3753,33 +3715,21 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -3789,12 +3739,6 @@
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
@@ -3804,24 +3748,12 @@
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
 name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -3831,21 +3763,9 @@
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
 name = "windows_x86_64_msvc"
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,7 +20,7 @@
 tokio-util = { version = "0.7.11", features = ["codec"] }
 clap = { version = "4.5", features = ["derive", "env", "wrap_help", "unicode"] }
 clap_complete = "4.5"
-age = { version = "0.10", features = ["ssh"] }
+age = { version = "0.11", features = ["ssh"] }
 anyhow = "1.0"
 tracing = "0.1"
 tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
modifiedcmds/fleet/Cargo.tomldiffbeforeafterboth
--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -20,7 +20,7 @@
 tempfile.workspace = true
 time = { version = "0.3", features = ["serde"] }
 hostname = "0.4.0"
-age-core = "0.10"
+age-core = "0.11"
 peg = "0.8"
 base64 = "0.22.1"
 chrono = { version = "0.4", features = ["serde"] }
@@ -29,15 +29,15 @@
 futures = "0.3"
 itertools = "0.13"
 shlex = "1.3"
-tabled = { version = "0.15" }
+tabled = { version = "0.16" }
 owo-colors = { version = "4.0", features = [
 	"supports-color",
 	"supports-colors",
 ] }
 abort-on-drop = "0.2"
 regex = "1.10"
-openssh = "0.10"
-crossterm = { version = "0.27.0", features = ["use-dev-tty"] }
+openssh = "0.11"
+crossterm = { version = "0.28.0", features = ["use-dev-tty"] }
 fleet-shared.workspace = true
 
 tracing-indicatif = { version = "0.3", optional = true }
modifiedcmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -4,6 +4,7 @@
 	path::PathBuf,
 };
 
+use age::Recipient;
 use anyhow::{anyhow, bail, ensure, Context, Result};
 use chrono::{DateTime, Utc};
 use clap::Parser;
@@ -161,7 +162,8 @@
 
 	if should_regenerate {
 		info!("secret is owner-dependent, will regenerate");
-		let generated = generate_shared(config, secret_name, field, updated_set.to_vec(), batch).await?;
+		let generated =
+			generate_shared(config, secret_name, field, updated_set.to_vec(), batch).await?;
 		Ok(generated)
 	} else {
 		drop(batch);
@@ -487,8 +489,9 @@
 				io::stdin().read_to_end(&mut input)?;
 
 				if !input.is_empty() {
-					let encrypted = encrypt_secret_data(recipients, input)
-						.ok_or_else(|| anyhow!("no recipients provided"))?;
+					let encrypted =
+						encrypt_secret_data(recipients.iter().map(|r| r as &dyn Recipient), input)
+							.ok_or_else(|| anyhow!("no recipients provided"))?;
 					parts.insert(part_name, FleetSecretPart { raw: encrypted });
 				}
 
@@ -536,8 +539,8 @@
 
 				if let Some(secret) = parse_secret().await? {
 					let recipient = config.recipient(&machine).await?;
-					let encrypted =
-						encrypt_secret_data(vec![recipient], secret).expect("recipient provided");
+					let encrypted = encrypt_secret_data([&recipient as &dyn Recipient], secret)
+						.expect("recipient provided");
 					if out
 						.parts
 						.insert(part_name.clone(), FleetSecretPart { raw: encrypted })
modifiedcmds/generator-helper/src/main.rsdiffbeforeafterboth
before · cmds/generator-helper/src/main.rs
1use std::{2	env,3	fs::{File, OpenOptions},4	io::{self, copy, stdin, stdout, Read, Write},5	str::FromStr,6};78use age::{9	ssh::{ParseRecipientKeyError, Recipient as SshRecipient},10	Encryptor, Recipient,11};12use anyhow::{anyhow, bail, ensure, Context, Result};13use clap::{Parser, ValueEnum};14use fleet_shared::SecretData;15use rand::{16	distributions::{Alphanumeric, DistString, Distribution, Uniform},17	thread_rng, RngCore,18};1920fn write_output_file(out: &str) -> Result<File> {21	let file = OpenOptions::new()22		.create_new(true)23		.write(true)24		.open(out)25		.with_context(|| format!("failed to open output {out:?}"))?;26	Ok(file)27}28fn write_public(out: &str, mut input: impl Read, encoding: OutputEncoding) -> Result<()> {29	let mut output = write_output_file(out)?;3031	let mut data = Vec::new();32	copy(&mut input, &mut wrap_encoder(&mut data, encoding))?;3334	output.write_all(35		SecretData {36			data,37			encrypted: false,38		}39		.to_string()40		.as_bytes(),41	)?;42	Ok(())43}44fn write_private(45	identities: &Identities,46	out: &str,47	mut input: impl Read,48	encoding: OutputEncoding,49) -> Result<()> {50	let mut output = write_output_file(out)?;51	let encryptor = make_encryptor(identities)?;5253	let mut data = Vec::new();54	{55		let mut encrypted_writer = encryptor.wrap_output(&mut data)?;56		copy(57			&mut input,58			&mut wrap_encoder(&mut encrypted_writer, encoding),59		)?;60		encrypted_writer.finish()?;61	};6263	output.write_all(64		SecretData {65			data,66			encrypted: true,67		}68		.to_string()69		.as_bytes(),70	)?;71	Ok(())72}7374type Identities = Vec<SshRecipient>;75fn load_identities() -> Result<Identities> {76	let list = env::var("GENERATOR_HELPER_IDENTITIES");77	let list = match list {78		Ok(v) => v,79		Err(env::VarError::NotPresent) => {80			bail!("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");81		}82		Err(e) => bail!("somehow, identities list is not utf-8: {e}"),83	};84	let list = list.trim();85	ensure!(!list.is_empty(), "no identities passed, can't encrypt data");86	list.lines()87		.map(age::ssh::Recipient::from_str)88		.collect::<Result<Identities, ParseRecipientKeyError>>()89		.map_err(|e| anyhow!("parse recipients: {e:?}"))90}91fn make_encryptor(r: &Identities) -> Result<Encryptor> {92	Ok(Encryptor::with_recipients(93		r.iter()94			.map(|v| {95				let coerced: Box<dyn Recipient + Send> = Box::new(v.clone());96				coerced97			})98			.collect(),99	)100	.expect("list is not empty"))101}102fn wrap_encoder<'t>(w: impl Write + 't, encoding: OutputEncoding) -> impl Write + 't {103	fn coerce<'t>(w: impl Write + 't) -> Box<dyn Write + 't> {104		Box::new(w)105	}106	match encoding {107		OutputEncoding::Raw => coerce(w),108		OutputEncoding::Base64 => {109			use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};110111			let writer = EncoderWriter::new(w, &STANDARD);112			coerce(writer)113		}114		OutputEncoding::Hex => {115			struct HexWriter<W>(W);116			impl<W> Write for HexWriter<W>117			where118				W: Write,119			{120				fn write(&mut self, buf: &[u8]) -> io::Result<usize> {121					let encoded = hex::encode(buf);122					self.0.write_all(encoded.as_bytes())?;123					Ok(buf.len())124				}125126				fn flush(&mut self) -> io::Result<()> {127					self.0.flush()128				}129			}130			coerce(HexWriter(w))131		}132	}133}134135#[derive(Clone, Copy, ValueEnum, Default)]136enum OutputEncoding {137	/// Do not encode data, store as is.138	#[default]139	Raw,140	/// Encode as base64 (with padding).141	Base64,142	/// Encode as hex (without leading 0x)143	Hex,144}145146#[derive(Parser)]147enum Generate {148	/// Generate public, private keys without wrapping, in standard ed25519 schema149	/// (64 bytes private (due to merge with private), 32 bytes public)150	Ed25519 {151		#[arg(long, short = 'p')]152		public: String,153		#[arg(long, short = 's')]154		private: String,155		/// Private key should be just the private key (32 bytes), not standard private+public.156		#[arg(long)]157		no_embed_public: bool,158		#[arg(long, short = 'e', value_enum, default_value_t)]159		encoding: OutputEncoding,160	},161	/// Generate public, private keys without wrapping, in standard x25519 schema162	/// (32 bytes private, 32 bytes public)163	X25519 {164		#[arg(long, short = 'p')]165		public: String,166		#[arg(long, short = 's')]167		private: String,168		#[arg(long, short = 'e', value_enum, default_value_t)]169		encoding: OutputEncoding,170	},171	Password {172		#[arg(long, short = 'o')]173		output: String,174		#[arg(long)]175		size: usize,176		#[arg(long, short = 'n')]177		no_symbols: bool,178		#[arg(long, short = 'e', value_enum, default_value_t)]179		encoding: OutputEncoding,180	},181	Bytes {182		#[arg(long, short = 'o')]183		output: String,184		#[arg(long, short = 'c')]185		count: usize,186		/// Ensure there is no NULs in bytestring.187		#[arg(long)]188		no_nuls: bool,189		#[arg(long, short = 'e', value_enum, default_value_t)]190		encoding: OutputEncoding,191	},192}193194#[derive(Parser)]195enum Opts {196	/// Encode public part from stdin.197	Public {198		#[arg(long, short = 'o')]199		output: String,200		#[arg(long, short = 'e', value_enum, default_value_t)]201		encoding: OutputEncoding,202	},203	/// Encrypt private part from stdin.204	Private {205		#[arg(long, short = 'o')]206		output: String,207		#[arg(long, short = 'e', value_enum, default_value_t)]208		encoding: OutputEncoding,209	},210	/// Sometimes you also need to reencode secret, this command allows you to get raw data from211	/// secret encoded using `gh public`... I would like if I knew a better design for some sort of212	/// such thing. Ideally there should be no need to decode secrets back, but garage wants both213	/// raw pubkey and raw secret key, yet also requires node id which is hex-reencoded public key.214	Decode {215		#[arg(long, short = 'i')]216		input: String,217	},218	/// Generate keys in well-known schemas.219	///220	/// Note that this command is only intended to be used in fleet secret generator,221	/// otherwise you should ensure noone is able to read generated files, they don't have any mode set by default.222	///223	/// Fleet also doesn't zeroize memory/assumes good OsRng/makes other assumptions, which makes it only suitable to224	/// be used in nix sandbox.225	#[command(subcommand)]226	Generate(Generate),227}228229fn main() -> Result<()> {230	let opts = Opts::parse();231	// Assumed to be secure, seeded from secure OsRng+reseeded.232	let mut rng = thread_rng();233234	match opts {235		Opts::Public { output, encoding } => {236			write_public(&output, stdin(), encoding)?;237		}238		Opts::Private { output, encoding } => {239			let recipients = load_identities()?;240			write_private(&recipients, &output, stdin(), encoding)?;241		}242		Opts::Generate(gen) => {243			match gen {244				Generate::Ed25519 {245					public,246					private,247					no_embed_public,248					encoding,249				} => {250					use ed25519_dalek::SigningKey;251252					let recipients = load_identities()?;253					let key = SigningKey::generate(&mut rng).to_keypair_bytes();254					write_public(&public, &key[32..], encoding)?;255					write_private(256						&recipients,257						&private,258						&key[..{259							if no_embed_public {260								32261							} else {262								64263							}264						}],265						encoding,266					)?;267				}268				Generate::X25519 {269					public,270					private,271					encoding,272				} => {273					use x25519_dalek::{PublicKey, StaticSecret};274275					let recipients = load_identities()?;276					let key = StaticSecret::random_from_rng(rng);277					let public_key: PublicKey = (&key).into();278					write_public(&public, public_key.as_bytes().as_slice(), encoding)?;279					write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;280				}281				Generate::Password {282					size,283					no_symbols,284					output,285					encoding,286				} => {287					ensure!(288						size >= 6,289						"misconfiguration? password is shorter than 6 chars"290					);291					let recipients = load_identities()?;292					let out = if no_symbols {293						Alphanumeric.sample_string(&mut rng, size)294					} else {295						// Alphabet of Alphanumberic + symbols296						const GEN_ASCII_SYMBOLS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";297						let uniform = Uniform::new(0, GEN_ASCII_SYMBOLS.len());298						(0..size)299							.map(|_| uniform.sample(&mut rng))300							.map(|i| GEN_ASCII_SYMBOLS[i] as char)301							.collect::<String>()302					};303					write_private(&recipients, &output, out.as_bytes(), encoding)?;304				}305				Generate::Bytes {306					output,307					count,308					no_nuls,309					encoding,310				} => {311					ensure!(312						count >= 6,313						"misconfiguration? bytestring is shorter than 6 chars"314					);315					let recipients = load_identities()?;316					let mut bytes = vec![0u8; count];317					if no_nuls {318						let rand = Uniform::new_inclusive(0x1u8, 0xffu8).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, copy, stdin, stdout, Read, Write},5	str::FromStr,6};78use age::{9	ssh::{ParseRecipientKeyError, Recipient as SshRecipient},10	Encryptor, Recipient,11};12use anyhow::{anyhow, bail, ensure, Context, Result};13use clap::{Parser, ValueEnum};14use fleet_shared::SecretData;15use rand::{16	distributions::{Alphanumeric, DistString, Distribution, Uniform},17	thread_rng, RngCore,18};1920fn write_output_file(out: &str) -> Result<File> {21	let file = OpenOptions::new()22		.create_new(true)23		.write(true)24		.open(out)25		.with_context(|| format!("failed to open output {out:?}"))?;26	Ok(file)27}28fn write_public(out: &str, mut input: impl Read, encoding: OutputEncoding) -> Result<()> {29	let mut output = write_output_file(out)?;3031	let mut data = Vec::new();32	copy(&mut input, &mut wrap_encoder(&mut data, encoding))?;3334	output.write_all(35		SecretData {36			data,37			encrypted: false,38		}39		.to_string()40		.as_bytes(),41	)?;42	Ok(())43}44fn write_private(45	identities: &Identities,46	out: &str,47	mut input: impl Read,48	encoding: OutputEncoding,49) -> Result<()> {50	let mut output = write_output_file(out)?;51	let encryptor = make_encryptor(identities)?;5253	let mut data = Vec::new();54	{55		let mut encrypted_writer = encryptor.wrap_output(&mut data)?;56		copy(57			&mut input,58			&mut wrap_encoder(&mut encrypted_writer, encoding),59		)?;60		encrypted_writer.finish()?;61	};6263	output.write_all(64		SecretData {65			data,66			encrypted: true,67		}68		.to_string()69		.as_bytes(),70	)?;71	Ok(())72}7374type Identities = Vec<SshRecipient>;75fn load_identities() -> Result<Identities> {76	let list = env::var("GENERATOR_HELPER_IDENTITIES");77	let list = match list {78		Ok(v) => v,79		Err(env::VarError::NotPresent) => {80			bail!("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");81		}82		Err(e) => bail!("somehow, identities list is not utf-8: {e}"),83	};84	let list = list.trim();85	ensure!(!list.is_empty(), "no identities passed, can't encrypt data");86	list.lines()87		.map(age::ssh::Recipient::from_str)88		.collect::<Result<Identities, ParseRecipientKeyError>>()89		.map_err(|e| anyhow!("parse recipients: {e:?}"))90}91fn make_encryptor(r: &Identities) -> Result<Encryptor> {92	Ok(93		Encryptor::with_recipients(r.iter().map(|v| v as &dyn Recipient))94			.expect("list is not empty"),95	)96}97fn wrap_encoder<'t>(w: impl Write + 't, encoding: OutputEncoding) -> impl Write + 't {98	fn coerce<'t>(w: impl Write + 't) -> Box<dyn Write + 't> {99		Box::new(w)100	}101	match encoding {102		OutputEncoding::Raw => coerce(w),103		OutputEncoding::Base64 => {104			use base64::{engine::general_purpose::STANDARD, write::EncoderWriter};105106			let writer = EncoderWriter::new(w, &STANDARD);107			coerce(writer)108		}109		OutputEncoding::Hex => {110			struct HexWriter<W>(W);111			impl<W> Write for HexWriter<W>112			where113				W: Write,114			{115				fn write(&mut self, buf: &[u8]) -> io::Result<usize> {116					let encoded = hex::encode(buf);117					self.0.write_all(encoded.as_bytes())?;118					Ok(buf.len())119				}120121				fn flush(&mut self) -> io::Result<()> {122					self.0.flush()123				}124			}125			coerce(HexWriter(w))126		}127	}128}129130#[derive(Clone, Copy, ValueEnum, Default)]131enum OutputEncoding {132	/// Do not encode data, store as is.133	#[default]134	Raw,135	/// Encode as base64 (with padding).136	Base64,137	/// Encode as hex (without leading 0x)138	Hex,139}140141#[derive(Parser)]142enum Generate {143	/// Generate public, private keys without wrapping, in standard ed25519 schema144	/// (64 bytes private (due to merge with private), 32 bytes public)145	Ed25519 {146		#[arg(long, short = 'p')]147		public: String,148		#[arg(long, short = 's')]149		private: String,150		/// Private key should be just the private key (32 bytes), not standard private+public.151		#[arg(long)]152		no_embed_public: bool,153		#[arg(long, short = 'e', value_enum, default_value_t)]154		encoding: OutputEncoding,155	},156	/// Generate public, private keys without wrapping, in standard x25519 schema157	/// (32 bytes private, 32 bytes public)158	X25519 {159		#[arg(long, short = 'p')]160		public: String,161		#[arg(long, short = 's')]162		private: String,163		#[arg(long, short = 'e', value_enum, default_value_t)]164		encoding: OutputEncoding,165	},166	Password {167		#[arg(long, short = 'o')]168		output: String,169		#[arg(long)]170		size: usize,171		#[arg(long, short = 'n')]172		no_symbols: bool,173		#[arg(long, short = 'e', value_enum, default_value_t)]174		encoding: OutputEncoding,175	},176	Bytes {177		#[arg(long, short = 'o')]178		output: String,179		#[arg(long, short = 'c')]180		count: usize,181		/// Ensure there is no NULs in bytestring.182		#[arg(long)]183		no_nuls: bool,184		#[arg(long, short = 'e', value_enum, default_value_t)]185		encoding: OutputEncoding,186	},187}188189#[derive(Parser)]190enum Opts {191	/// Encode public part from stdin.192	Public {193		#[arg(long, short = 'o')]194		output: String,195		#[arg(long, short = 'e', value_enum, default_value_t)]196		encoding: OutputEncoding,197	},198	/// Encrypt private part from stdin.199	Private {200		#[arg(long, short = 'o')]201		output: String,202		#[arg(long, short = 'e', value_enum, default_value_t)]203		encoding: OutputEncoding,204	},205	/// Sometimes you also need to reencode secret, this command allows you to get raw data from206	/// secret encoded using `gh public`... I would like if I knew a better design for some sort of207	/// such thing. Ideally there should be no need to decode secrets back, but garage wants both208	/// raw pubkey and raw secret key, yet also requires node id which is hex-reencoded public key.209	Decode {210		#[arg(long, short = 'i')]211		input: String,212	},213	/// Generate keys in well-known schemas.214	///215	/// Note that this command is only intended to be used in fleet secret generator,216	/// otherwise you should ensure noone is able to read generated files, they don't have any mode set by default.217	///218	/// Fleet also doesn't zeroize memory/assumes good OsRng/makes other assumptions, which makes it only suitable to219	/// be used in nix sandbox.220	#[command(subcommand)]221	Generate(Generate),222}223224fn main() -> Result<()> {225	let opts = Opts::parse();226	// Assumed to be secure, seeded from secure OsRng+reseeded.227	let mut rng = thread_rng();228229	match opts {230		Opts::Public { output, encoding } => {231			write_public(&output, stdin(), encoding)?;232		}233		Opts::Private { output, encoding } => {234			let recipients = load_identities()?;235			write_private(&recipients, &output, stdin(), encoding)?;236		}237		Opts::Generate(gen) => {238			match gen {239				Generate::Ed25519 {240					public,241					private,242					no_embed_public,243					encoding,244				} => {245					use ed25519_dalek::SigningKey;246247					let recipients = load_identities()?;248					let key = SigningKey::generate(&mut rng).to_keypair_bytes();249					write_public(&public, &key[32..], encoding)?;250					write_private(251						&recipients,252						&private,253						&key[..{254							if no_embed_public {255								32256							} else {257								64258							}259						}],260						encoding,261					)?;262				}263				Generate::X25519 {264					public,265					private,266					encoding,267				} => {268					use x25519_dalek::{PublicKey, StaticSecret};269270					let recipients = load_identities()?;271					let key = StaticSecret::random_from_rng(rng);272					let public_key: PublicKey = (&key).into();273					write_public(&public, public_key.as_bytes().as_slice(), encoding)?;274					write_private(&recipients, &private, key.as_bytes().as_slice(), encoding)?;275				}276				Generate::Password {277					size,278					no_symbols,279					output,280					encoding,281				} => {282					ensure!(283						size >= 6,284						"misconfiguration? password is shorter than 6 chars"285					);286					let recipients = load_identities()?;287					let out = if no_symbols {288						Alphanumeric.sample_string(&mut rng, size)289					} else {290						// Alphabet of Alphanumberic + symbols291						const GEN_ASCII_SYMBOLS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";292						let uniform = Uniform::new(0, GEN_ASCII_SYMBOLS.len());293						(0..size)294							.map(|_| uniform.sample(&mut rng))295							.map(|i| GEN_ASCII_SYMBOLS[i] as char)296							.collect::<String>()297					};298					write_private(&recipients, &output, out.as_bytes(), encoding)?;299				}300				Generate::Bytes {301					output,302					count,303					no_nuls,304					encoding,305				} => {306					ensure!(307						count >= 6,308						"misconfiguration? bytestring is shorter than 6 chars"309					);310					let recipients = load_identities()?;311					let mut bytes = vec![0u8; count];312					if no_nuls {313						let rand = Uniform::new_inclusive(0x1u8, 0xffu8).sample_iter(&mut rng);314						for (byte, rand) in bytes.iter_mut().zip(rand) {315							*byte = rand;316						}317					} else {318						rng.fill_bytes(&mut bytes);319					};320					write_private(&recipients, &output, bytes.as_slice(), encoding)?;321				}322			}323		}324		Opts::Decode { input } => {325			let mut data = Vec::new();326			File::open(input)?.read_to_end(&mut data)?;327			let data = String::from_utf8(data).context(328				"encoded data is always utf-8, you are trying to use decode the wrong way.",329			)?;330			let data =331				SecretData::from_str(&data).map_err(|e| anyhow!("failed to decode data: {e}"))?;332			ensure!(333				!data.encrypted,334				"you can not decrypt secret data, only decode public."335			);336			stdout().write_all(&data.data)?;337		}338	}339	Ok(())340}
modifiedcmds/install-secrets/src/main.rsdiffbeforeafterboth
--- a/cmds/install-secrets/src/main.rs
+++ b/cmds/install-secrets/src/main.rs
@@ -68,10 +68,9 @@
 	ensure!(input.encrypted, "passed data is not encrypted!");
 	let mut input = Cursor::new(&input.data);
 	let decryptor = Decryptor::new(&mut input).context("failed to init decryptor")?;
-	let decryptor = match decryptor {
-		Decryptor::Recipients(r) => r,
-		Decryptor::Passphrase(_) => bail!("should be recipients"),
-	};
+	if decryptor.is_scrypt() {
+		bail!("should be recipients");
+	}
 	let mut decryptor = decryptor
 		.decrypt(iter::once(identity as &dyn age::Identity))
 		.context("failed to decrypt, wrong key?")?;
@@ -89,10 +88,7 @@
 			SshRecipient::from_str(&t).map_err(|e| anyhow!("failed to parse recipient: {e:?}"))
 		})
 		.collect::<Result<Vec<SshRecipient>>>()?;
-	let recipients = recipients
-		.into_iter()
-		.map(|v| Box::new(v) as Box<dyn Recipient + Send>)
-		.collect::<Vec<_>>();
+	let recipients = recipients.iter().map(|v| v as &dyn Recipient);
 	let mut encrypted = vec![];
 	let mut encryptor = Encryptor::with_recipients(recipients)
 		.expect("recipients provided")
modifiedcrates/fleet-base/src/fleetdata.rsdiffbeforeafterboth
--- a/crates/fleet-base/src/fleetdata.rs
+++ b/crates/fleet-base/src/fleetdata.rs
@@ -6,7 +6,6 @@
 use age::Recipient;
 use chrono::{DateTime, Utc};
 use fleet_shared::SecretData;
-use itertools::Itertools;
 use serde::{de::Error, Deserialize, Serialize};
 use serde_json::Value;
 
@@ -73,16 +72,13 @@
 }
 
 /// Returns None if recipients.is_empty()
-pub fn encrypt_secret_data(
-	recipients: impl IntoIterator<Item = impl Recipient + Send + 'static>,
+pub fn encrypt_secret_data<'a>(
+	recipients: impl IntoIterator<Item = &'a dyn Recipient>,
 	data: Vec<u8>,
 ) -> Option<SecretData> {
 	let mut encrypted = vec![];
-	let recipients = recipients
-		.into_iter()
-		.map(|v| Box::new(v) as Box<dyn Recipient + Send>)
-		.collect_vec();
-	let mut encryptor = age::Encryptor::with_recipients(recipients)?
+	let mut encryptor = age::Encryptor::with_recipients(recipients.into_iter())
+		.ok()?
 		.wrap_output(&mut encrypted)
 		.expect("in memory write");
 	io::copy(&mut Cursor::new(data), &mut encryptor).expect("in memory copy");
modifiedflake.lockdiffbeforeafterboth
--- a/flake.lock
+++ b/flake.lock
@@ -37,11 +37,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1731514040,
-        "narHash": "sha256-4VkY8gwyR83N6MPT7ipXTOSBXpVL2Hrwh898UAR3HZ8=",
+        "lastModified": 1731873344,
+        "narHash": "sha256-bKfFggwcvvh9gmOsaMCXKVAGBfXCZZ6QrxLq9Nb1/vw=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "155168226cb666d242306e13d7dbdaa8a76d20e1",
+        "rev": "39e98fadd66c2564ac85b1f65bab89e044302c62",
         "type": "github"
       },
       "original": {
@@ -66,11 +66,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1731464916,
-        "narHash": "sha256-WZ5rpjr/wCt7yBOUsvDE2i22hYz9g8W921jlwVktRQ4=",
+        "lastModified": 1731820690,
+        "narHash": "sha256-/hHFMTD+FGURXZ4JtfXoIgpy87zL505pVi6AL76Wc+U=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "2c19bad6e881b5a154cafb7f9106879b5b356d1f",
+        "rev": "bbab2ab9e1932133b1996baa1dc00fefe924ca81",
         "type": "github"
       },
       "original": {
modifiedmodules/secrets.nixdiffbeforeafterboth
--- a/modules/secrets.nix
+++ b/modules/secrets.nix
@@ -1,4 +1,8 @@
-{lib, config, ...}: let
+{
+  lib,
+  config,
+  ...
+}: let
   inherit (lib.options) mkOption;
   inherit (lib.types) unspecified nullOr listOf str bool attrsOf submodule;
   inherit (lib.strings) concatStringsSep;
@@ -51,9 +55,11 @@
     };
   };
   config = {
-    hosts = mapAttrs (_: secretMap: {
-      nixos.secrets = mapAttrs (_: s: removeAttrs s ["createdAt" "expiresAt"]) secretMap;
-    }) config.data.hostSecrets;
+    hosts =
+      mapAttrs (_: secretMap: {
+        nixos.secrets = mapAttrs (_: s: removeAttrs s ["createdAt" "expiresAt"]) secretMap;
+      })
+      config.data.hostSecrets;
     nixpkgs.overlays = [
       (final: prev: {
         mkSecretGenerators = {recipients}: rec {