git.delta.rocks / jrsonnet / refs/commits / 757475fe4cab

difftreelog

feat manager identities

ytxvryoyYaroslav Bolyukin2025-07-29parent: #34f0c72.patch.diff
in: trunk

7 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -92,6 +92,8 @@
  "scrypt",
  "sha2",
  "subtle",
+ "which",
+ "wsl",
  "x25519-dalek",
  "zeroize",
 ]
@@ -111,6 +113,7 @@
  "rand 0.8.5",
  "secrecy",
  "sha2",
+ "tempfile",
 ]
 
 [[package]]
@@ -1286,6 +1289,15 @@
 ]
 
 [[package]]
+name = "home"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
 name = "hostname"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3639,6 +3651,18 @@
 ]
 
 [[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix 0.38.40",
+]
+
+[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3776,6 +3800,12 @@
 ]
 
 [[package]]
+name = "wsl"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dab7ac864710bdea6594becbea5b5050333cf34fefb0dc319567eb347950d4"
+
+[[package]]
 name = "x25519-dalek"
 version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,7 +11,7 @@
 nix-eval = { path = "./crates/nix-eval" }
 nixlike = { path = "./crates/nixlike" }
 
-age = { version = "0.11", features = ["ssh"] }
+age = { version = "0.11", features = ["ssh", "plugin"] }
 anyhow = "1.0"
 clap = { version = "4.5", features = ["derive", "env", "unicode", "wrap_help"] }
 clap_complete = "4.5"
modifiedcmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -23,6 +23,7 @@
 
 #[derive(Parser)]
 pub enum Secret {
+	AddManager,
 	/// Force load host keys for all defined hosts
 	ForceKeys,
 	/// Add secret, data should be provided in stdin
@@ -521,6 +522,9 @@
 impl Secret {
 	pub async fn run(self, config: &Config, opts: &FleetOpts) -> Result<()> {
 		match self {
+			Secret::AddManager => {
+				todo!("part of fleet-pusher")
+			}
 			Secret::ForceKeys => {
 				for host in config.list_hosts().await? {
 					if opts.should_skip(&host).await? {
modifiedcrates/fleet-base/src/fleetdata.rsdiffbeforeafterboth
--- a/crates/fleet-base/src/fleetdata.rs
+++ b/crates/fleet-base/src/fleetdata.rs
@@ -53,12 +53,22 @@
 
 #[derive(Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
+pub struct ManagerKey {
+	pub name: String,
+	pub key: String,
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
 pub struct FleetData {
 	pub version: FleetDataVersion,
 	#[serde(default = "generate_gc_prefix")]
 	pub gc_root_prefix: String,
 
 	#[serde(default)]
+	pub manager_keys: Vec<ManagerKey>,
+
+	#[serde(default)]
 	pub hosts: BTreeMap<String, HostData>,
 	#[serde(default)]
 	#[serde(skip_serializing_if = "BTreeMap::is_empty")]
modifiedflake.lockdiffbeforeafterboth
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "crane": {
       "locked": {
-        "lastModified": 1750266157,
-        "narHash": "sha256-tL42YoNg9y30u7zAqtoGDNdTyXTi8EALDeCB13FtbQA=",
+        "lastModified": 1753316655,
+        "narHash": "sha256-tzWa2kmTEN69OEMhxFy+J2oWSvZP5QhEgXp3TROOzl0=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "e37c943371b73ed87faf33f7583860f81f1d5a48",
+        "rev": "f35a3372d070c9e9ccb63ba7ce347f0634ddf3d2",
         "type": "github"
       },
       "original": {
@@ -22,11 +22,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1749398372,
-        "narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=",
+        "lastModified": 1753121425,
+        "narHash": "sha256-TVcTNvOeWWk1DXljFxVRp+E0tzG1LhrVjOGGoMHuXio=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569",
+        "rev": "644e0fc48951a860279da645ba77fe4a6e814c5e",
         "type": "github"
       },
       "original": {
@@ -37,11 +37,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1750895632,
-        "narHash": "sha256-EPZWiRmaSTxoBArK5dQyRlSNVLXiBt2hmsYIPgMf3zk=",
+        "lastModified": 1753320130,
+        "narHash": "sha256-KCuv6iYQ0XTVAEJvDLIsk99CJm7fuqIE0/KknyeYPtM=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "6ac57ce7fee0d80226095a57ccb7519855ad7c5e",
+        "rev": "788cc7374af486168b8aab6ca49e316c03508a86",
         "type": "github"
       },
       "original": {
@@ -68,11 +68,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1750819193,
-        "narHash": "sha256-XvkupGPZqD54HuKhN/2WhbKjAHeTl1UEnWspzUzRFfA=",
+        "lastModified": 1753238793,
+        "narHash": "sha256-jmQeEpgX+++MEgrcikcwoSiI7vDZWLP0gci7XiWb9uQ=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "1ba3b9c59b68a4b00156827ad46393127b51b808",
+        "rev": "0ad7ab4ca8e83febf147197e65c006dff60623ab",
         "type": "github"
       },
       "original": {
@@ -103,11 +103,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1749194973,
-        "narHash": "sha256-eEy8cuS0mZ2j/r/FE0/LYBSBcIs/MKOIVakwHVuqTfk=",
+        "lastModified": 1753006367,
+        "narHash": "sha256-tzbhc4XttkyEhswByk5R38l+ztN9UDbnj0cTcP6Hp9A=",
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "a05be418a1af1198ca0f63facb13c985db4cb3c5",
+        "rev": "421b56313c65a0815a52b424777f55acf0b56ddf",
         "type": "github"
       },
       "original": {
modifiedmodules/secrets-data.nixdiffbeforeafterboth
before · modules/secrets-data.nix
1{2  lib,3  fleetLib,4  config,5  ...6}:7let8  inherit (fleetLib.options) mkDataOption;9  inherit (lib.options) mkOption;10  inherit (lib.types)11    nullOr12    listOf13    str14    attrsOf15    submodule16    bool17    unspecified18    ;19  inherit (lib.attrsets)20    mapAttrsToList21    mapAttrs22    filterAttrs23    genAttrs24    ;25  inherit (lib.lists) sort unique concatLists;26  inherit (lib.strings) toJSON;2728  secretDataValue = {29    options = {30      raw = mkOption {31        type = nullOr str;32        description = "Raw secret data in unspecified encoded and optionally encrypted format.";33        default = null;34      };35    };36  };3738  sharedSecretData = {39    freeformType = attrsOf (submodule secretDataValue);40    options = {41      createdAt = mkOption {42        type = str;43        description = "Timestamp of secret generation/last rotation.";44        default = null;45      };46      expiresAt = mkOption {47        type = nullOr str;48        description = "Expiration timestamp triggering mandatory secret rotation.";49        default = null;50      };5152      owners = mkOption {53        type = listOf str;54        description = ''55          List of hosts currently authorized to decrypt this shared secret.5657          If owners differ from expected owners, the secret is considered outdated58          and requires regeneration or re-encryption.59        '';60        default = [ ];61      };62      generationData = mkOption {63        type = unspecified;64        description = "Contextual metadata associated with secret part.";65        default = null;66      };67    };68    config = { };69  };7071  hostSecretData = {72    freeformType = attrsOf (submodule secretDataValue);73    options = {74      createdAt = mkOption {75        type = str;76        description = "Timestamp of secret generation/last rotation.";77        default = null;78      };79      expiresAt = mkOption {80        type = nullOr str;81        description = "Expiration timestamp triggering mandatory secret rotation.";82        default = null;83      };84      shared = mkOption {85        type = bool;86        description = "Indicates if secret is a shared secret, so other hosts might have the same piece of secret data.";87        default = false;88      };89      generationData = mkOption {90        type = unspecified;91        description = "Contextual metadata associated with secret part.";92        default = null;93      };94    };95    config = { };96  };97in98{99  options.data = mkDataOption (100    { config, ... }:101    {102      options = {103        sharedSecrets = mkOption {104          type = attrsOf (submodule sharedSecretData);105          default = { };106          description = "Shared secret data.";107        };108        hostSecrets = mkOption {109          type = attrsOf (attrsOf (submodule hostSecretData));110          default = { };111          description = "Host-specific secrets.";112          internal = true;113        };114      };115      config.hostSecrets =116        let117          hostsWithSharedSecrets = unique (118            concatLists (mapAttrsToList (_: s: s.owners) config.sharedSecrets)119          );120          secretsHavingHost = host: filterAttrs (_: secret: lib.elem host secret.owners) config.sharedSecrets;121          toHostSecret = _: secret: (removeAttrs secret [ "owners" ]) // { shared = true; };122        in123        genAttrs hostsWithSharedSecrets (host: mapAttrs toHostSecret (secretsHavingHost host));124    }125  );126  config = {127    assertions =128      (mapAttrsToList (name: secret: {129        assertion =130          secret.expectedOwners == null131          ||132            sort (a: b: a < b) (config.data.sharedSecrets.${name} or { owners = [ ]; }).owners133            == sort (a: b: a < b) secret.expectedOwners;134        message = "Shared secret ${name} is expected to be encrypted for ${toJSON secret.expectedOwners}, but it is encrypted for ${135          toJSON (config.data.sharedSecrets.${name} or { owners = [ ]; }).owners136        }. Run fleet secrets regenerate to fix";137      }) config.sharedSecrets)138      ++ (mapAttrsToList (name: secret: {139        # TODO: Same aassertion should be in host secrets140        assertion =141          (config.data.sharedSecrets.${name} or { generationData = null; }).generationData142          == secret.expectedGenerationData;143        message = "Shared secret ${name} has unexpected generation data ${toJSON secret.expectedGenerationData} != ${144          toJSON (config.data.sharedSecrets.${name} or { generationData = null; }).generationData145        }. Run fleet secrets regenerate to fix";146      }) config.sharedSecrets);147    sharedSecrets = mapAttrs (_: _: { }) config.data.sharedSecrets;148  };149}
modifiedrust-toolchain.tomldiffbeforeafterboth
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "1.86.0"
+channel = "nightly-2025-06-10"
 components = ["rustfmt", "clippy", "rust-analyzer", "rust-src"]