git.delta.rocks / jrsonnet / refs/commits / 347bd4a9df43

difftreelog

fix do not assert for secret regeneration command

Yaroslav Bolyukin2024-12-03parent: #68ce59a.patch.diff
in: trunk

4 files changed

modifiedcmds/fleet/src/main.rsdiffbeforeafterboth
--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -203,7 +203,13 @@
 		.map(|a| extra_args::parse_os(&a))
 		.transpose()?
 		.unwrap_or_default();
-	let config = opts.fleet_opts.build(nix_args).await?;
+	let config = opts
+		.fleet_opts
+		.build(
+			nix_args,
+			matches!(opts.command, Opts::Deploy(_) | Opts::BuildSystems(_)),
+		)
+		.await?;
 
 	match run_command(&config, opts.fleet_opts, opts.command).await {
 		Ok(()) => {
modifiedcrates/fleet-base/src/opts.rsdiffbeforeafterboth
--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -181,7 +181,7 @@
 	}
 
 	// TODO: Config should be detached from opts.
-	pub async fn build(&self, nix_args: Vec<OsString>) -> Result<Config> {
+	pub async fn build(&self, nix_args: Vec<OsString>, assert: bool) -> Result<Config> {
 		let directory = current_dir()?;
 
 		let pool = NixSessionPool::new(
@@ -204,7 +204,9 @@
 
 		let config_field = nix_go!(fleet_field.config);
 
-		assert_warn("fleet config evaluation", &config_field).await?;
+		if assert {
+			assert_warn("fleet config evaluation", &config_field).await?;
+		}
 
 		let import = nix_go!(builtins_field.import);
 		let overlays = nix_go!(config_field.nixpkgs.overlays);
modifiedcrates/nix-eval/src/util.rsdiffbeforeafterboth
--- a/crates/nix-eval/src/util.rs
+++ b/crates/nix-eval/src/util.rs
@@ -1,17 +1,19 @@
+use std::time::Instant;
+
 use anyhow::bail;
 use tracing::{debug, warn};
-use std::time::Instant;
 
 use crate::{nix_go_json, Value};
 
+#[tracing::instrument(level = "info", skip(val))]
 pub async fn assert_warn(action: &str, val: &Value) -> anyhow::Result<()> {
 	let before_errors = Instant::now();
 	let errors: Vec<String> = nix_go_json!(val.errors);
 	debug!("errors evaluation took {:?}", before_errors.elapsed());
 	if !errors.is_empty() {
 		bail!(
-			"{action} failed with error{}{}",
-			(errors.len() != 1).then_some("s:\n- ").unwrap_or(": "),
+			"failed with error{}{}",
+			if errors.len() != 1 { "s:\n- " } else { ": " },
 			errors.join("\n- "),
 		);
 	}
@@ -21,8 +23,8 @@
 	debug!("warnings evaluation took {:?}", before_errors.elapsed());
 	if !warnings.is_empty() {
 		warn!(
-			"{action} completed with warning{}{}",
-			(warnings.len() != 1).then_some("s:\n- ").unwrap_or(": "),
+			"completed with warning{}{}",
+			if warnings.len() != 1 { "s:\n- " } else { ": " },
 			warnings.join("\n- "),
 		);
 	}
modifiedmodules/secrets-data.nixdiffbeforeafterboth
after · modules/secrets-data.nix
1{2  lib,3  fleetLib,4  config,5  ...6}: let7  inherit (fleetLib.options) mkDataOption;8  inherit (lib.options) mkOption;9  inherit (lib.types) nullOr listOf str attrsOf submodule bool unspecified;10  inherit (lib.attrsets) mapAttrsToList mapAttrs filterAttrs genAttrs;11  inherit (lib.lists) sort unique concatLists;12  inherit (lib.strings) toJSON;1314  secretDataValue = {15    options = {16      raw = mkOption {17        type = nullOr str;18        description = "Encrypted + encoded secret data";19        default = null;20      };21    };22  };2324  sharedSecretData = {25    freeformType = attrsOf (submodule secretDataValue);26    options = {27      createdAt = mkOption {28        type = str;29        description = "When this secret was (re)generated";30        default = null;31      };32      expiresAt = mkOption {33        type = nullOr str;34        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";35        default = null;36      };3738      owners = mkOption {39        type = listOf str;40        description = ''41          For which owners this secret is currently encrypted,42          if not matches expectedOwners - then this secret is considered outdated, and43          should be regenerated/reencrypted.4445          Imported from fleet.nix46        '';47        default = [];48      };49      generationData = mkOption {50        type = unspecified;51        description = "Data that is embedded into secret part";52        default = null;53      };54    };55    config = {};56  };5758  hostSecretData = {59    freeformType = attrsOf (submodule secretDataValue);60    options = {61      createdAt = mkOption {62        type = str;63        description = "When this secret was (re)generated";64        default = null;65      };66      expiresAt = mkOption {67        type = nullOr str;68        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";69        default = null;70      };71      shared = mkOption {72        type = bool;73        description = "On which date this secret will expire, someone should regenerate this secret before it expires.";74        default = false;75      };76      generationData = mkOption {77        type = unspecified;78        description = "Data that is embedded into secret part";79        default = null;80      };81    };82    config = {};83  };84in {85  options.data = mkDataOption ({config, ...}: {86    options = {87      sharedSecrets = mkOption {88        type = attrsOf (submodule sharedSecretData);89        default = {};90        description = "Stored shared secret data.";91      };92      hostSecrets = mkOption {93        type = attrsOf (attrsOf (submodule hostSecretData));94        default = {};95        description = "Host secrets.";96        internal = true;97      };98    };99    config.hostSecrets = let100      hostsWithSharedSecrets = unique (concatLists (mapAttrsToList (_: s: s.owners) config.sharedSecrets));101      secretsHavingHost = host: filterAttrs (_: secret: lib.elem host secret.owners) config.sharedSecrets;102      toHostSecret = _: secret: (removeAttrs secret ["owners"]) // {shared = true;};103    in104      genAttrs hostsWithSharedSecrets (host: mapAttrs toHostSecret (secretsHavingHost host));105  });106  config = {107    assertions =108      (mapAttrsToList109        (name: secret: {110          assertion = secret.expectedOwners == null || sort (a: b: a < b) config.data.sharedSecrets.${name}.owners == sort (a: b: a < b) secret.expectedOwners;111          message = "Shared secret ${name} is expected to be encrypted for ${toJSON secret.expectedOwners}, but it is encrypted for ${toJSON config.data.sharedSecrets.${name}.owners}. Run fleet secrets regenerate to fix";112        })113        config.sharedSecrets)114      ++ (mapAttrsToList115        (name: secret: {116          # TODO: Same aassertion should be in host secrets117          assertion = config.data.sharedSecrets.${name}.generationData == secret.expectedGenerationData;118          message = "Shared secret ${name} has unexpected generation data ${toJSON secret.expectedGenerationData} != ${toJSON config.data.sharedSecrets.${name}.expectedGenerationData}. Run fleet secrets regenerate to fix";119        })120        config.sharedSecrets);121    sharedSecrets =122      mapAttrs (_: _: {}) config.data.sharedSecrets;123  };124}