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

difftreelog

refactor temporarly break cross, but greatly cleanup data

Yaroslav Bolyukin2023-12-31parent: #7c6930a.patch.diff
in: trunk

16 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -117,9 +117,9 @@
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 dependencies = [
  "memchr",
 ]
@@ -170,9 +170,9 @@
 
 [[package]]
 name = "anstream"
-version = "0.6.4"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
+checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -190,37 +190,37 @@
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
+checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.0.0"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.1"
+version = "3.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
+checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
 dependencies = [
  "anstyle",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.75"
+version = "1.0.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9"
 
 [[package]]
 name = "arc-swap"
@@ -242,13 +242,13 @@
 
 [[package]]
 name = "async-trait"
-version = "0.1.74"
+version = "0.1.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
+checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -387,9 +387,9 @@
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
@@ -482,9 +482,9 @@
 
 [[package]]
 name = "clap"
-version = "4.4.7"
+version = "4.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
+checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -492,9 +492,9 @@
 
 [[package]]
 name = "clap_builder"
-version = "4.4.7"
+version = "4.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
+checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
 dependencies = [
  "anstream",
  "anstyle",
@@ -514,7 +514,7 @@
  "heck",
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -544,9 +544,9 @@
 
 [[package]]
 name = "const-oid"
-version = "0.9.5"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
 
 [[package]]
 name = "cookie-factory"
@@ -556,9 +556,9 @@
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.4"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
 
 [[package]]
 name = "countme"
@@ -568,9 +568,9 @@
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
 dependencies = [
  "libc",
 ]
@@ -615,7 +615,7 @@
 checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
 dependencies = [
  "cfg-if",
- "hashbrown 0.14.1",
+ "hashbrown 0.14.3",
  "lock_api",
  "once_cell",
  "parking_lot_core",
@@ -633,9 +633,9 @@
 
 [[package]]
 name = "deranged"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
 dependencies = [
  "powerfmt",
  "serde",
@@ -691,7 +691,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -708,9 +708,9 @@
 
 [[package]]
 name = "env_logger"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
 dependencies = [
  "humantime",
  "is-terminal",
@@ -727,12 +727,12 @@
 
 [[package]]
 name = "errno"
-version = "0.3.5"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
 dependencies = [
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -752,7 +752,7 @@
 
 [[package]]
 name = "fleet"
-version = "0.1.0"
+version = "0.2.0"
 dependencies = [
  "abort-on-drop",
  "age",
@@ -827,7 +827,7 @@
  "intl-memoizer",
  "intl_pluralrules",
  "rustc-hash",
- "self_cell",
+ "self_cell 0.10.3",
  "smallvec",
  "unic-langid",
 ]
@@ -858,9 +858,9 @@
 
 [[package]]
 name = "futures"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -873,9 +873,9 @@
 
 [[package]]
 name = "futures-channel"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -883,15 +883,15 @@
 
 [[package]]
 name = "futures-core"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -900,38 +900,38 @@
 
 [[package]]
 name = "futures-io"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
 
 [[package]]
 name = "futures-task"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 
 [[package]]
 name = "futures-util"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -968,9 +968,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
 dependencies = [
  "cfg-if",
  "libc",
@@ -989,9 +989,9 @@
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "hashbrown"
@@ -1001,9 +1001,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.14.1"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
 
 [[package]]
 name = "heck"
@@ -1028,9 +1028,9 @@
 
 [[package]]
 name = "hkdf"
-version = "0.12.3"
+version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
+checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
 dependencies = [
  "hmac",
 ]
@@ -1077,7 +1077,7 @@
  "serde",
  "serde_derive",
  "thiserror",
- "toml 0.8.0",
+ "toml 0.8.8",
  "unic-langid",
 ]
 
@@ -1119,35 +1119,35 @@
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.38",
+ "syn 2.0.43",
  "unic-langid",
 ]
 
 [[package]]
 name = "i18n-embed-impl"
-version = "0.8.2"
+version = "0.8.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2a4d5bff745c9a6e1459c490059281b353a4ab0a4e1e58b3eeeaef71f97d07b"
+checksum = "81093c4701672f59416582fe3145676126fd23ba5db910acad0793c1108aaa58"
 dependencies = [
  "find-crate",
  "i18n-config",
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.57"
+version = "0.1.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
+checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
- "windows",
+ "windows-core",
 ]
 
 [[package]]
@@ -1161,12 +1161,12 @@
 
 [[package]]
 name = "indexmap"
-version = "2.0.2"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
+checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.1",
+ "hashbrown 0.14.3",
 ]
 
 [[package]]
@@ -1229,13 +1229,13 @@
 
 [[package]]
 name = "is-terminal"
-version = "0.4.9"
+version = "0.4.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
+checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
 dependencies = [
  "hermit-abi 0.3.3",
  "rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -1255,15 +1255,15 @@
 
 [[package]]
 name = "itoa"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -1279,15 +1279,15 @@
 
 [[package]]
 name = "libc"
-version = "0.2.149"
+version = "0.2.151"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
 
 [[package]]
 name = "libm"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
 [[package]]
 name = "libmimalloc-sys"
@@ -1307,7 +1307,7 @@
 dependencies = [
  "bitflags 2.4.1",
  "libc",
- "redox_syscall 0.4.1",
+ "redox_syscall",
 ]
 
 [[package]]
@@ -1318,15 +1318,15 @@
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.10"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
+checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
 
 [[package]]
 name = "lock_api"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -1355,9 +1355,9 @@
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
 
 [[package]]
 name = "memoffset"
@@ -1394,9 +1394,9 @@
 
 [[package]]
 name = "mio"
-version = "0.8.8"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
 dependencies = [
  "libc",
  "wasi 0.11.0+wasi-snapshot-preview1",
@@ -1514,9 +1514,9 @@
 
 [[package]]
 name = "object"
-version = "0.32.1"
+version = "0.32.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
 dependencies = [
  "memchr",
 ]
@@ -1535,9 +1535,9 @@
 
 [[package]]
 name = "openssh"
-version = "0.10.1"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dfe68c42d6ee6bd9de175b7a5d9bb86aa99d4e2fa7cf2f2a44e97f60b6d2759"
+checksum = "8274f2bf1fc3785406a3ff07c92c15590c00e84efb883da77b671562ca9a6115"
 dependencies = [
  "dirs",
  "libc",
@@ -1595,13 +1595,13 @@
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.8"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.3.5",
+ "redox_syscall",
  "smallvec",
  "windows-targets 0.48.5",
 ]
@@ -1659,7 +1659,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -1721,9 +1721,9 @@
 
 [[package]]
 name = "portable-atomic"
-version = "1.4.3"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
 
 [[package]]
 name = "powerfmt"
@@ -1763,9 +1763,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.69"
+version = "1.0.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
+checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
 dependencies = [
  "unicode-ident",
 ]
@@ -1849,7 +1849,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
 ]
 
 [[package]]
@@ -1859,15 +1859,6 @@
 checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
 dependencies = [
  "rand_core 0.5.1",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
-dependencies = [
- "bitflags 1.3.2",
 ]
 
 [[package]]
@@ -1885,7 +1876,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
 dependencies = [
- "getrandom 0.2.10",
+ "getrandom 0.2.11",
  "libredox",
  "thiserror",
 ]
@@ -2015,7 +2006,7 @@
  "proc-macro2",
  "quote",
  "rust-embed-utils",
- "syn 2.0.38",
+ "syn 2.0.43",
  "walkdir",
 ]
 
@@ -2043,22 +2034,22 @@
 
 [[package]]
 name = "rustix"
-version = "0.38.21"
+version = "0.38.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
+checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
 dependencies = [
  "bitflags 2.4.1",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "ryu"
-version = "1.0.15"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
 
 [[package]]
 name = "salsa20"
@@ -2116,9 +2107,18 @@
 
 [[package]]
 name = "self_cell"
-version = "0.10.2"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
+dependencies = [
+ "self_cell 1.0.3",
+]
+
+[[package]]
+name = "self_cell"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
+checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba"
 
 [[package]]
 name = "serde"
@@ -2146,7 +2146,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -2162,9 +2162,9 @@
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.3"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
 dependencies = [
  "serde",
 ]
@@ -2182,9 +2182,9 @@
 
 [[package]]
 name = "sharded-slab"
-version = "0.1.4"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
 dependencies = [
  "lazy_static",
 ]
@@ -2231,9 +2231,9 @@
 
 [[package]]
 name = "smallvec"
-version = "1.11.1"
+version = "1.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
+checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
 
 [[package]]
 name = "smol_str"
@@ -2246,9 +2246,9 @@
 
 [[package]]
 name = "socket2"
-version = "0.5.4"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
  "windows-sys 0.48.0",
@@ -2305,9 +2305,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.38"
+version = "2.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
+checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2342,22 +2342,22 @@
 
 [[package]]
 name = "tempfile"
-version = "3.8.1"
+version = "3.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
+checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall 0.4.1",
+ "redox_syscall",
  "rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "termcolor"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
+checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
 dependencies = [
  "winapi-util",
 ]
@@ -2380,22 +2380,22 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.50"
+version = "1.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
+checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.50"
+version = "1.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
+checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -2410,9 +2410,9 @@
 
 [[package]]
 name = "time"
-version = "0.3.30"
+version = "0.3.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
+checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e"
 dependencies = [
  "deranged",
  "powerfmt",
@@ -2429,27 +2429,27 @@
 
 [[package]]
 name = "time-macros"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
+checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f"
 dependencies = [
  "time-core",
 ]
 
 [[package]]
 name = "tinystr"
-version = "0.7.2"
+version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8faa444297615a4e020acb64146b0603c9c395c03a97c17fd9028816d3b4d63e"
+checksum = "83c02bf3c538ab32ba913408224323915f4ef9a6d61c0e85d493f355921c0ece"
 dependencies = [
  "displaydoc",
 ]
 
 [[package]]
 name = "tokio"
-version = "1.33.0"
+version = "1.35.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
+checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
 dependencies = [
  "backtrace",
  "bytes",
@@ -2466,13 +2466,13 @@
 
 [[package]]
 name = "tokio-macros"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -2510,9 +2510,9 @@
 
 [[package]]
 name = "toml"
-version = "0.8.0"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e"
+checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2522,18 +2522,18 @@
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.20.0"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95"
+checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
 dependencies = [
  "indexmap",
  "serde",
@@ -2561,7 +2561,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
 
 [[package]]
@@ -2588,20 +2588,20 @@
 
 [[package]]
 name = "tracing-log"
-version = "0.1.3"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
 dependencies = [
- "lazy_static",
  "log",
+ "once_cell",
  "tracing-core",
 ]
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.17"
+version = "0.3.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
 dependencies = [
  "matchers",
  "nu-ansi-term",
@@ -2632,18 +2632,18 @@
 
 [[package]]
 name = "unic-langid"
-version = "0.9.1"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f"
+checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516"
 dependencies = [
  "unic-langid-impl",
 ]
 
 [[package]]
 name = "unic-langid-impl"
-version = "0.9.1"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff"
+checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6"
 dependencies = [
  "serde",
  "tinystr",
@@ -2772,9 +2772,9 @@
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -2782,24 +2782,24 @@
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -2807,22 +2807,22 @@
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
 
 [[package]]
 name = "winapi"
@@ -2856,12 +2856,12 @@
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
-name = "windows"
-version = "0.48.0"
+name = "windows-core"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
@@ -2883,6 +2883,15 @@
 ]
 
 [[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.0",
+]
+
+[[package]]
 name = "windows-targets"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2913,6 +2922,21 @@
 ]
 
 [[package]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
+]
+
+[[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2925,6 +2949,12 @@
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
 [[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
+
+[[package]]
 name = "windows_aarch64_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2937,6 +2967,12 @@
 checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
 [[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
+
+[[package]]
 name = "windows_i686_gnu"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2949,6 +2985,12 @@
 checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
 [[package]]
+name = "windows_i686_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
+
+[[package]]
 name = "windows_i686_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2961,6 +3003,12 @@
 checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
 [[package]]
+name = "windows_i686_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
+
+[[package]]
 name = "windows_x86_64_gnu"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2973,6 +3021,12 @@
 checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
 [[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
+
+[[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2985,6 +3039,12 @@
 checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
 [[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
+
+[[package]]
 name = "windows_x86_64_msvc"
 version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2997,10 +3057,16 @@
 checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
 [[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
+
+[[package]]
 name = "winnow"
-version = "0.5.15"
+version = "0.5.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
+checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
 dependencies = [
  "memchr",
 ]
@@ -3024,9 +3090,9 @@
 
 [[package]]
 name = "zeroize"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
 dependencies = [
  "zeroize_derive",
 ]
@@ -3039,5 +3105,5 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.38",
+ "syn 2.0.43",
 ]
modifiedcmds/fleet/Cargo.tomldiffbeforeafterboth
--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "fleet"
 description = "NixOS configuration management"
-version = "0.1.0"
+version = "0.2.0"
 authors = ["Yaroslav Bolyukin <iam@lach.pw>"]
 edition = "2021"
 
modifiedcmds/fleet/src/better_nix_eval.rsdiffbeforeafterboth
--- a/cmds/fleet/src/better_nix_eval.rs
+++ b/cmds/fleet/src/better_nix_eval.rs
@@ -9,7 +9,7 @@
 use std::sync::{Arc, OnceLock};
 
 use anyhow::{anyhow, bail, ensure, Context, Result};
-use better_command::{ClonableHandler, NixHandler, Handler, NoopHandler};
+use better_command::{ClonableHandler, Handler, NixHandler, NoopHandler};
 use futures::StreamExt;
 use itertools::Itertools;
 use r2d2::{Pool, PooledConnection};
@@ -299,8 +299,11 @@
 		let mut fexpr = b"builtins.toJSON (".to_vec();
 		fexpr.extend_from_slice(expr.as_ref());
 		fexpr.push(b')');
-		let v = self.execute_expression_string(fexpr).await?;
-		Ok(serde_json::from_str(&v)?)
+		let v = self
+			.execute_expression_string(fexpr)
+			.await
+			.context("string expression")?;
+		serde_json::from_str(&v).context("json parse")
 	}
 	async fn execute_expression_wrapping(
 		&mut self,
@@ -450,15 +453,26 @@
 
 #[macro_export]
 macro_rules! nix_expr_inner {
-	(Obj { $($ident:ident: $($val:tt)+),* $(,)? }) => {{
-		use $crate::better_nix_eval::NixExprBuilder;
+	//(@munch_object FIXME: value should be arbitrary nix_expr_inner input... Time to write proc-macro?
+	(@obj($o:ident) $field:ident, $($tt:tt)*) => {{
+		$o.obj_key(
+			NixExprBuilder::string(stringify!($field)),
+			NixExprBuilder::field($field),
+		);
+		nix_expr_inner!(@obj($o) $($tt)*);
+	}};
+	(@obj($o:ident) $field:ident: $v:block, $($tt:tt)*) => {{
+		$o.obj_key(
+			NixExprBuilder::string(stringify!($field)),
+			NixExprBuilder::serialized(&$v),
+		);
+		nix_expr_inner!(@obj($o) $($tt)*);
+	}};
+	(@obj($o:ident)) => {{}};
+	(Obj { $($tt:tt)* }) => {{
+		use $crate::{better_nix_eval::NixExprBuilder, nix_expr_inner};
 		let mut out = NixExprBuilder::object();
-		$(
-			out.obj_key(
-				NixExprBuilder::string(stringify!($ident)),
-				$crate::nix_expr_inner!($($val)+),
-			);
-		)*
+		nix_expr_inner!(@obj(out) $($tt)*);
 		out.end_obj();
 		out
 	}};
@@ -522,6 +536,9 @@
 		$o.push(Index::ExprApply($crate::nix_expr_inner!($($var)+)));
 		nix_go!(@o($o) $($tt)*);
 	};
+	(@o($o:ident) | $($var:tt)*) => {
+		$o.push(Index::Pipe($crate::nix_expr_inner!($($var)+)));
+	};
 	(@o($o:ident)) => {};
 	($field:ident $($tt:tt)+) => {{
 		use $crate::{nix_go, better_nix_eval::Index};
@@ -545,6 +562,7 @@
 	Apply(String),
 	Expr(NixExprBuilder),
 	ExprApply(NixExprBuilder),
+	Pipe(NixExprBuilder),
 }
 impl Index {
 	pub fn var(v: impl AsRef<str>) -> Self {
@@ -582,6 +600,9 @@
 			Index::ExprApply(e) => {
 				write!(f, "<apply>({})", e.out)
 			}
+			Index::Pipe(e) => {
+				write!(f, "<map>({})", e.out)
+			}
 		}
 	}
 }
@@ -604,9 +625,9 @@
 	session: NixSession,
 	value: Option<u32>,
 }
-fn context(full_path: Option<&[Index]>, query: &str) -> String {
+fn context(op: &str, full_path: Option<&[Index]>, query: &str) -> String {
 	if let Some(full_path) = &full_path {
-		format!("full path: {}", PathDisplay(full_path))
+		format!("on {op}, full path: {}", PathDisplay(full_path))
 	} else {
 		format!("query: {query:?}")
 	}
@@ -628,7 +649,7 @@
 			.await
 			.execute_assign(query)
 			.await
-			.with_context(|| context(None, query))?;
+			.with_context(|| context("new root", None, query))?;
 		Ok(Self(Arc::new(FieldInner {
 			full_path: None,
 			session,
@@ -686,6 +707,12 @@
 					query.push_str(&index);
 					query = format!("({query})");
 				}
+				Index::Pipe(v) => {
+					let index = Field::new(self.0.session.clone(), &v.out).await?;
+					used_fields.push(index.clone());
+					let index = format!("sess_field_{}", index.0.value.expect("value"));
+					query = format!("({index} {query})");
+				}
 			}
 		}
 
@@ -720,7 +747,7 @@
 			.await
 			.execute_expression_to_json(&query)
 			.await
-			.with_context(|| context(self.0.full_path.as_deref(), &query))
+			.with_context(|| context("as_json", self.0.full_path.as_deref(), &query))
 	}
 	pub async fn has_field(&self, name: &str) -> Result<bool> {
 		let id = self.0.value.expect("can't list root fields");
@@ -733,7 +760,7 @@
 			.await
 			.execute_expression_to_json(&query)
 			.await
-			.with_context(|| context(self.0.full_path.as_deref(), &query))
+			.with_context(|| context("has_field", self.0.full_path.as_deref(), &query))
 	}
 	pub async fn list_fields(&self) -> Result<Vec<String>> {
 		let id = self.0.value.expect("can't list root fields");
@@ -745,7 +772,7 @@
 			.await
 			.execute_expression_to_json(&query)
 			.await
-			.with_context(|| context(self.0.full_path.as_deref(), &query))
+			.with_context(|| context("list field", self.0.full_path.as_deref(), &query))
 	}
 	pub async fn type_of(&self) -> Result<String> {
 		let id = self.0.value.expect("can't list root fields");
@@ -757,7 +784,11 @@
 			.await
 			.execute_expression_to_json(&query)
 			.await
-			.with_context(|| context(self.0.full_path.as_deref(), &query))
+			.with_context(|| context("type_of", self.0.full_path.as_deref(), &query))
+	}
+	pub async fn import(&self) -> Result<Self> {
+		let import = Self::new(self.0.session.clone(), "import").await?;
+		Ok(nix_go!(self | import))
 	}
 	pub async fn build(&self) -> Result<HashMap<String, PathBuf>> {
 		let id = self.0.value.expect("can't use build on not-value");
@@ -773,7 +804,7 @@
 		ensure!(
 			!vid.is_empty(),
 			"build failed: {}",
-			context(self.0.full_path.as_deref(), &query),
+			context("build", self.0.full_path.as_deref(), &query),
 		);
 		let Some(vid) = vid.strip_prefix("This derivation produced the following outputs:\n")
 		else {
modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -53,7 +53,7 @@
 	fn build_attr(&self) -> String {
 		match self {
 			PackageAction::SdImage => "sdImage".to_owned(),
-			PackageAction::InstallationCd => "installationCd".to_owned(),
+			PackageAction::InstallationCd => "isoImage".to_owned(),
 		}
 	}
 }
@@ -178,7 +178,7 @@
 	if !build.disable_rollback {
 		let _span = info_span!("preparing").entered();
 		info!("preparing for rollback");
-		let generation = get_current_generation(&host).await?;
+		let generation = get_current_generation(host).await?;
 		info!(
 			"rollback target would be {} {}",
 			generation.id, generation.datetime
@@ -234,7 +234,7 @@
 		let mut switch_script = built.clone();
 		switch_script.push("bin");
 		switch_script.push("switch-to-configuration");
-		let mut cmd = host.cmd(switch_script).await?;
+		let mut cmd = host.cmd(switch_script).in_current_span().await?;
 		cmd.arg(action.name());
 		if let Err(e) = cmd.sudo().run().in_current_span().await {
 			error!("failed to activate: {e}");
@@ -285,11 +285,9 @@
 		info!("building");
 		let host = config.host(&host).await?;
 		let action = Action::from(self.subcommand.clone());
-		let fleet_field = &config.fleet_field;
+		let fleet_config = &config.config_field;
 		let drv = nix_go!(
-			fleet_field.buildSystems(Obj {
-				localSystem: { config.local_system.clone() }
-			})[{ action.build_attr() }][{ &host.name }]
+			fleet_config.hosts[{ &host.name }].nixosSystem.config.system.build[{ action.build_attr() }]
 		);
 		let outputs = drv.build().await.map_err(|e| {
 			if action.build_attr() == "sdImage" {
modifiedcmds/fleet/src/cmds/info.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/info.rs
+++ b/cmds/fleet/src/cmds/info.rs
@@ -37,9 +37,9 @@
 			InfoCmd::ListHosts { ref tagged } => {
 				'host: for host in config.list_hosts().await? {
 					if !tagged.is_empty() {
-						let fleet_field = &config.fleet_field;
+						let config = &config.config_unchecked_field;
 						let tags: Vec<String> =
-							nix_go_json!(fleet_field.configuredSystems[{ host.name }].config.tags);
+							nix_go_json!(config.hosts[{ host.name }].nixosSystem.config.tags);
 						for tag in tagged {
 							if !tags.contains(tag) {
 								continue 'host;
modifiedcmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -10,14 +10,15 @@
 use futures::StreamExt;
 use itertools::Itertools;
 use owo_colors::OwoColorize;
+use serde::Deserialize;
 use std::{
-	collections::HashSet,
+	collections::{BTreeSet, HashSet},
 	io::{self, Cursor, Read},
 	path::PathBuf,
 };
 use tabled::{Table, Tabled};
 use tokio::fs::read_to_string;
-use tracing::{info, info_span, warn};
+use tracing::{error, info, info_span, warn, Instrument};
 
 #[derive(Parser)]
 pub enum Secret {
@@ -92,77 +93,182 @@
 	List {},
 }
 
-async fn generate_shared(
+#[tracing::instrument(skip(config, secret, field, prefer_identities))]
+async fn update_owner_set(
+	secret_name: &str,
 	config: &Config,
-	display_name: &str,
-	secret: Field,
+	mut secret: FleetSharedSecret,
+	field: Field,
+	updated_set: &[String],
+	prefer_identities: &[String],
 ) -> Result<FleetSharedSecret> {
-	Ok(if secret.has_field("generateImpure").await? {
-		let config_field = &config.config_unchecked_field;
-		let generate = nix_go!(secret.generateImpure);
-		let owners: Vec<String> = nix_go_json!(secret.expectedOwners);
+	let original_set = secret.owners.clone();
 
-		let on: String = nix_go_json!(generate.on);
-		let call_package = nix_go!(
-			config_field.buildableSystems(Obj {
-				localSystem: { config.local_system.clone() }
-			})[{ on }]
-			.config
-			.nixpkgs
-			.resolvedPkgs
-			.callPackage
-		);
+	let set = original_set.iter().collect::<BTreeSet<_>>();
+	let expected_set = updated_set.iter().collect::<BTreeSet<_>>();
 
-		let host = config.host(&on).await?;
+	if set == expected_set {
+		info!("no need to update owner list, it is already correct");
+		return Ok(secret);
+	}
 
-		let generator = nix_go!(call_package(generate.generator)(Obj {}));
-		let generator = generator.build().await?;
-		let generator = generator
-			.get("out")
-			.ok_or_else(|| anyhow!("missing generateImpure out"))?;
-		let generator = host.remote_derivation(generator).await?;
+	let should_regenerate = if set.difference(&expected_set).next().is_some() {
+		// TODO: Remove this warning for revokable secrets.
+		warn!("host was removed from secret owners, but until this host rebuild, the secret will still be stored on it.");
+		nix_go_json!(field.regenerateOnOwnerRemoved)
+	} else if expected_set.difference(&set).next().is_some() {
+		nix_go_json!(field.regenerateOnOwnerAdded)
+	} else {
+		false
+	};
+
+	if should_regenerate {
+		info!("secret is owner-dependent, will regenerate");
+		let generated = generate_shared(config, secret_name, field, updated_set.to_vec()).await?;
+		Ok(generated)
+	} else {
+		let identity_holder = if !prefer_identities.is_empty() {
+			prefer_identities
+				.iter()
+				.find(|i| original_set.iter().any(|s| s == *i))
+		} else {
+			secret.owners.first()
+		};
+		let Some(identity_holder) = identity_holder else {
+			bail!("no available holder found");
+		};
 
-		let mut recipients = String::new();
-		for owner in &owners {
-			let key = config.key(owner).await?;
-			recipients.push_str(&format!("-r \"{key}\" "));
+		if let Some(data) = secret.secret.secret {
+			let host = config.host(identity_holder).await?;
+			let encrypted = host.reencrypt(data, updated_set.to_vec()).await?;
+			secret.secret.secret = Some(encrypted);
 		}
-		recipients.push_str("-e");
 
-		let out = host.mktemp_dir().await?;
+		secret.owners = updated_set.to_vec();
+		Ok(secret)
+	}
+}
+
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+enum GeneratorKind {
+	Impure,
+}
+
+async fn generate_impure(
+	config: &Config,
+	_display_name: &str,
+	secret: Field,
+	default_generator: Field,
+	owners: &[String],
+) -> Result<FleetSecret> {
+	let config_field = &config.config_unchecked_field;
+	let generator = nix_go!(secret.generator);
+
+	let on: String = nix_go_json!(default_generator.impureOn);
+	let call_package = nix_go!(
+		config_field.buildableSystems(Obj {
+			localSystem: { config.local_system.clone() },
+		})[{ on }]
+		.config
+		.nixpkgs
+		.resolvedPkgs
+		.callPackage
+	);
+
+	let host = config.host(&on).await?;
+
+	let generator = nix_go!(call_package(generator)(Obj {}));
+	let generator = generator.build().await?;
+	let generator = generator
+		.get("out")
+		.ok_or_else(|| anyhow!("missing generateImpure out"))?;
+	let generator = host.remote_derivation(generator).await?;
+
+	let mut recipients = String::new();
+	for owner in owners {
+		let key = config.key(owner).await?;
+		recipients.push_str(&format!("-r \"{key}\" "));
+	}
+	recipients.push_str("-e");
 
-		let mut gen = host.cmd(generator).await?;
-		gen.env("rageArgs", recipients).env("out", &out);
-		gen.run().await?;
+	let out = host.mktemp_dir().await?;
 
-		{
-			let marker = host.read_file_text(format!("{out}/marker")).await?;
-			ensure!(marker == "SUCCESS", "generation not succeeded");
-		}
+	let mut gen = host.cmd(generator).await?;
+	gen.env("rageArgs", recipients).env("out", &out);
+	gen.run().await.context("impure generator")?;
 
-		let public = host.read_file_text(format!("{out}/public")).await.ok();
-		let secret = host.read_file_bin(format!("{out}/secret")).await.ok();
-		if let Some(secret) = &secret {
-			ensure!(
-				age::Decryptor::new(Cursor::new(&secret)).is_ok(),
-				"builder produced non-encrypted value as secret, this is highly insecure"
-			);
+	{
+		let marker = host.read_file_text(format!("{out}/marker")).await?;
+		ensure!(marker == "SUCCESS", "generation not succeeded");
+	}
+
+	let public = host.read_file_text(format!("{out}/public")).await.ok();
+	let secret = host.read_file_bin(format!("{out}/secret")).await.ok();
+	if let Some(secret) = &secret {
+		ensure!(
+			age::Decryptor::new(Cursor::new(&secret)).is_ok(),
+			"builder produced non-encrypted value as secret, this is highly insecure, and not allowed."
+		);
+	}
+
+	let created_at = host.read_file_value(format!("{out}/created_at")).await?;
+	let expires_at = host.read_file_value(format!("{out}/expires_at")).await.ok();
+
+	Ok(FleetSecret {
+		created_at,
+		expires_at,
+		public,
+		secret: secret.map(SecretData),
+	})
+}
+async fn generate(
+	config: &Config,
+	display_name: &str,
+	secret: Field,
+	owners: &[String],
+) -> Result<FleetSecret> {
+	let generator = nix_go!(secret.generator);
+	// Can't properly check on nix module system level
+	{
+		let gen_ty = generator.type_of().await?;
+		if gen_ty == "null" {
+			bail!("secret has no generator defined, can't automatically generate it.");
 		}
+		if gen_ty != "lambda" {
+			bail!("generator should be lambda, got {gen_ty}");
+		}
+	}
+	let default_pkgs = &config.default_pkgs;
+	let default_call_package = nix_go!(default_pkgs.callPackage);
+	// Generators provide additional information in passthru, to access
+	// passthru we should call generator, but information about where this generator is supposed to build
+	// is located in passthru... Thus evaluating generator on host.
+	//
+	// Maybe it is also possible to do some magic with __functor?
+	//
+	// I don't want to make modules always responsible for additional secret data anyway,
+	// so it should be in derivation, and not in the secret data itself.
+	let default_generator = nix_go!(default_call_package(generator)(Obj {}));
 
-		let created_at = host.read_file_value(format!("{out}/created_at")).await?;
-		let expires_at = host.read_file_value(format!("{out}/expires_at")).await.ok();
+	let kind: GeneratorKind = nix_go_json!(default_generator.generatorKind);
 
-		FleetSharedSecret {
-			owners,
-			secret: FleetSecret {
-				created_at,
-				expires_at,
-				public,
-				secret: secret.map(SecretData),
-			},
+	match kind {
+		GeneratorKind::Impure => {
+			generate_impure(config, display_name, secret, default_generator, owners).await
 		}
-	} else {
-		bail!("no generator defined for {display_name}")
+	}
+}
+async fn generate_shared(
+	config: &Config,
+	display_name: &str,
+	secret: Field,
+	expected_owners: Vec<String>,
+) -> Result<FleetSharedSecret> {
+	// let owners: Vec<String> = nix_go_json!(secret.expectedOwners);
+	Ok(FleetSharedSecret {
+		secret: generate(config, display_name, secret, &expected_owners).await?,
+		owners: expected_owners,
 	})
 }
 
@@ -270,9 +376,7 @@
 					machines = shared.owners;
 				}
 
-				let recipients = config
-					.recipients(&machines.iter().map(String::as_str).collect_vec())
-					.await?;
+				let recipients = config.recipients(machines.clone()).await?;
 
 				let secret = {
 					let mut input = vec![];
@@ -362,7 +466,7 @@
 				remove_machines,
 				prefer_identities,
 			} => {
-				let mut secret = config.shared_secret(&name)?;
+				let secret = config.shared_secret(&name)?;
 				if secret.secret.secret.is_none() {
 					bail!("no secret");
 				}
@@ -378,61 +482,84 @@
 				if target_machines.is_empty() {
 					info!("no machines left for secret, removing it");
 					config.remove_shared(&name);
-					return Ok(());
-				}
-
-				if target_machines == initial_machines {
-					warn!("secret owners are already correct");
 					return Ok(());
 				}
 
-				let identity_holder = if !prefer_identities.is_empty() {
-					prefer_identities
-						.iter()
-						.find(|i| initial_machines.iter().any(|s| s == *i))
-				} else {
-					secret.owners.first()
-				};
-				let Some(identity_holder) = identity_holder else {
-					bail!("no available holder found");
-				};
-				let target_recipients = futures::stream::iter(&target_machines)
-					.then(|m| async { config.key(m).await })
-					.collect::<Vec<_>>()
-					.await;
-				let target_recipients =
-					target_recipients.into_iter().collect::<Result<Vec<_>>>()?;
+				let config_field = &config.config_unchecked_field;
+				let config_field = nix_go!(config_field.configUnchecked);
+				let field = nix_go!(config_field.sharedSecrets[{ name }]);
 
-				if let Some(data) = secret.secret.secret {
-					let host = config.host(&identity_holder).await?;
-					let encrypted = host.reencrypt(data, target_recipients).await?;
-					secret.secret.secret = Some(encrypted);
-				}
-
-				secret.owners = target_machines;
-				config.replace_shared(name, secret);
+				let updated = update_owner_set(
+					&name,
+					config,
+					secret,
+					field,
+					&target_machines,
+					&prefer_identities,
+				)
+				.await?;
+				config.replace_shared(name, updated);
 			}
 			Secret::Regenerate { prefer_identities } => {
+				info!("checking for secrets to regenerate");
 				{
+					let _span = info_span!("shared").entered();
 					let expected_shared_set = config
 						.list_configured_shared()
 						.await?
 						.into_iter()
 						.collect::<HashSet<_>>();
 					let shared_set = config.list_shared().into_iter().collect::<HashSet<_>>();
-					for removed in expected_shared_set.difference(&shared_set) {
-						info!("generating secret: {removed}");
+					for missing in expected_shared_set.difference(&shared_set) {
 						let config_field = &config.config_unchecked_field;
 						let config_field = nix_go!(config_field.configUnchecked);
-						let secret = nix_go!(config_field.sharedSecrets[{ removed }]);
-						let shared = generate_shared(config, removed, secret).await?;
-						config.replace_shared(removed.to_string(), shared)
+						let secret = nix_go!(config_field.sharedSecrets[{ missing }]);
+						let expected_owners: Option<Vec<String>> =
+							nix_go_json!(secret.expectedOwners);
+						let Some(expected_owners) = expected_owners else {
+							// TODO: Might still need to regenerate
+							continue;
+						};
+						info!("generating secret: {missing}");
+						let shared = generate_shared(config, missing, secret, expected_owners)
+							.in_current_span()
+							.await?;
+						config.replace_shared(missing.to_string(), shared)
+					}
+				}
+				for host in config.list_hosts().await? {
+					let _span = info_span!("host", host = host.name).entered();
+					let expected_set = host
+						.list_configured_secrets()
+						.in_current_span()
+						.await?
+						.into_iter()
+						.collect::<HashSet<_>>();
+					let stored_set = config
+						.list_secrets(&host.name)
+						.into_iter()
+						.collect::<HashSet<_>>();
+					for missing in expected_set.difference(&stored_set) {
+						info!("generating secret: {missing}");
+						let secret = host.secret_field(missing).in_current_span().await?;
+						let generated =
+							match generate(config, missing, secret, &[host.name.clone()])
+								.in_current_span()
+								.await
+							{
+								Ok(v) => v,
+								Err(e) => {
+									error!("{e}");
+									continue;
+								}
+							};
+						config.insert_secret(&host.name, missing.to_string(), generated)
 					}
 				}
 				let mut to_remove = Vec::new();
 				for name in &config.list_shared() {
 					info!("updating secret: {name}");
-					let mut data = config.shared_secret(name)?;
+					let data = config.shared_secret(name)?;
 					let config_field = &config.config_unchecked_field;
 					let config_field = nix_go!(config_field.configUnchecked);
 					let expected_owners: Vec<String> =
@@ -442,55 +569,20 @@
 						to_remove.push(name.to_string());
 						continue;
 					}
-					let set = data.owners.iter().collect::<HashSet<_>>();
-					let expected_set = expected_owners.iter().collect::<HashSet<_>>();
-					let should_remove = set.difference(&expected_set).next().is_some();
-					if set == expected_set {
-						info!("secret data is ok");
-						continue;
-					}
 
 					let secret = nix_go!(config_field.sharedSecrets[{ name }]);
-					let owner_dependent: bool = nix_go_json!(secret.ownerDependent);
-					let regenerate_on_remove: bool = nix_go_json!(secret.regenerateOnOwnerRemoved);
-					#[allow(clippy::nonminimal_bool)]
-					if !owner_dependent && !(should_remove && regenerate_on_remove) {
-						warn!("reencrypting secret '{name}' for new owner set");
-						// TODO: force regeneration
-						if should_remove {
-							warn!("secret will not be regenerated for removed machines, and until host rebuild, they will still possess the ability to decode secret");
-						}
-
-						let identity_holder = if !prefer_identities.is_empty() {
-							prefer_identities
-								.iter()
-								.find(|i| data.owners.iter().any(|s| s == *i))
-						} else {
-							data.owners.first()
-						};
-						let Some(identity_holder) = identity_holder else {
-							bail!("no available holder found");
-						};
-
-						let target_recipients = futures::stream::iter(&expected_owners)
-							.then(|m| async { config.key(m).await })
-							.collect::<Vec<_>>()
-							.await;
-						let target_recipients =
-							target_recipients.into_iter().collect::<Result<Vec<_>>>()?;
-
-						if let Some(secret) = data.secret.secret {
-							let host = config.host(identity_holder).await?;
-							let encrypted = host.reencrypt(secret, target_recipients).await?;
-
-							data.secret.secret = Some(encrypted);
-						}
-						data.owners = expected_owners;
-						config.replace_shared(name.to_owned(), data);
-					} else {
-						let shared = generate_shared(config, name, secret).await?;
-						config.replace_shared(name.to_owned(), shared)
-					}
+					config.replace_shared(
+						name.to_owned(),
+						update_owner_set(
+							&name,
+							config,
+							data,
+							secret,
+							&expected_owners,
+							&prefer_identities,
+						)
+						.await?,
+					);
 				}
 				for k in to_remove {
 					config.remove_shared(&k);
modifiedcmds/fleet/src/command.rsdiffbeforeafterboth
--- a/cmds/fleet/src/command.rs
+++ b/cmds/fleet/src/command.rs
@@ -1,5 +1,3 @@
-use std::thread::sleep;
-use std::time::Duration;
 use std::{ffi::OsStr, pin, process::Stdio, sync::Arc, task::Poll};
 
 use anyhow::{anyhow, Result};
@@ -9,7 +7,7 @@
 use openssh::{OverSsh, OwningCommand, Session};
 use tokio::{io::AsyncRead, process::Command, select};
 use tokio_util::codec::{BytesCodec, FramedRead, LinesCodec};
-use tracing::{info, debug};
+use tracing::debug;
 
 fn escape_bash(input: &str, out: &mut String) {
 	const TO_ESCAPE: &str = "$ !\"#&'()*,;<>?[\\]^`{|}";
@@ -162,6 +160,10 @@
 		self
 	}
 	pub fn sudo(mut self) -> Self {
+		// TODO: Multiple escalation strategies.
+		// Maybe escalation should be moved to ConfigHost, to also support cases
+		// when there is no sudo on remote machine, but instead we can reconnect
+		// as root using ssh?
 		if std::env::var_os("NO_SUDO").is_some() {
 			let mut out = Self::new("su");
 			out.ssh_session = self.ssh_session.take();
@@ -267,7 +269,7 @@
 ) -> Result<Option<Vec<u8>>> {
 	cmd.stderr(Stdio::piped());
 	cmd.stdout(Stdio::piped());
-	debug!("running command {cmd:?} on local");
+	debug!("running command {str:?} on local");
 	let mut child = cmd.spawn()?;
 	let mut stderr = child.stderr.take().unwrap();
 	let stdout = child.stdout.take().unwrap();
@@ -328,7 +330,7 @@
 	err_handler: &mut dyn Handler,
 	mut out_handler: Option<&mut dyn Handler>,
 ) -> Result<Option<Vec<u8>>> {
-	debug!("running command {cmd:?} over ssh");
+	debug!("running command {str:?} over ssh");
 	cmd.stderr(openssh::Stdio::piped());
 	cmd.stdout(openssh::Stdio::piped());
 	let mut child = cmd.spawn().await?;
modifiedcmds/fleet/src/host.rsdiffbeforeafterboth
--- a/cmds/fleet/src/host.rs
+++ b/cmds/fleet/src/host.rs
@@ -14,6 +14,7 @@
 use openssh::SessionBuilder;
 use serde::de::DeserializeOwned;
 use tempfile::NamedTempFile;
+use tracing::instrument;
 
 use crate::{
 	better_nix_eval::{Field, NixSessionPool},
@@ -28,12 +29,13 @@
 	pub opts: FleetOpts,
 	pub data: Mutex<FleetData>,
 	pub nix_args: Vec<OsString>,
-	/// fleetConfigurations.<name>.<localSystem>
-	pub fleet_field: Field,
-	/// fleet_config.configUnchecked
+	/// fleet_config.config
 	pub config_field: Field,
-	/// fleet_config.unchecked
+	/// fleet_config.unchecked.config
 	pub config_unchecked_field: Field,
+
+	/// import nixpkgs {system = local};
+	pub default_pkgs: Field,
 }
 
 #[derive(Clone)]
@@ -48,9 +50,12 @@
 }
 
 pub struct ConfigHost {
+	config: Config,
 	pub name: String,
 	pub local: bool,
 	pub session: OnceLock<Arc<openssh::Session>>,
+
+	pub nixos_config: Field,
 }
 impl ConfigHost {
 	async fn open_session(&self) -> Result<Arc<openssh::Session>> {
@@ -64,7 +69,7 @@
 		let session = session
 			.connect(&self.name)
 			.await
-			.map_err(|e| anyhow!("ssh error: {e}"))?;
+			.map_err(|e| anyhow!("ssh error while connecting to {}: {e}", self.name))?;
 		let session = Arc::new(session);
 		self.session.set(session.clone()).expect("TOCTOU happened");
 		Ok(session)
@@ -119,7 +124,8 @@
 		let mut cmd = self.cmd("fleet-install-secrets").await?;
 		cmd.arg("reencrypt").eqarg("--secret", data.encode_z85());
 		for target in targets {
-			cmd.eqarg("--targets", target);
+			let key = self.config.key(&target).await?;
+			cmd.eqarg("--targets", key);
 		}
 		let encoded = cmd
 			.sudo()
@@ -139,7 +145,7 @@
 			.arg("--substitute-on-destination")
 			.comparg("--to", format!("ssh-ng://{}", self.name))
 			.arg(path);
-		nix.run_nix().await?;
+		nix.run_nix().await.context("nix copy")?;
 		Ok(path.to_owned())
 	}
 	pub async fn systemctl_stop(&self, name: &str) -> Result<()> {
@@ -161,6 +167,25 @@
 		}
 		cmd.run().await
 	}
+
+	pub async fn list_configured_secrets(&self) -> Result<Vec<String>> {
+		let nixos = &self.nixos_config;
+		let secrets = nix_go!(nixos.secrets);
+		let mut out = Vec::new();
+		for name in secrets.list_fields().await? {
+			let secret = nix_go!(secrets[{ name }]);
+			let is_shared: bool = nix_go_json!(secret.shared);
+			if is_shared {
+				continue;
+			}
+			out.push(name);
+		}
+		Ok(out)
+	}
+	pub async fn secret_field(&self, name: &str) -> Result<Field> {
+		let nixos = &self.nixos_config;
+		Ok(nix_go!(nixos.secrets[{ name }]))
+	}
 }
 
 impl Config {
@@ -178,28 +203,28 @@
 	}
 
 	pub async fn host(&self, name: &str) -> Result<ConfigHost> {
+		let config = &self.config_unchecked_field;
+		let nixos_config = nix_go!(config.configuredSystems[{ name }].config);
 		Ok(ConfigHost {
+			config: self.clone(),
 			name: name.to_owned(),
 			local: self.is_local(name),
 			session: OnceLock::new(),
+			nixos_config,
 		})
 	}
 	pub async fn list_hosts(&self) -> Result<Vec<ConfigHost>> {
-		let fleet_field = &self.fleet_field;
-		let names = nix_go!(fleet_field.configuredHosts).list_fields().await?;
+		let config = &self.config_unchecked_field;
+		let names = nix_go!(config.hosts).list_fields().await?;
 		let mut out = vec![];
 		for name in names {
-			out.push(ConfigHost {
-				local: self.is_local(&name),
-				name,
-				session: OnceLock::new(),
-			})
+			out.push(self.host(&name).await?);
 		}
 		Ok(out)
 	}
 	pub async fn system_config(&self, host: &str) -> Result<Field> {
-		let fleet_field = &self.fleet_field;
-		Ok(nix_go!(fleet_field.configuredSystems[{ host }].config))
+		let fleet_field = &self.config_unchecked_field;
+		Ok(nix_go!(fleet_field.hosts[{ host }].nixosSystem.config))
 	}
 
 	pub(super) fn data(&self) -> MutexGuard<FleetData> {
@@ -233,6 +258,14 @@
 		data.shared_secrets.remove(secret);
 	}
 
+	pub fn list_secrets(&self, host: &str) -> Vec<String> {
+		let data = self.data();
+		let Some(secrets) = data.host_secrets.get(host) else {
+			return Vec::new();
+		};
+		secrets.keys().cloned().collect()
+	}
+
 	pub fn has_secret(&self, host: &str, secret: &str) -> bool {
 		let data = self.data();
 		let Some(host_secrets) = data.host_secrets.get(host) else {
@@ -319,18 +352,27 @@
 		let pool = NixSessionPool::new(directory.as_os_str().to_owned(), nix_args.clone()).await?;
 		let root_field = pool.get().await?;
 
+		let builtins_field = Field::field(root_field.clone(), "builtins").await?;
 		if self.local_system == "detect" {
-			let builtins_field = Field::field(root_field.clone(), "builtins").await?;
 			self.local_system = nix_go_json!(builtins_field.currentSystem);
 		}
 		let local_system = self.local_system.clone();
 
 		let fleet_root = Field::field(root_field, "fleetConfigurations").await?;
-
 		let fleet_field = nix_go!(fleet_root.default);
-		let config_field = nix_go!(fleet_field.configUnchecked);
-		let config_unchecked_field = nix_go!(fleet_field.unchecked);
 
+		let config_field = nix_go!(fleet_field.config);
+		let config_unchecked_field = nix_go!(fleet_field.unchecked.config);
+
+		let import = nix_go!(builtins_field.import);
+		let overlays = nix_go!(fleet_field.overlays);
+		let nixpkgs = nix_go!(fleet_field.nixpkgs | import);
+
+		let default_pkgs = nix_go!(nixpkgs(Obj {
+			overlays,
+			system: { self.local_system.clone() },
+		}));
+
 		let mut fleet_data_path = directory.clone();
 		fleet_data_path.push("fleet.nix");
 		let bytes = std::fs::read_to_string(fleet_data_path)?;
@@ -342,9 +384,9 @@
 			data,
 			local_system,
 			nix_args,
-			fleet_field,
 			config_field,
 			config_unchecked_field,
+			default_pkgs,
 		})))
 	}
 }
modifiedcmds/fleet/src/keys.rsdiffbeforeafterboth
--- a/cmds/fleet/src/keys.rs
+++ b/cmds/fleet/src/keys.rs
@@ -43,9 +43,9 @@
 		age::ssh::Recipient::from_str(&key).map_err(|e| anyhow!("parse recipient error: {:?}", e))
 	}
 
-	pub async fn recipients(&self, hosts: &[&str]) -> Result<Vec<impl Recipient>> {
+	pub async fn recipients(&self, hosts: Vec<String>) -> Result<Vec<impl Recipient>> {
 		futures::stream::iter(hosts.iter())
-			.then(|m| self.recipient(m))
+			.then(|m| self.recipient(m.as_ref()))
 			.try_collect::<Vec<_>>()
 			.await
 	}
modifiedcmds/fleet/src/main.rsdiffbeforeafterboth
--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -12,6 +12,8 @@
 mod fleetdata;
 
 use std::ffi::OsString;
+use std::io::{stderr, stdout, Write};
+use std::process::exit;
 use std::time::Duration;
 
 use anyhow::{bail, Result};
@@ -24,7 +26,7 @@
 use host::{Config, FleetOpts};
 use human_repr::HumanCount;
 use indicatif::{ProgressState, ProgressStyle};
-use tracing::info;
+use tracing::{error, info};
 use tracing::{info_span, Instrument};
 use tracing_indicatif::IndicatifLayer;
 use tracing_subscriber::{prelude::*, EnvFilter};
@@ -81,7 +83,7 @@
 }
 
 #[derive(Parser)]
-#[clap(version = "1.0", author)]
+#[clap(version, author)]
 struct RootOpts {
 	#[clap(flatten)]
 	fleet_opts: FleetOpts,
@@ -136,13 +138,13 @@
 		),
 	);
 
-	let filter = EnvFilter::from_default_env();
+	let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
 
 	tracing_subscriber::registry()
 		.with(
 			tracing_subscriber::fmt::layer()
 				.without_time()
-				.with_target(false)
+				.with_target(true)
 				.with_writer(indicatif_layer.get_stderr_writer())
 				.with_filter(filter), // .withou,
 		)
@@ -151,8 +153,15 @@
 }
 
 #[tokio::main]
-async fn main() -> Result<()> {
+async fn main() {
 	setup_logging();
+	if let Err(e) = main_real().await {
+		error!("{e:#}");
+		exit(1);
+	}
+}
+
+async fn main_real() -> Result<()> {
 	let _ = better_nix_eval::TOKIO_RUNTIME.set(tokio::runtime::Handle::current());
 
 	let nix_args = std::env::var_os("NIX_ARGS")
modifiedflake.lockdiffbeforeafterboth
--- a/flake.lock
+++ b/flake.lock
@@ -38,11 +38,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1703705939,
-        "narHash": "sha256-9s2Ep3NyRDj9HUgfv2TQUwQEanRUAmeXkvKIr/o1XbY=",
+        "lastModified": 1703974965,
+        "narHash": "sha256-dvZjLuAcLnv25bqStTL2ZICC5YSs8aynF5amRM+I6UM=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "1ada32da4ba24d7310653c9ac54888bee463f455",
+        "rev": "9f434bd436e2bb5615827469ed651e30c26daada",
         "type": "github"
       },
       "original": {
@@ -67,11 +67,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1703643208,
-        "narHash": "sha256-UL4KO8JxnD5rOycwHqBAf84lExF1/VnYMDC7b/wpPDU=",
+        "lastModified": 1703902408,
+        "narHash": "sha256-qXdWvu+tlgNjeoz8yQMRKSom6QyRROfgpmeOhwbujqw=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "ce117f3e0de8262be8cd324ee6357775228687cf",
+        "rev": "319f57cd2c34348c55970a4bf2b35afe82088681",
         "type": "github"
       },
       "original": {
modifiedflake.nixdiffbeforeafterboth
--- a/flake.nix
+++ b/flake.nix
@@ -29,7 +29,7 @@
         llvmPkgs = pkgs.buildPackages.llvmPackages_11;
         rust =
           (pkgs.rustChannelOf {
-            date = "2023-12-26";
+            date = "2023-12-29";
             channel = "nightly";
           })
           .default
modifiedlib/default.nixdiffbeforeafterboth
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -1,18 +1,31 @@
 {flake-utils}: {
   fleetConfiguration = {
+    # TODO: Provide by fleet, instead of requesting user to provide it.
+    # This is not good that user needs to provide it, as it becomes a flake data, and fleet arbitrarily rewriting it
+    # always dirnets the flake. Instead, fleetConfiguration should return function, parameters of which should be filled
+    # by fleet itself, which is possible since fleet moving to nix repl execution.
     data,
     nixpkgs,
+    overlays ? [],
     hosts,
-    ...
-  } @ allConfig: let
+    modules,
+    globalModules ? [],
+  }: let
     hostNames = nixpkgs.lib.attrNames hosts;
-    config = builtins.removeAttrs allConfig ["nixpkgs" "data"];
     fleetLib = import ./fleetLib.nix {
       inherit nixpkgs hostNames;
     };
   in let
     root = nixpkgs.lib.evalModules {
-      modules = (import ../modules/fleet/_modules.nix) ++ [config data];
+      modules =
+        (import ../modules/fleet/_modules.nix)
+        ++ [
+          data
+          ({...}: {
+            inherit globalModules hosts;
+          })
+        ]
+        ++ modules;
       specialArgs = {
         inherit nixpkgs fleetLib;
       };
@@ -25,84 +38,20 @@
     withData = {
       root,
       data,
-    }: rec {
+    }: {
       configuredHosts = root.config.hosts;
-      configuredUncheckedHosts = root.config.hosts;
-      configuredSystems = configuredSystemsWithExtraModules [];
-      configuredSystemsWithExtraModules = extraModules:
-        nixpkgs.lib.listToAttrs (
-          map
-          (
-            name: {
-              inherit name;
-              value = nixpkgs.lib.nixosSystem {
-                system = configuredHosts.${name}.system;
-                modules = configuredHosts.${name}.modules ++ extraModules;
-                specialArgs = {
-                  inherit fleetLib;
-                  fleet = fleetLib.hostsToAttrs (host: configuredSystems.${host}.config);
-                };
-              };
-            }
-          )
-          (builtins.attrNames root.config.hosts)
-        );
-      buildableSystems = {localSystem}: let
-        buildConfigurationModule = {config, ...}: {
-          # Equivalent to nixpkgs.localSystem
-          # nixpkgs.system = localSystem;
-          nixpkgs.buildPlatform.system = localSystem;
-        };
-      in
-        configuredSystemsWithExtraModules [
-          buildConfigurationModule
-        ];
-      buildSystems = {localSystem}: let
-        buildConfigurationModule = {config, ...}: {
-          # Equivalent to nixpkgs.localSystem
-          # nixpkgs.system = localSystem;
-          nixpkgs.buildPlatform.system = localSystem;
-        };
-      in {
-        toplevel = builtins.mapAttrs (_name: value: value.config.system.build.toplevel) (configuredSystemsWithExtraModules [
-          buildConfigurationModule
-          ({...}: {
-            buildTarget = "toplevel";
-          })
-        ]);
-        sdImage = builtins.mapAttrs (_name: value: value.config.system.build.sdImage) (configuredSystemsWithExtraModules [
-          buildConfigurationModule
-          #(nixpkgs + "/nixos/modules/installer/sd-card/sd-image-aarch64-installer.nix")
-          ({...}: {
-            buildTarget = "sd-image";
-          })
-        ]);
-        installationCd = builtins.mapAttrs (_name: value: value.config.system.build.isoImage) (configuredSystemsWithExtraModules [
-          buildConfigurationModule
-          (nixpkgs + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix")
-          ({lib, ...}: {
-            buildTarget = "installation-cd";
-            # Needed for https://github.com/NixOS/nixpkgs/issues/58959
-            boot.supportedFilesystems = lib.mkForce ["btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs"];
-          })
-        ]);
-      };
-      configUnchecked = root.config;
+      config = root.config;
     };
     defaultData = withData {
       inherit data;
       root = checkedRoot;
     };
     uncheckedData = withData {inherit data root;};
-  in rec {
-    inherit (defaultData) configuredHosts configuredSystems buildSystems configUnchecked buildableSystems;
+  in {
+    inherit nixpkgs overlays;
+    inherit (defaultData) configuredHosts configuredSystems config buildableSystems;
     unchecked = {
-      inherit (uncheckedData) configuredHosts configuredSystems buildSystems configUnchecked buildableSystems;
-    };
-    injectData = data: let
-      injectedData = withData data;
-    in {
-      inherit (injectedData) configuredHosts configuredSystems buildSystems configUnchecked;
+      inherit (uncheckedData) configuredHosts configuredSystems config buildableSystems;
     };
   };
 }
modifiedmodules/fleet/meta.nixdiffbeforeafterboth
--- a/modules/fleet/meta.nix
+++ b/modules/fleet/meta.nix
@@ -1,49 +1,82 @@
-{ lib, fleetLib, config, ... }: with lib;
-let
-  host = with types; {
-    options = {
-      modules = mkOption {
-        type = listOf (mkOptionType {
-          name = "submodule";
-          inherit (submodule { }) check;
-          merge = lib.options.mergeOneOption;
-          description = "Nixos modules";
-        });
-        description = "List of nixos modules";
-        default = [ ];
-      };
-      system = mkOption {
-        type = str;
-        description = "Type of system";
+{
+  lib,
+  fleetLib,
+  config,
+  nixpkgs,
+  ...
+}:
+with lib; let
+  hostModule = with types;
+    {...} @ hostConfig: {
+      options = {
+        modules = mkOption {
+          type = listOf (mkOptionType {
+            name = "submodule";
+            inherit (submodule {}) check;
+            merge = lib.options.mergeOneOption;
+            description = "Nixos modules";
+          });
+          description = "List of nixos modules";
+          default = [];
+        };
+        system = mkOption {
+          type = str;
+          description = "Type of system";
+        };
+        encryptionKey = mkOption {
+          type = str;
+          description = "Encryption key";
+        };
+        nixosSystem = mkOption {
+          type = unspecified;
+          description = "Nixos configuration";
+        };
       };
-      encryptionKey = mkOption {
-        type = str;
-        description = "Encryption key";
+      config.nixosSystem = nixpkgs.lib.nixosSystem {
+        inherit (hostConfig.config) system modules;
+        specialArgs = {
+          inherit fleetLib;
+          fleet = fleetLib.hostsToAttrs (host: config.hosts.${host}.nixosSystem.config);
+        };
       };
     };
+  overlayType = mkOptionType {
+    name = "nixpkgs-overlay";
+    description = "nixpkgs overlay";
+    check = lib.isFunction;
+    merge = lib.mergeOneOption;
   };
-in
-{
+in {
   options = with types; {
     hosts = mkOption {
-      type = attrsOf (submodule host);
-      default = { };
+      type = attrsOf (submodule hostModule);
+      default = {};
       description = "Configurations of individual hosts";
     };
     globalModules = mkOption {
       type = listOf (mkOptionType {
         name = "submodule";
-        inherit (submodule { }) check;
+        inherit (submodule {}) check;
         merge = lib.options.mergeOneOption;
         description = "Nixos modules";
       });
       description = "Modules, which should be added to every system";
-      default = [ ];
+      default = [];
     };
+    overlays = mkOption {
+      default = [];
+      type = listOf overlayType;
+    };
   };
   config = {
     hosts = fleetLib.hostsToAttrs (host: {
-      modules = config.globalModules;
+      modules =
+        config.globalModules
+        ++ [
+          ({...}: {
+            nixpkgs.overlays = config.overlays;
+          })
+        ];
     });
     globalModules = import ../../nixos/modules/module-list.nix;
   };
modifiedmodules/fleet/secrets.nixdiffbeforeafterboth
1{ lib, fleetLib, config, ... }: with lib; with fleetLib;1{ lib, fleetLib, config, ... }: with lib; with fleetLib;
2let2let
3 sharedSecret = with types; {3 sharedSecret = with types; ({config, ...}: {
4 options = {4 options = {
5 expectedOwners = mkOption {5 expectedOwners = mkOption {
6 type = listOf str;6 type = nullOr (listOf str);
7 description = ''7 description = ''
8 List of hosts to encrypt secret for8 List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)
99
10 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners10 Secrets would be decrypted and stored to /run/secrets/$\{name} on owners
11 '';11 '';
12 default = [ ];
13 };12 };
13 # TODO: Aren't those options may be just desugared to data/expectedData?
14 ownerDependent = mkOption {14 regenerateOnOwnerAdded = mkOption {
15 type = bool;15 type = bool;
16 description = "Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted";16 description = ''
17 Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.
18
19 You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.
20 '';
17 };21 };
18 generateImpure = mkOption {
19 type = unspecified;
20 };
21 generator = mkOption {22 regenerateOnOwnerRemoved = mkOption {
22 type = nullOr (submodule {
23 packages = mkOption {
24 type = attrsOf package;
25 description = ''23 default = config.regenerateOnOwnerAdded;
26 Derivation to execute for shared secret generation (key = system).
27 This derivation should produce directory, with exactly two files:
28 - publicData
29 - encryptedSecretData
30
31 If null - secret value may only be created manually.
32 '';
33 };
34 expectedData = mkOption {
35 type = types.unspecified;24 type = bool;
36 description = "Data expected to be used for secret generation, if doesn't match specified - secret should be regenerated";
37 };
38 dependencies = mkOption {
39 type = listOf str;
40 description = ''25 description = ''
41 List of secrets, on which this secret depends.26 Should this secret be removed on owner removal, or it may be just reencrypted
4227
43 During generation, generator command will be ran on host, which already has specified secrets generated.28 Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.
44 '';29 Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked
45 default = [];30 in some other way than by this secret ownership, I.e by firewall/etc.
46 };31 '';
47 data = mkOption {
48 type = types.unspecified;
49 description = "Data used for secret generation. Imported from fleet.nix";
50 default = null;
51 internal = true;
52 };
53 });
54 default = null;
55 };32 };
56 expireIn = mkOption {33 generator = mkOption {
57 type = nullOr int;34 type = nullOr unspecified;
58 description = "Time in hours, in which this secret should be regenerated";35 description = "Derivation to evaluate for secret generation";
59 default = null;36 default = null;
60 };37 };
61 createdAt = mkOption {38 createdAt = mkOption {
62 type = nullOr str;39 type = nullOr str;
40 description = "When this secret was (re)generated";
63 default = null;41 default = null;
64 };42 };
65 expiresAt = mkOption {43 expiresAt = mkOption {
66 type = nullOr str;44 type = nullOr str;
45 description = "On which date this secret will expire, someone should regenerate this secret before it expires.";
67 default = null;46 default = null;
68 };47 };
6948
78 '';57 '';
79 default = [ ];58 default = [ ];
80 };59 };
60 # TODO: Make secret generator generate arbitrary number of secret/public parts?
61 # Make it generate a folder, where all files except suffixed by .enc are public, and the rest are secret?
62 # How should modules refer to those files then?
81 public = mkOption {63 public = mkOption {
82 type = nullOr str;64 type = nullOr str;
83 description = "Secret public data. Imported from fleet.nix";65 description = "Secret public data. Imported from fleet.nix";
90 internal = true;72 internal = true;
91 };73 };
92 };74 };
93 };75 });
94 hostSecret = with types; {76 hostSecret = with types; {
95 options = {77 options = {
96 createdAt = mkOption {78 createdAt = mkOption {
132 config = {114 config = {
133 assertions = mapAttrsToList115 assertions = mapAttrsToList
134 (name: secret: {116 (name: secret: {
135 assertion = builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;117 assertion = secret.expectedOwners == null || builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;
136 message = "Shared secret ${name} is expected to be encrypted for ${builtins.toJSON secret.expectedOwners}, but it is encrypted for ${builtins.toJSON secret.owners}. Run fleet secrets regenerate to fix";118 message = "Shared secret ${name} is expected to be encrypted for ${builtins.toJSON secret.expectedOwners}, but it is encrypted for ${builtins.toJSON secret.owners}. Run fleet secrets regenerate to fix";
137 })119 })
138 config.sharedSecrets;120 config.sharedSecrets;
141 let123 let
142 cleanupSecret = (secretName: v: {124 cleanupSecret = (secretName: v: {
143 inherit (v) public secret;125 inherit (v) public secret;
126 shared = true;
144 });127 });
145 in128 in
146 [129 [
modifiednixos/secrets.nixdiffbeforeafterboth
--- a/nixos/secrets.nix
+++ b/nixos/secrets.nix
@@ -5,7 +5,7 @@
 let
   sysConfig = config;
   secretType = types.submodule ({ config, ... }: {
-    config = let secretName = config._module.args.name; in rec {
+    config = let secretName = config._module.args.name; in {
       stableSecretPath = mkOptionDefault "/run/secrets/secret-stable-${secretName}";
       secretPath = mkOptionDefault "/run/secrets/secret-${config.secretHash}-${secretName}";
       secretHash = mkOptionDefault (if config.secret != null then (builtins.hashString "sha1" config.secret) else throw "secret is not defined for secret ${secretName}");
@@ -14,63 +14,74 @@
       publicPath = mkOptionDefault "/run/secrets/public-${config.publicHash}-${secretName}";
       publicHash = mkOptionDefault (if config.public != null then (builtins.hashString "sha1" config.public) else throw "public is not defined for secret ${secretName}");
     };
-    options = {
+    options = with types; {
+      shared = mkOption {
+        description = "Is this secret owned by this machine, or propagated from shared secrets";
+        default = false;
+      };
+
+      generator = mkOption {
+        type = nullOr unspecified;
+        description = "Derivation to evaluate for secret generation";
+        default = null;
+      };
+
       public = mkOption {
-        type = types.nullOr types.str;
+        type = nullOr str;
         description = "Secret public data";
         default = null;
       };
       secret = mkOption {
-        type = types.nullOr types.str;
+        type = nullOr str;
         description = "Encrypted secret data";
         default = null;
       };
       mode = mkOption {
-        type = types.str;
+        type = str;
         description = "Secret mode";
         default = "0440";
       };
       owner = mkOption {
-        type = types.str;
+        type = str;
         description = "Owner of the secret";
         default = "root";
       };
       group = mkOption {
-        type = types.str;
+        type = str;
         description = "Group of the secret";
         default = sysConfig.users.users.${config.owner}.group;
       };
 
       secretHash = mkOption {
-        type = types.str;
+        type = str;
         description = "Hash of .secret field";
       };
       publicHash = mkOption {
-        type = types.str;
+        type = str;
         description = "Hash of .public field";
       };
 
       stableSecretPath = mkOption {
-        type = types.str;
+        type = str;
         description = ''
           Use this, if target process supports re-reading of secret from disk,
           and doesn't needs to be restarted when secret is updated in file
         '';
       };
       secretPath = mkOption {
-        type = types.str;
+        type = str;
         description = "Path to decrypted secret, suffixed with contents hash";
       };
 
       stablePublicPath = mkOption {
-        type = types.str;
+        type = str;
         description = ''
           Use this, if target process supports re-reading of secret from disk,
           and doesn't needs to be restarted when secret is updated in file
         '';
       };
       publicPath = mkOption {
-        type = types.str;
+        type = str;
         description = "Path to the public part of secret";
       };
     };