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
before · cmds/fleet/src/cmds/secrets/mod.rs
1use crate::{2	better_nix_eval::Field,3	fleetdata::{FleetSecret, FleetSharedSecret, SecretData},4	host::Config,5	nix_go, nix_go_json,6};7use anyhow::{anyhow, bail, ensure, Context, Result};8use chrono::{DateTime, Utc};9use clap::Parser;10use futures::StreamExt;11use itertools::Itertools;12use owo_colors::OwoColorize;13use std::{14	collections::HashSet,15	io::{self, Cursor, Read},16	path::PathBuf,17};18use tabled::{Table, Tabled};19use tokio::fs::read_to_string;20use tracing::{info, info_span, warn};2122#[derive(Parser)]23pub enum Secret {24	/// Force load host keys for all defined hosts25	ForceKeys,26	/// Add secret, data should be provided in stdin27	AddShared {28		/// Secret name29		name: String,30		/// Secret owners31		machines: Vec<String>,32		/// Override secret if already present33		#[clap(long)]34		force: bool,35		/// Secret public part36		#[clap(long)]37		public: Option<String>,38		/// Load public part from specified file39		#[clap(long)]40		public_file: Option<PathBuf>,4142		/// Create a notification on secret expiration43		#[clap(long)]44		expires_at: Option<DateTime<Utc>>,4546		/// Secret with this name already exists, override its value while keeping the same owners.47		#[clap(long)]48		re_add: bool,49	},50	/// Add secret, data should be provided in stdin51	Add {52		/// Secret name53		name: String,54		/// Secret owners55		machine: String,56		/// Override secret if already present57		#[clap(long)]58		force: bool,59		#[clap(long)]60		public: Option<String>,61		#[clap(long)]62		public_file: Option<PathBuf>,63	},64	/// Read secret from remote host, requires sudo on said host65	Read {66		name: String,67		machine: String,68		#[clap(long)]69		plaintext: bool,70	},71	UpdateShared {72		name: String,7374		#[clap(long)]75		machines: Option<Vec<String>>,7677		#[clap(long)]78		add_machines: Vec<String>,79		#[clap(long)]80		remove_machines: Vec<String>,8182		/// Which host should we use to decrypt83		#[clap(long)]84		prefer_identities: Vec<String>,85	},86	Regenerate {87		/// Which host should we use to decrypt, in case if reencryption is required, without88		/// regeneration89		#[clap(long)]90		prefer_identities: Vec<String>,91	},92	List {},93}9495async fn generate_shared(96	config: &Config,97	display_name: &str,98	secret: Field,99) -> Result<FleetSharedSecret> {100	Ok(if secret.has_field("generateImpure").await? {101		let config_field = &config.config_unchecked_field;102		let generate = nix_go!(secret.generateImpure);103		let owners: Vec<String> = nix_go_json!(secret.expectedOwners);104105		let on: String = nix_go_json!(generate.on);106		let call_package = nix_go!(107			config_field.buildableSystems(Obj {108				localSystem: { config.local_system.clone() }109			})[{ on }]110			.config111			.nixpkgs112			.resolvedPkgs113			.callPackage114		);115116		let host = config.host(&on).await?;117118		let generator = nix_go!(call_package(generate.generator)(Obj {}));119		let generator = generator.build().await?;120		let generator = generator121			.get("out")122			.ok_or_else(|| anyhow!("missing generateImpure out"))?;123		let generator = host.remote_derivation(generator).await?;124125		let mut recipients = String::new();126		for owner in &owners {127			let key = config.key(owner).await?;128			recipients.push_str(&format!("-r \"{key}\" "));129		}130		recipients.push_str("-e");131132		let out = host.mktemp_dir().await?;133134		let mut gen = host.cmd(generator).await?;135		gen.env("rageArgs", recipients).env("out", &out);136		gen.run().await?;137138		{139			let marker = host.read_file_text(format!("{out}/marker")).await?;140			ensure!(marker == "SUCCESS", "generation not succeeded");141		}142143		let public = host.read_file_text(format!("{out}/public")).await.ok();144		let secret = host.read_file_bin(format!("{out}/secret")).await.ok();145		if let Some(secret) = &secret {146			ensure!(147				age::Decryptor::new(Cursor::new(&secret)).is_ok(),148				"builder produced non-encrypted value as secret, this is highly insecure"149			);150		}151152		let created_at = host.read_file_value(format!("{out}/created_at")).await?;153		let expires_at = host.read_file_value(format!("{out}/expires_at")).await.ok();154155		FleetSharedSecret {156			owners,157			secret: FleetSecret {158				created_at,159				expires_at,160				public,161				secret: secret.map(SecretData),162			},163		}164	} else {165		bail!("no generator defined for {display_name}")166	})167}168169async fn parse_public(170	public: Option<String>,171	public_file: Option<PathBuf>,172) -> Result<Option<String>> {173	Ok(match (public, public_file) {174		(Some(v), None) => Some(v),175		(None, Some(v)) => Some(read_to_string(v).await?),176		(Some(_), Some(_)) => {177			bail!("only public or public_file should be set")178		}179		(None, None) => None,180	})181}182183fn parse_machines(184	initial: Vec<String>,185	machines: Option<Vec<String>>,186	mut add_machines: Vec<String>,187	mut remove_machines: Vec<String>,188) -> Result<Vec<String>> {189	if machines.is_none() && add_machines.is_empty() && remove_machines.is_empty() {190		bail!("no operation");191	}192193	let initial_machines = initial.clone();194	let mut target_machines = initial;195	info!("Currently encrypted for {initial_machines:?}");196197	// ensure!(machines.is_some() || !add_machines.is_empty() || )198	if let Some(machines) = machines {199		ensure!(200			add_machines.is_empty() && remove_machines.is_empty(),201			"can't combine --machines and --add-machines/--remove-machines"202		);203		let target = initial_machines.iter().collect::<HashSet<_>>();204		let source = machines.iter().collect::<HashSet<_>>();205		for removed in target.difference(&source) {206			remove_machines.push((*removed).clone());207		}208		for added in source.difference(&target) {209			add_machines.push((*added).clone());210		}211	}212213	for machine in &remove_machines {214		let mut removed = false;215		while let Some(pos) = target_machines.iter().position(|m| m == machine) {216			target_machines.swap_remove(pos);217			removed = true;218		}219		if !removed {220			warn!("secret is not enabled for {machine}");221		}222	}223	for machine in &add_machines {224		if target_machines.iter().any(|m| m == machine) {225			warn!("secret is already added to {machine}");226		} else {227			target_machines.push(machine.to_owned());228		}229	}230	if !remove_machines.is_empty() {231		// TODO: maybe force secret regeneration?232		// Not that useful without revokation.233		warn!("secret will not be regenerated for removed machines, and until host rebuild, they will still possess the ability to decode secret");234	}235	Ok(target_machines)236}237impl Secret {238	pub async fn run(self, config: &Config) -> Result<()> {239		match self {240			Secret::ForceKeys => {241				for host in config.list_hosts().await? {242					if config.should_skip(&host.name) {243						continue;244					}245					config.key(&host.name).await?;246				}247			}248			Secret::AddShared {249				mut machines,250				name,251				force,252				public,253				public_file,254				expires_at,255				re_add,256			} => {257				let exists = config.has_shared(&name);258				if exists && !force && !re_add {259					bail!("secret already defined");260				}261				if re_add {262					// Fixme: use clap to limit this usage263					ensure!(!force, "--force and --readd are not compatible");264					ensure!(exists, "secret doesn't exists");265					ensure!(266						machines.is_empty(),267						"you can't use machines argument for --readd"268					);269					let shared = config.shared_secret(&name)?;270					machines = shared.owners;271				}272273				let recipients = config274					.recipients(&machines.iter().map(String::as_str).collect_vec())275					.await?;276277				let secret = {278					let mut input = vec![];279					io::stdin().read_to_end(&mut input)?;280281					if input.is_empty() {282						None283					} else {284						Some(285							SecretData::encrypt(recipients, input)286								.ok_or_else(|| anyhow!("no recipients provided"))?,287						)288					}289				};290				let public = parse_public(public, public_file).await?;291				config.replace_shared(292					name,293					FleetSharedSecret {294						owners: machines,295						secret: FleetSecret {296							created_at: Utc::now(),297							expires_at,298							secret,299							public,300						},301					},302				);303			}304			Secret::Add {305				machine,306				name,307				force,308				public,309				public_file,310			} => {311				let recipient = config.recipient(&machine).await?;312313				let secret = {314					let mut input = vec![];315					io::stdin().read_to_end(&mut input)?;316					if input.is_empty() {317						bail!("no data provided")318					}319320					Some(SecretData::encrypt(vec![recipient], input).expect("recipient provided"))321				};322323				if config.has_secret(&machine, &name) && !force {324					bail!("secret already defined");325				}326				let public = parse_public(public, public_file).await?;327328				config.insert_secret(329					&machine,330					name,331					FleetSecret {332						created_at: Utc::now(),333						expires_at: None,334						secret,335						public,336					},337				);338			}339			#[allow(clippy::await_holding_refcell_ref)]340			Secret::Read {341				name,342				machine,343				plaintext,344			} => {345				let secret = config.host_secret(&machine, &name)?;346				let Some(secret) = secret.secret else {347					bail!("no secret {name}");348				};349				let host = config.host(&machine).await?;350				let data = host.decrypt(secret).await?;351				if plaintext {352					let s = String::from_utf8(data).context("output is not utf8")?;353					print!("{s}");354				} else {355					println!("{}", z85::encode(&data));356				}357			}358			Secret::UpdateShared {359				name,360				machines,361				add_machines,362				remove_machines,363				prefer_identities,364			} => {365				let mut secret = config.shared_secret(&name)?;366				if secret.secret.secret.is_none() {367					bail!("no secret");368				}369370				let initial_machines = secret.owners.clone();371				let target_machines = parse_machines(372					initial_machines.clone(),373					machines,374					add_machines,375					remove_machines,376				)?;377378				if target_machines.is_empty() {379					info!("no machines left for secret, removing it");380					config.remove_shared(&name);381					return Ok(());382				}383384				if target_machines == initial_machines {385					warn!("secret owners are already correct");386					return Ok(());387				}388389				let identity_holder = if !prefer_identities.is_empty() {390					prefer_identities391						.iter()392						.find(|i| initial_machines.iter().any(|s| s == *i))393				} else {394					secret.owners.first()395				};396				let Some(identity_holder) = identity_holder else {397					bail!("no available holder found");398				};399				let target_recipients = futures::stream::iter(&target_machines)400					.then(|m| async { config.key(m).await })401					.collect::<Vec<_>>()402					.await;403				let target_recipients =404					target_recipients.into_iter().collect::<Result<Vec<_>>>()?;405406				if let Some(data) = secret.secret.secret {407					let host = config.host(&identity_holder).await?;408					let encrypted = host.reencrypt(data, target_recipients).await?;409					secret.secret.secret = Some(encrypted);410				}411412				secret.owners = target_machines;413				config.replace_shared(name, secret);414			}415			Secret::Regenerate { prefer_identities } => {416				{417					let expected_shared_set = config418						.list_configured_shared()419						.await?420						.into_iter()421						.collect::<HashSet<_>>();422					let shared_set = config.list_shared().into_iter().collect::<HashSet<_>>();423					for removed in expected_shared_set.difference(&shared_set) {424						info!("generating secret: {removed}");425						let config_field = &config.config_unchecked_field;426						let config_field = nix_go!(config_field.configUnchecked);427						let secret = nix_go!(config_field.sharedSecrets[{ removed }]);428						let shared = generate_shared(config, removed, secret).await?;429						config.replace_shared(removed.to_string(), shared)430					}431				}432				let mut to_remove = Vec::new();433				for name in &config.list_shared() {434					info!("updating secret: {name}");435					let mut data = config.shared_secret(name)?;436					let config_field = &config.config_unchecked_field;437					let config_field = nix_go!(config_field.configUnchecked);438					let expected_owners: Vec<String> =439						nix_go_json!(config_field.sharedSecrets[{ name }].expectedOwners);440					if expected_owners.is_empty() {441						warn!("secret was removed from fleet config: {name}, removing from data");442						to_remove.push(name.to_string());443						continue;444					}445					let set = data.owners.iter().collect::<HashSet<_>>();446					let expected_set = expected_owners.iter().collect::<HashSet<_>>();447					let should_remove = set.difference(&expected_set).next().is_some();448					if set == expected_set {449						info!("secret data is ok");450						continue;451					}452453					let secret = nix_go!(config_field.sharedSecrets[{ name }]);454					let owner_dependent: bool = nix_go_json!(secret.ownerDependent);455					let regenerate_on_remove: bool = nix_go_json!(secret.regenerateOnOwnerRemoved);456					#[allow(clippy::nonminimal_bool)]457					if !owner_dependent && !(should_remove && regenerate_on_remove) {458						warn!("reencrypting secret '{name}' for new owner set");459						// TODO: force regeneration460						if should_remove {461							warn!("secret will not be regenerated for removed machines, and until host rebuild, they will still possess the ability to decode secret");462						}463464						let identity_holder = if !prefer_identities.is_empty() {465							prefer_identities466								.iter()467								.find(|i| data.owners.iter().any(|s| s == *i))468						} else {469							data.owners.first()470						};471						let Some(identity_holder) = identity_holder else {472							bail!("no available holder found");473						};474475						let target_recipients = futures::stream::iter(&expected_owners)476							.then(|m| async { config.key(m).await })477							.collect::<Vec<_>>()478							.await;479						let target_recipients =480							target_recipients.into_iter().collect::<Result<Vec<_>>>()?;481482						if let Some(secret) = data.secret.secret {483							let host = config.host(identity_holder).await?;484							let encrypted = host.reencrypt(secret, target_recipients).await?;485486							data.secret.secret = Some(encrypted);487						}488						data.owners = expected_owners;489						config.replace_shared(name.to_owned(), data);490					} else {491						let shared = generate_shared(config, name, secret).await?;492						config.replace_shared(name.to_owned(), shared)493					}494				}495				for k in to_remove {496					config.remove_shared(&k);497				}498			}499			Secret::List {} => {500				let _span = info_span!("loading secrets").entered();501				let configured = config.list_configured_shared().await?;502				#[derive(Tabled)]503				struct SecretDisplay {504					#[tabled(rename = "Name")]505					name: String,506					#[tabled(rename = "Owners")]507					owners: String,508				}509				let mut table = vec![];510				for name in configured.iter().cloned() {511					let config = config.clone();512					let expected_owners = config.shared_secret_expected_owners(&name).await?;513					let data = config.shared_secret(&name)?;514					let owners = data515						.owners516						.iter()517						.map(|o| {518							if expected_owners.contains(o) {519								o.green().to_string()520							} else {521								o.red().to_string()522							}523						})524						.collect::<Vec<_>>();525					table.push(SecretDisplay {526						owners: owners.join(", "),527						name,528					})529				}530				info!("loaded\n{}", Table::new(table).to_string())531			}532		}533		Ok(())534	}535}
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
--- a/modules/fleet/secrets.nix
+++ b/modules/fleet/secrets.nix
@@ -1,69 +1,48 @@
 { lib, fleetLib, config, ... }: with lib; with fleetLib;
 let
-  sharedSecret = with types; {
+  sharedSecret = with types; ({config, ...}: {
     options = {
       expectedOwners = mkOption {
-        type = listOf str;
+        type = nullOr (listOf str);
         description = ''
-          List of hosts to encrypt secret for
+          List of hosts to encrypt secret for. null if managed by user (= via owners field from fleet.nix)
 
           Secrets would be decrypted and stored to /run/secrets/$\{name} on owners
         '';
-        default = [ ];
       };
-      ownerDependent = mkOption {
+      # TODO: Aren't those options may be just desugared to data/expectedData?
+      regenerateOnOwnerAdded = mkOption {
         type = bool;
-        description = "Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted";
+        description = ''
+          Is this secret owner-dependent, and needs to be regenerated on ownership set change, or it may be just reencrypted.
+          
+          You want to have this option set to true, when this secret contains some reference to its owners, i.e x509 SANs.
+        '';
       };
-      generateImpure = mkOption {
-        type = unspecified;
+      regenerateOnOwnerRemoved = mkOption {
+        default = config.regenerateOnOwnerAdded;
+        type = bool;
+        description = ''
+          Should this secret be removed on owner removal, or it may be just reencrypted
+          
+          Most probably its value should be equal to regenerateOnOwnerAdded, override only if you know what are you doing.
+          Contrary to regenerateOnOwnerAdded, you may want to set this option to false, when host permissions are revoked
+          in some other way than by this secret ownership, I.e by firewall/etc.
+        '';
       };
       generator = mkOption {
-        type = nullOr (submodule {
-          packages = mkOption {
-            type = attrsOf package;
-            description = ''
-              Derivation to execute for shared secret generation (key = system).
-              This derivation should produce directory, with exactly two files:
-                - publicData
-                - encryptedSecretData
-
-              If null - secret value may only be created manually.
-            '';
-          };
-          expectedData = mkOption {
-            type = types.unspecified;
-            description = "Data expected to be used for secret generation, if doesn't match specified - secret should be regenerated";
-          };
-          dependencies = mkOption {
-            type = listOf str;
-            description = ''
-              List of secrets, on which this secret depends.
-
-              During generation, generator command will be ran on host, which already has specified secrets generated.
-            '';
-            default = [];
-          };
-          data = mkOption {
-            type = types.unspecified;
-            description = "Data used for secret generation. Imported from fleet.nix";
-            default = null;
-            internal = true;
-          };
-        });
-        default = null;
-      };
-      expireIn = mkOption {
-        type = nullOr int;
-        description = "Time in hours, in which this secret should be regenerated";
+        type = nullOr unspecified;
+        description = "Derivation to evaluate for secret generation";
         default = null;
       };
       createdAt = mkOption {
         type = nullOr str;
+        description = "When this secret was (re)generated";
         default = null;
       };
       expiresAt = mkOption {
         type = nullOr str;
+        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";
         default = null;
       };
 
@@ -78,6 +57,9 @@
         '';
         default = [ ];
       };
+      # TODO: Make secret generator generate arbitrary number of secret/public parts?
+      # Make it generate a folder, where all files except suffixed by .enc are public, and the rest are secret?
+      # How should modules refer to those files then?
       public = mkOption {
         type = nullOr str;
         description = "Secret public data. Imported from fleet.nix";
@@ -90,7 +72,7 @@
         internal = true;
       };
     };
-  };
+  });
   hostSecret = with types; {
     options = {
       createdAt = mkOption {
@@ -132,7 +114,7 @@
   config = {
     assertions = mapAttrsToList
       (name: secret: {
-        assertion = builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;
+        assertion = secret.expectedOwners == null || builtins.sort (a: b: a < b) secret.owners == builtins.sort (a: b: a < b) secret.expectedOwners;
         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";
       })
       config.sharedSecrets;
@@ -141,6 +123,7 @@
         let
           cleanupSecret = (secretName: v: {
             inherit (v) public secret;
+            shared = true;
           });
         in
         [
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";
       };
     };