difftreelog
fix shared generator condition
in: trunk
10 files changed
cmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -114,7 +114,8 @@
set.spawn_local(
(async move {
- let built = match build_task(config.clone(), hostname.clone(), "toplevel-fleet").await
+ let built = match build_task(config.clone(), hostname.clone(), "toplevel-fleet")
+ .await
{
Ok(path) => path,
Err(e) => {
cmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -632,23 +632,23 @@
let config = config.clone();
let data = config.shared_secret(&name).expect("exists");
/*
- let definition = config.shared_secret_definition(&name)?;
- let expectations = definition.expectations()?;
- let owners = data
- .owners()
- .map(|o| {
- if expectations.owners.contains(o) {
- o.green().to_string()
- } else {
- o.red().to_string()
- }
- })
- .collect::<Vec<_>>();
- table.push(SecretDisplay {
- owners: owners.join(", "),
- name,
- })
-*/
+ let definition = config.shared_secret_definition(&name)?;
+ let expectations = definition.expectations()?;
+ let owners = data
+ .owners()
+ .map(|o| {
+ if expectations.owners.contains(o) {
+ o.green().to_string()
+ } else {
+ o.red().to_string()
+ }
+ })
+ .collect::<Vec<_>>();
+ table.push(SecretDisplay {
+ owners: owners.join(", "),
+ name,
+ })
+ */
}
// info!("loaded\n{}", Table::new(table).to_string())
}
crates/fleet-base/src/fleetdata.rsdiffbeforeafterboth--- a/crates/fleet-base/src/fleetdata.rs
+++ b/crates/fleet-base/src/fleetdata.rs
@@ -153,7 +153,7 @@
#[serde(flatten)]
pub secret: FleetSecretData,
- #[serde(default, skip_serializing, alias="managed")]
+ #[serde(default, skip_serializing, alias = "managed")]
pub _deprecated_managed: bool,
}
crates/nix-eval/src/util.rsdiffbeforeafterboth--- a/crates/nix-eval/src/util.rs
+++ b/crates/nix-eval/src/util.rs
@@ -1,15 +1,23 @@
use std::time::Instant;
use anyhow::bail;
+use serde::Deserialize;
use tracing::{debug, warn};
use crate::{Value, nix_go_json};
+#[derive(Deserialize, Debug)]
+struct Assertion {
+ assertion: bool,
+ message: String,
+}
+
#[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());
+ // let assertions: Vec<Assertion> = nix_go_json!(val.assertions);
+ debug!("errors evaluation took {:?} {errors:?} ", before_errors.elapsed());
if !errors.is_empty() {
bail!(
"failed with error{}{}",
crates/nixlike/Cargo.tomldiffbeforeafterboth--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -7,10 +7,10 @@
[dependencies]
thiserror.workspace = true
+itertools = "0.14.0"
linked-hash-map = "0.5.6"
peg = "0.8.5"
ron = "0.11.0"
serde = { version = "1.0.219", features = ["derive"] }
serde-transcode = "1.1.1"
serde_json = "1.0.140"
-itertools = "0.14.0"
lib/default.nixdiffbeforeafterboth1# Shared functions for fleet configuration, available as `fleet` module argument2{ lib }:3let4 inherit (lib.trivial) isFunction functionArgs;5 inherit (lib.options) mkOption mergeOneOption;6 inherit (lib.modules) mkOverride;7 inherit (lib.types)8 listOf9 submodule10 attrsOf11 mkOptionType12 ;13 inherit (lib.strings) optionalString hasPrefix removePrefix;14in15rec {16 types = {17 overlay = mkOptionType {18 name = "nixpkgs-overlay";19 description = "nixpkgs overlay";20 check = {21 __functor = _self: isFunction;22 isV2MergeCoherent = true;23 };24 merge = mergeOneOption;25 };26 listOfOverlay = listOf types.overlay;2728 mkHostsType = module: attrsOf (submodule module);29 mkDataType = module: submodule module;30 };3132 options = {33 mkHostsOption =34 module:35 mkOption {36 type = types.mkHostsType module;37 };38 mkDataOption =39 module:40 mkOption {41 type = types.mkDataType module;42 };43 };4445 inherit (options) mkHostsOption;4647 modules = {48 /**49 Use in places, where fleet might know better than nixpkgs defaults to50 */51 mkFleetDefault = mkOverride 999;52 /**53 Some generators use mkDefault, but optionDefault is set by nixpkgs.54 */55 mkFleetGeneratorDefault = mkOverride 1001;56 };5758 inherit (modules) mkFleetDefault mkFleetGeneratorDefault;5960 secrets = {6162 /**63 Generate a random secret password, 32 ascii characters by default6465 Options:66 size: generated password length in ascii characters (bytes).67 noSymbols: by default, character set includes various special characters ($ , ! + * : ~), and might68 not be accepted in some contexts, this option switches charset to just [A-Za-z0-9].6970 Output:71 Resulting secret has only part: secret, which contains encrypted password.72 */73 mkPassword =74 {75 size ? 32,76 }:77 (78 {79 coreutils,80 mkSecretGenerator,81 }:82 mkSecretGenerator {83 script = ''84 mkdir $out85 gh generate password -o $out/secret --size ${toStringsize}86 '';87 parts.secret.encrypted = true;88 }89 );9091 /**92 Generate a random ed25519 keypair9394 Options:95 noEmbedPublic: By default, secret key also embeds public key in itself ("extended" format, 64 bytes)96 When noEmbedPublis is enabled - only the private scalar is included.97 encoding: Encoring of public and secret parts, can be "raw" (default), "base64" or "hex".9899 Output:100 Resulting secret has two parts: public and secret, where the secret part is encrypted.101102 This secret format is used by e.g Garage S3 server103 */104 mkEd25519 =105 {106 noEmbedPublic ? false,107 encoding ? null,108 }:109 (110 { mkSecretGenerator }:111 mkSecretGenerator {112 script = ''113 mkdir $out114 gh generate ed25519 -p $out/public -s $out/secret \115 ${optionalStringnoEmbedPublic"--no-embed-public"} \116 ${optionalString(encoding!=null)"--encoding=${encoding}"}117 '';118 parts.secret.encrypted = true;119 parts.public.encrypted = false;120 }121 );122123 /**124 Generate a random x25519 keypair125126 Options:127 encoding: Encoring of public and secret parts, can be "raw" (default), "base64" or "hex".128129 Output:130 Resulting secret has two parts: public and secret, where the secret part is encrypted.131132 This secret format is used by e.g Wireguard VPN for peers (base64-encoded)133 */134 mkX25519 =135 {136 encoding ? null,137 }:138 (139 { mkSecretGenerator }:140 mkSecretGenerator {141 script = ''142 mkdir $out143 gh generate x25519 -p $out/public -s $out/secret \144 ${optionalString(encoding!=null)"--encoding=${encoding}"}145 '';146147 parts.secret.encrypted = true;148 parts.public.encrypted = false;149 }150 );151152 mkAskPass =153 { prompt ? "Secret value", part ? "secret" }:154 (155 {156 kdePackages,157 mkImpureSecretGenerator,158 }:159 mkImpureSecretGenerator {160 # TODO: Escape prompt?161 script = ''162 ${kdePackages.kdialog}/bin/kdialog --inputbox "${prompt}" | gh private -o $out/${part}163 '';164165 parts.${part}.encrypted = true;166 }167 );168169 /**170 Generate a random RSA keypair171172 Options:173 size: RSA key size, 4096 by default174175 Output:176 Resulting secret has two parts: public and secret, where the secret part is encrypted.177 Both parts are PEM encoded.178 */179 mkRsa =180 {181 size ? 4096,182 }:183 (184 {185 openssl,186 mkSecretGenerator,187 }:188 mkSecretGenerator {189 script = ''190 mkdir $out191192 ${openssl}/bin/openssl genrsa -out rsa_private.key ${toStringsize}193 ${openssl}/bin/openssl rsa -in rsa_private.key -pubout -out rsa_public.key194195 cat rsa_private.key | gh private -o $out/secret196 cat rsa_public.key | gh public -o $out/public197 '';198199 parts.secret.encrypted = true;200 parts.public.encrypted = false;201 }202 );203204 /**205 Generate a random byte sequence206207 Options:208 size: generated password length in bytes, 32 by default.209 encoding: how the generated bytes should be encoded, "raw" (default), "hex" or "base64"210 noNuls: prevent output byte sequence from containing internal \0, useful for some C applications211 that can't handle their strings properly.212213 Output:214 Resulting secret has only part: secret, which contains encrypted bytes.215216 Might be used for e.g. Wireguard VPN PSK keys (base64-encoded)217 */218 mkBytes =219 {220 count ? 32,221 encoding,222 noNuls ? false,223 }:224 (225 { mkSecretGenerator }:226 mkSecretGenerator {227 script = ''228 mkdir $out229 gh generate bytes --count=${toStringcount} --encoding=${encoding} -o $out/secret \230 ${optionalStringnoNuls"--no-nuls"}231 '';232 parts.secret.encrypted = true;233 }234 );235 /**236 Shorthand for `mkBytes`, which defaults to "hex" encoding237 */238 mkHexBytes =239 {240 count ? 32,241 }:242 mkBytes {243 inherit count;244 encoding = "hex";245 };246 /**247 Shorthand for `mkBytes`, which defaults to "base64" encoding248 */249 mkBase64Bytes =250 {251 count ? 32,252 }:253 mkBytes {254 inherit count;255 encoding = "base64";256 };257258 # Wireguard259 # mkWireguard = {}: mkX25519 {encoding = "base64";};260 # mkWireguardPsk = {}: mkBase64Bytes {count = 32;};261 };262263 inherit (secrets)264 mkPassword265 mkEd25519266 mkX25519267 mkRsa268 mkBytes269 mkHexBytes270 mkBase64Bytes271 mkAskPass272 ;273274 strings =275 let276 plaintextPrefix = "<PLAINTEXT>";277 plaintextNewlinePrefix = "<PLAINTEXT-NL>";278 in279 {280 /**281 Decode public secret part into string282 */283 decodeRawSecret =284 raw:285 if hasPrefix plaintextPrefix raw then286 removePrefix plaintextPrefix raw287 else if hasPrefix plaintextNewlinePrefix raw then288 removePrefix plaintextNewlinePrefix raw289 else290 throw "decodeRawSecret only works with plaintext-encoded secret public parts, got ${raw}";291 };292293 inherit (strings) decodeRawSecret;294}lib/flakePart.nixdiffbeforeafterboth--- a/lib/flakePart.nix
+++ b/lib/flakePart.nix
@@ -34,7 +34,7 @@
# to do that, evaluate all the modules with only needed option declared.
bootstrapEval = lib.evalModules {
class = "fleet";
- prefix = ["fleetConfiguration"];
+ prefix = [ "fleetConfiguration" ];
modules = [
module
{
@@ -53,7 +53,7 @@
bootstrapNixpkgs = bootstrapEval.config.nixpkgs.buildUsing;
normalEval = bootstrapNixpkgs.lib.evalModules {
class = "fleet";
- prefix = ["fleetConfiguration"];
+ prefix = [ "fleetConfiguration" ];
modules = (import ../modules/module-list.nix) ++ [
module
(
modules/nixos.nixdiffbeforeafterboth--- a/modules/nixos.nix
+++ b/modules/nixos.nix
@@ -39,13 +39,23 @@
in
config.nixpkgs.buildUsing.lib.evalModules {
class = "nixos";
- prefix = ["fleetConfiguration" "hosts" hostArgs.config._module.args.name "nixos"];
+ prefix = [
+ "fleetConfiguration"
+ "hosts"
+ hostArgs.config._module.args.name
+ "nixos"
+ ];
modules = (import "${modulesPath}/module-list.nix") ++ [
(module // { key = "attr<host.nixos>"; })
(config.nixos // { key = "attr<fleet.nixos>"; })
];
specialArgs = {
- inherit fleetLib inputs self modulesPath;
+ inherit
+ fleetLib
+ inputs
+ self
+ modulesPath
+ ;
};
};
};
@@ -54,32 +64,34 @@
};
};
config = {
- nixos = let
- inherit (hostArgs.config) system;
- in {
- _module.args = {
- nixosHosts = mapAttrs (_: value: value.nixos_unchecked.config) config.hosts;
- hosts = config.hosts;
- host = hostArgs.config;
- fleetConfiguration = config;
+ nixos =
+ let
+ inherit (hostArgs.config) system;
+ in
+ {
+ _module.args = {
+ nixosHosts = mapAttrs (_: value: value.nixos_unchecked.config) config.hosts;
+ hosts = config.hosts;
+ host = hostArgs.config;
+ fleetConfiguration = config;
- inputs' = mapAttrs (
- inputName: input:
- builtins.addErrorContext
- "while retrieving system-dependent attributes for input ${escapeNixIdentifier inputName}"
- (
- if input._type or null == "flake" then
- _fleetFlakeRootConfig.perInput system input
- else
- "input is not a flake, perhaps flake = false was added to te input declaration?"
- )
- ) inputs;
- self' = builtins.addErrorContext "while retrieving system-dependent attributes for a flake's own outputs" (
- _fleetFlakeRootConfig.perInput system self
- );
+ inputs' = mapAttrs (
+ inputName: input:
+ builtins.addErrorContext
+ "while retrieving system-dependent attributes for input ${escapeNixIdentifier inputName}"
+ (
+ if input._type or null == "flake" then
+ _fleetFlakeRootConfig.perInput system input
+ else
+ "input is not a flake, perhaps flake = false was added to te input declaration?"
+ )
+ ) inputs;
+ self' = builtins.addErrorContext "while retrieving system-dependent attributes for a flake's own outputs" (
+ _fleetFlakeRootConfig.perInput system self
+ );
+ };
+ nixpkgs.hostPlatform = system;
};
- nixpkgs.hostPlatform = system;
- };
nixos_unchecked = hostArgs.config.nixos.extendModules {
modules = [
{
modules/nixos/secrets.nixdiffbeforeafterboth--- a/modules/nixos/secrets.nix
+++ b/modules/nixos/secrets.nix
@@ -77,7 +77,7 @@
}:
let
secretName = config._module.args.name;
- literal = l: enum [l];
+ literal = l: enum [ l ];
in
{
options = {
@@ -109,17 +109,16 @@
config = {
# C api is broken in regard to thunks
# https://github.com/NixOS/nix/issues/12800
- parts = let
- hostName = host._module.args.name;
- generator = config.generator;
- in builtins.deepSeq [
- hostName
- secretName
- generator
- ] (builtins.fleetEnsureHostSecret
- hostName
- secretName
- generator);
+ parts =
+ let
+ hostName = host._module.args.name;
+ generator = config.generator;
+ in
+ builtins.deepSeq [
+ hostName
+ secretName
+ generator
+ ] (builtins.fleetEnsureHostSecret hostName secretName generator);
};
}
);
@@ -136,14 +135,16 @@
secrets = mkOption {
type = attrsOf secretType;
default = { };
- apply = mapAttrs (_: secret: secret.parts // {definition = secret;});
+ apply = mapAttrs (_: secret: secret.parts // { definition = secret; });
description = "Host-local secrets";
};
system.secretsData = mkOption {
type = unspecified;
- default = mapAttrs (_: s:
- (removeAttrs s.definition ["generator"]) // {
- parts = mapAttrs (_: part: removeAttrs part ["data"]) s.definition.parts;
+ default = mapAttrs (
+ _: s:
+ (removeAttrs s.definition [ "generator" ])
+ // {
+ parts = mapAttrs (_: part: removeAttrs part [ "data" ]) s.definition.parts;
}
) config.secrets;
description = "secrets.json contents";
@@ -152,13 +153,25 @@
config = {
environment.systemPackages = [ pkgs.fleet-install-secrets ];
- assertions = mapAttrsToList (name: secret: let
- hasSharedDefinition = fleetConfiguration.secrets ? name;
- in {
- assertion = (secret.definition.generator == "shared") == hasSharedDefinition && hasSharedDefinition -> (elem host._module.args.name fleetConfiguration.secrets.${name}.expectedOwners);
- message = if hasSharedDefinition then"secret ${name} has host-specific secret generator, secrets with host-specific generators can not have shared generator in fleet configuration"
- else "secret ${name} is declared as shared, for shared secret fleet configuration should include shared secret generator, and expectedOwners should contain this host";
- }) config.secrets;
+ assertions = mapAttrsToList (
+ name: secret:
+ let
+ hasSharedDefinition = fleetConfiguration.secrets ? ${name};
+ in
+ {
+ assertion =
+ (secret.definition.generator == "shared") == hasSharedDefinition
+ && (
+ hasSharedDefinition
+ -> (elem host._module.args.name fleetConfiguration.secrets.${name}.expectedOwners)
+ );
+ message =
+ if hasSharedDefinition then
+ "secret ${name} has host-specific secret generator, secrets with host-specific generators can not have shared generator in fleet configuration"
+ else
+ "secret ${name} is declared as shared, for shared secret fleet configuration should include shared secret generator, and expectedOwners should contain this host";
+ }
+ ) config.secrets;
systemd.services.fleet-install-secrets = mkIf useSysusers {
wantedBy = [ "sysinit.target" ];
modules/nixos/top-level.nixdiffbeforeafterboth--- a/modules/nixos/top-level.nix
+++ b/modules/nixos/top-level.nix
@@ -2,6 +2,7 @@
pkgs,
config,
lib,
+ ...
}:
let
inherit (lib.strings) optionalString;