difftreelog
style add treefmt
in: trunk
27 files changed
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,12 +12,12 @@
nix-eval = { path = "./crates/nix-eval" }
tokio = { version = "1.36.0", features = [
- "fs",
- "rt",
- "macros",
- "sync",
- "time",
- "rt-multi-thread",
+ "fs",
+ "rt",
+ "macros",
+ "sync",
+ "time",
+ "rt-multi-thread",
] }
tokio-util = { version = "0.7.11", features = ["codec"] }
clap = { version = "4.5", features = ["derive", "env", "wrap_help", "unicode"] }
cmds/fleet/Cargo.tomldiffbeforeafterboth--- a/cmds/fleet/Cargo.toml
+++ b/cmds/fleet/Cargo.toml
@@ -32,8 +32,8 @@
shlex = "1.3"
tabled = { version = "0.16" }
owo-colors = { version = "4.0", features = [
- "supports-color",
- "supports-colors",
+ "supports-color",
+ "supports-colors",
] }
abort-on-drop = "0.2"
regex = "1.10"
@@ -52,8 +52,8 @@
default = ["indicatif"]
# Not quite stable
indicatif = [
- "dep:tracing-indicatif",
- "dep:indicatif",
- "dep:human-repr",
- "better-command/indicatif",
+ "dep:tracing-indicatif",
+ "dep:indicatif",
+ "dep:human-repr",
+ "better-command/indicatif",
]
cmds/install-secrets/src/main.rsdiffbeforeafterboth--- a/cmds/install-secrets/src/main.rs
+++ b/cmds/install-secrets/src/main.rs
@@ -200,7 +200,7 @@
if data.is_empty() {
info!("no secrets to install");
- return Ok(())
+ return Ok(());
}
let identity = host_identity()?;
crates/nixlike/fuzz/fuzz_targets/fuzz_target_1.rsdiffbeforeafterboth--- a/crates/nixlike/fuzz/fuzz_targets/fuzz_target_1.rs
+++ b/crates/nixlike/fuzz/fuzz_targets/fuzz_target_1.rs
@@ -2,8 +2,8 @@
use libfuzzer_sys::fuzz_target;
fuzz_target!(|data: String| {
- let serialized = nixlike::serialize(data.clone()).unwrap();
- let deserialized: String = nixlike::parse_str(&serialized).unwrap();
-
- assert_eq!(data, deserialized);
+ let serialized = nixlike::serialize(data.clone()).unwrap();
+ let deserialized: String = nixlike::parse_str(&serialized).unwrap();
+
+ assert_eq!(data, deserialized);
});
flake.lockdiffbeforeafterboth--- a/flake.lock
+++ b/flake.lock
@@ -57,7 +57,8 @@
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay",
- "shelly": "shelly"
+ "shelly": "shelly",
+ "treefmt-nix": "treefmt-nix"
}
},
"rust-overlay": {
@@ -94,6 +95,26 @@
"repo": "shelly",
"type": "github"
}
+ },
+ "treefmt-nix": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1744961264,
+ "narHash": "sha256-aRmUh0AMwcbdjJHnytg1e5h5ECcaWtIFQa6d9gI85AI=",
+ "owner": "numtide",
+ "repo": "treefmt-nix",
+ "rev": "8d404a69efe76146368885110f29a2ca3700bee6",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "treefmt-nix",
+ "type": "github"
+ }
}
},
"root": "root",
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -1,5 +1,5 @@
{
- description = "NixOS configuration management";
+ description = "NixOS cluster configuration management";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/release-24.11";
@@ -13,6 +13,10 @@
};
crane.url = "github:ipetkov/crane";
shelly.url = "github:CertainLach/shelly";
+ treefmt-nix = {
+ url = "github:numtide/treefmt-nix";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
};
outputs =
inputs:
@@ -75,6 +79,7 @@
config,
system,
pkgs,
+ self,
...
}:
let
@@ -92,6 +97,7 @@
lib = pkgs.lib;
rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rust;
+ treefmt = (inputs.treefmt-nix.lib.evalModule pkgs ./treefmt.nix).config.build;
in
{
_module.args.pkgs = import inputs.nixpkgs {
@@ -128,7 +134,10 @@
# with rust in nixpkgs.
(prefixAttrs "nixpkgs-" {
inherit (packages) fleet-install-secrets;
- });
+ })
+ // {
+ checks.formatting = treefmt.check self;
+ };
# TODO: It should be possible to move lib.mkIf to default attribute, instead of disabling the whole
# devShells block, yet nix flake check fails here, due to no default shell found. It is nix or flake-parts bug?
shelly.shells.default = lib.mkIf deployerSystem {
@@ -151,7 +160,7 @@
];
environment.PROTOC = "${pkgs.protobuf}/bin/protoc";
};
- formatter = pkgs.alejandra;
+ formatter = treefmt.wrapper;
};
};
}
lib/default.nixdiffbeforeafterboth--- a/lib/default.nix
+++ b/lib/default.nix
@@ -1,11 +1,18 @@
# Shared functions for fleet configuration, available as `fleet` module argument
-{lib}: let
+{ lib }:
+let
inherit (lib.trivial) isFunction;
inherit (lib.options) mkOption mergeOneOption;
inherit (lib.modules) mkOverride;
- inherit (lib.types) listOf submodule attrsOf mkOptionType;
+ inherit (lib.types)
+ listOf
+ submodule
+ attrsOf
+ mkOptionType
+ ;
inherit (lib.strings) optionalString hasPrefix removePrefix;
-in rec {
+in
+rec {
types = {
overlay = mkOptionType {
name = "nixpkgs-overlay";
@@ -20,11 +27,13 @@
};
options = {
- mkHostsOption = module:
+ mkHostsOption =
+ module:
mkOption {
type = types.mkHostsType module;
};
- mkDataOption = module:
+ mkDataOption =
+ module:
mkOption {
type = types.mkDataType module;
};
@@ -57,10 +66,14 @@
Output:
Resulting secret has only part: secret, which contains encrypted password.
*/
- mkPassword = {size ? 32}: {
- coreutils,
- mkSecretGenerator,
- }:
+ mkPassword =
+ {
+ size ? 32,
+ }:
+ {
+ coreutils,
+ mkSecretGenerator,
+ }:
mkSecretGenerator {
script = ''
mkdir $out
@@ -81,10 +94,12 @@
This secret format is used by e.g Garage S3 server
*/
- mkEd25519 = {
- noEmbedPublic ? false,
- encoding ? null,
- }: {mkSecretGenerator}:
+ mkEd25519 =
+ {
+ noEmbedPublic ? false,
+ encoding ? null,
+ }:
+ { mkSecretGenerator }:
mkSecretGenerator {
script = ''
mkdir $out
@@ -105,7 +120,11 @@
This secret format is used by e.g Wireguard VPN for peers (base64-encoded)
*/
- mkX25519 = {encoding ? null}: {mkSecretGenerator}:
+ mkX25519 =
+ {
+ encoding ? null,
+ }:
+ { mkSecretGenerator }:
mkSecretGenerator {
script = ''
mkdir $out
@@ -124,10 +143,14 @@
Resulting secret has two parts: public and secret, where the secret part is encrypted.
Both parts are PEM encoded.
*/
- mkRsa = {size ? 4096}: {
- openssl,
- mkSecretGenerator,
- }:
+ mkRsa =
+ {
+ size ? 4096,
+ }:
+ {
+ openssl,
+ mkSecretGenerator,
+ }:
mkSecretGenerator {
script = ''
mkdir $out
@@ -154,11 +177,13 @@
Might be used for e.g. Wireguard VPN PSK keys (base64-encoded)
*/
- mkBytes = {
- count ? 32,
- encoding,
- noNuls ? false,
- }: {mkSecretGenerator}:
+ mkBytes =
+ {
+ count ? 32,
+ encoding,
+ noNuls ? false,
+ }:
+ { mkSecretGenerator }:
mkSecretGenerator {
script = ''
mkdir $out
@@ -169,7 +194,10 @@
/**
Shorthand for `mkBytes`, which defaults to "hex" encoding
*/
- mkHexBytes = {count ? 32}:
+ mkHexBytes =
+ {
+ count ? 32,
+ }:
mkBytes {
inherit count;
encoding = "hex";
@@ -177,7 +205,10 @@
/**
Shorthand for `mkBytes`, which defaults to "base64" encoding
*/
- mkBase64Bytes = {count ? 32}:
+ mkBase64Bytes =
+ {
+ count ? 32,
+ }:
mkBytes {
inherit count;
encoding = "base64";
@@ -188,22 +219,34 @@
# mkWireguardPsk = {}: mkBase64Bytes {count = 32;};
};
- inherit (secrets) mkPassword mkEd25519 mkX25519 mkRsa mkBytes mkHexBytes mkBase64Bytes;
+ inherit (secrets)
+ mkPassword
+ mkEd25519
+ mkX25519
+ mkRsa
+ mkBytes
+ mkHexBytes
+ mkBase64Bytes
+ ;
- strings = let
- plaintextPrefix = "<PLAINTEXT>";
- plaintextNewlinePrefix = "<PLAINTEXT-NL>";
- in {
- /**
- Decode public secret part into string
- */
- decodeRawSecret = raw:
- if hasPrefix plaintextPrefix raw
- then removePrefix plaintextPrefix raw
- else if hasPrefix plaintextNewlinePrefix raw
- then removePrefix plaintextNewlinePrefix raw
- else throw "decodeRawSecret only works with plaintext-encoded secret public parts, got ${raw}";
- };
+ strings =
+ let
+ plaintextPrefix = "<PLAINTEXT>";
+ plaintextNewlinePrefix = "<PLAINTEXT-NL>";
+ in
+ {
+ /**
+ Decode public secret part into string
+ */
+ decodeRawSecret =
+ raw:
+ if hasPrefix plaintextPrefix raw then
+ removePrefix plaintextPrefix raw
+ else if hasPrefix plaintextNewlinePrefix raw then
+ removePrefix plaintextNewlinePrefix raw
+ else
+ throw "decodeRawSecret only works with plaintext-encoded secret public parts, got ${raw}";
+ };
inherit (strings) decodeRawSecret;
}
lib/flakePart.nixdiffbeforeafterboth--- a/lib/flakePart.nix
+++ b/lib/flakePart.nix
@@ -1,20 +1,28 @@
-{crane}: {
+{ crane }:
+{
fleetLib,
lib,
config,
inputs,
self,
...
-}: let
+}:
+let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.attrsets) mapAttrs;
- inherit (lib.types) lazyAttrsOf deferredModule unspecified str;
+ inherit (lib.types)
+ lazyAttrsOf
+ deferredModule
+ unspecified
+ str
+ ;
inherit (lib.strings) isPath;
inherit (lib.modules) mkIf mkOptionDefault;
-in {
+in
+{
options.fleetModules = mkOption {
type = lazyAttrsOf unspecified;
- default = {};
+ default = { };
};
options.fleetNixosConfigurationsCompat = {
enable = mkEnableOption "Create nixosConfiguration output based on fleetConfiguration";
@@ -30,9 +38,11 @@
};
options.fleetConfigurations = mkOption {
type = lazyAttrsOf deferredModule;
- apply = nameToModule:
+ apply =
+ nameToModule:
mapAttrs (
- name: module: data: let
+ name: module: data:
+ let
# To use user-provided nixpkgs, we first need to extract wanted nixpkgs attribute,
# to do that, evaluate all the modules with only needed option declared.
bootstrapEval = lib.evalModules {
@@ -53,28 +63,27 @@
};
bootstrapNixpkgs = bootstrapEval.config.nixpkgs.buildUsing;
normalEval = bootstrapNixpkgs.lib.evalModules {
- modules =
- (import ../modules/module-list.nix)
- ++ [
- module
- {
- config = {
- data =
- if isPath data
- then import data
- else data;
- nixpkgs.buildUsing = mkOptionDefault bootstrapNixpkgs;
- nixpkgs.overlays = [
- (final: prev: {
- inherit (import ../pkgs {
+ modules = (import ../modules/module-list.nix) ++ [
+ module
+ {
+ config = {
+ data = if isPath data then import data else data;
+ nixpkgs.buildUsing = mkOptionDefault bootstrapNixpkgs;
+ nixpkgs.overlays = [
+ (final: prev: {
+ inherit
+ (import ../pkgs {
inherit (prev) callPackage;
craneLib = crane.mkLib prev;
- }) fleet-install-secrets fleet-generator-helper;
- })
- ];
- };
- }
- ];
+ })
+ fleet-install-secrets
+ fleet-generator-helper
+ ;
+ })
+ ];
+ };
+ }
+ ];
specialArgs = {
inherit inputs self;
fleetLib = import ../lib {
@@ -84,21 +93,19 @@
};
};
in
- normalEval
- )
- nameToModule;
+ normalEval
+ ) nameToModule;
};
config = {
- _module.args.fleetLib = import ../lib {inherit lib;};
+ _module.args.fleetLib = import ../lib { inherit lib; };
flake.fleetConfigurations = config.fleetConfigurations;
- flake.nixosConfigurations = let
- cfg = config.fleetNixosConfigurationsCompat;
- in
- mkIf cfg.enable
- (
- mapAttrs
- (name: host: host.nixos)
- (config.fleetConfigurations.${cfg.configuration} cfg.data).config.hosts
+ flake.nixosConfigurations =
+ let
+ cfg = config.fleetNixosConfigurationsCompat;
+ in
+ mkIf cfg.enable (
+ mapAttrs (name: host: host.nixos)
+ (config.fleetConfigurations.${cfg.configuration} cfg.data).config.hosts
);
flake.fleetModules = config.fleetModules;
};
modules/assertions.nixdiffbeforeafterboth--- a/modules/assertions.nix
+++ b/modules/assertions.nix
@@ -2,7 +2,8 @@
lib,
config,
...
-}: let
+}:
+let
inherit (lib.options) mkOption;
inherit (lib.types) listOf unspecified str;
inherit (lib.lists) map filter;
@@ -14,12 +15,13 @@
Similar to warnings, however build will fail if any error exists.
'';
};
-in {
+in
+{
options = {
assertions = mkOption {
type = listOf unspecified;
internal = true;
- default = [];
+ default = [ ];
example = [
{
assertion = false;
@@ -35,9 +37,9 @@
warnings = mkOption {
internal = true;
- default = [];
+ default = [ ];
type = listOf str;
- example = ["The `foo' service is deprecated and will go away soon!"];
+ example = [ "The `foo' service is deprecated and will go away soon!" ];
description = ''
This option allows modules to show warnings to users during
the evaluation of the system configuration.
@@ -47,18 +49,16 @@
inherit errors;
};
config = {
- errors =
- map (v: v.message)
- (filter (v: !v.assertion) config.assertions);
+ errors = map (v: v.message) (filter (v: !v.assertion) config.assertions);
- nixos = {config, ...}: {
- _file = ./assertions.nix;
- options = {
- inherit errors;
+ nixos =
+ { config, ... }:
+ {
+ _file = ./assertions.nix;
+ options = {
+ inherit errors;
+ };
+ config.errors = map (v: v.message) (filter (v: !v.assertion) config.assertions);
};
- config.errors =
- map (v: v.message)
- (filter (v: !v.assertion) config.assertions);
- };
};
}
modules/extras/tf.nixdiffbeforeafterboth--- a/modules/extras/tf.nix
+++ b/modules/extras/tf.nix
@@ -4,15 +4,18 @@
fleetLib,
inputs,
...
-}: let
+}:
+let
inherit (lib.options) mkOption;
inherit (lib.types) deferredModule attrsOf unspecified;
inherit (fleetLib.options) mkDataOption;
-in {
+in
+{
options = {
tf = mkOption {
type = deferredModule;
- apply = module: system:
+ apply =
+ module: system:
inputs.terranix.lib.terranixConfiguration {
inherit system;
pkgs = config.nixpkgs.buildUsing.legacyPackages.${system};
@@ -24,7 +27,7 @@
data = mkDataOption {
# host => hostData
options.extra.terraformHosts = mkOption {
- default = {};
+ default = { };
type = attrsOf (attrsOf unspecified);
description = "Hosts data provided by fleet tf";
};
modules/fleetLib.nixdiffbeforeafterboth--- a/modules/fleetLib.nix
+++ b/modules/fleetLib.nix
@@ -1,4 +1,5 @@
-{lib, ...}: {
+{ lib, ... }:
+{
_module.args.fleetLib = import ../../lib {
inherit lib;
};
modules/hosts.nixdiffbeforeafterboth--- a/modules/hosts.nix
+++ b/modules/hosts.nix
@@ -3,14 +3,21 @@
fleetLib,
config,
...
-}: let
+}:
+let
inherit (fleetLib.modules) mkFleetGeneratorDefault;
inherit (fleetLib.types) mkHostsType mkDataType;
inherit (lib.options) mkOption;
- inherit (lib.types) str listOf attrsOf submodule;
+ inherit (lib.types)
+ str
+ listOf
+ attrsOf
+ submodule
+ ;
inherit (lib.attrsets) mapAttrsToList mapAttrs;
inherit (lib.lists) flatten groupBy;
-in {
+in
+{
# Fleet Meta Configuration Module
options = {
@@ -52,60 +59,68 @@
};
hosts = mkOption {
- type = mkHostsType ({config, ...}: {
- options = {
- system = mkOption {
- description = "System architecture and platform identifier";
- type = str;
- example = "x86_64-linux";
- };
+ type = mkHostsType (
+ { config, ... }:
+ {
+ options = {
+ system = mkOption {
+ description = "System architecture and platform identifier";
+ type = str;
+ example = "x86_64-linux";
+ };
- tags = mkOption {
- description = ''
- Tags for host classification.
- Used for host selection via @tag syntax in CLI tools.
- '';
- type = listOf str;
- };
+ tags = mkOption {
+ description = ''
+ Tags for host classification.
+ Used for host selection via @tag syntax in CLI tools.
+ '';
+ type = listOf str;
+ };
- # Network configuration details
- network = mkOption {
- type = submodule {
- options = {
- internalIps = mkOption {
- description = "List of internal IP addresses for the host";
- type = listOf str;
- default = [];
- };
+ # Network configuration details
+ network = mkOption {
+ type = submodule {
+ options = {
+ internalIps = mkOption {
+ description = "List of internal IP addresses for the host";
+ type = listOf str;
+ default = [ ];
+ };
- externalIps = mkOption {
- description = "List of external IP addresses for the host";
- type = listOf str;
- default = [];
+ externalIps = mkOption {
+ description = "List of external IP addresses for the host";
+ type = listOf str;
+ default = [ ];
+ };
};
};
};
};
- };
- config = {
- # Default hostname generation
- nixos.networking.hostName = mkFleetGeneratorDefault config._module.args.name;
- # Default 'all' tag for every host
- tags = ["all"];
- };
- _file = ./meta.nix;
- });
- default = {};
+ config = {
+ # Default hostname generation
+ nixos.networking.hostName = mkFleetGeneratorDefault config._module.args.name;
+ # Default 'all' tag for every host
+ tags = [ "all" ];
+ };
+ _file = ./meta.nix;
+ }
+ );
+ default = { };
};
};
# Generate a mapping of hosts indexed by their tags
- config.taggedWith = let
- # Flatten host tags into a list of {hostname, tag} pairs
- hostTagList = flatten (mapAttrsToList (hostname: host: map (tag: {inherit hostname tag;}) host.tags) config.hosts);
- # Group hostnames by their tags
- grouped = mapAttrs (_: hosts: lib.map (pair: pair.hostname) hosts) (groupBy (elem: elem.tag) hostTagList);
- in
+ config.taggedWith =
+ let
+ # Flatten host tags into a list of {hostname, tag} pairs
+ hostTagList = flatten (
+ mapAttrsToList (hostname: host: map (tag: { inherit hostname tag; }) host.tags) config.hosts
+ );
+ # Group hostnames by their tags
+ grouped = mapAttrs (_: hosts: lib.map (pair: pair.hostname) hosts) (
+ groupBy (elem: elem.tag) hostTagList
+ );
+ in
grouped;
# Source file reference
modules/meta.nixdiffbeforeafterboth--- a/modules/meta.nix
+++ b/modules/meta.nix
@@ -1,7 +1,9 @@
-{lib, ...}: let
+{ lib, ... }:
+let
inherit (lib.modules) mkRemovedOptionModule;
-in {
+in
+{
imports = [
- (mkRemovedOptionModule ["fleetModules"] "replaced with imports.")
+ (mkRemovedOptionModule [ "fleetModules" ] "replaced with imports.")
];
}
modules/nixos.nixdiffbeforeafterboth--- a/modules/nixos.nix
+++ b/modules/nixos.nix
@@ -6,7 +6,8 @@
config,
_fleetFlakeRootConfig,
...
-}: let
+}:
+let
inherit (lib.attrsets) mapAttrs;
inherit (lib.options) mkOption;
inherit (lib.types) deferredModule unspecified;
@@ -15,7 +16,8 @@
inherit (fleetLib.options) mkHostsOption;
_file = ./nixos.nix;
-in {
+in
+{
options = {
nixos = mkOption {
description = ''
@@ -31,26 +33,33 @@
Nixos configuration for the current host.
'';
type = deferredModule;
- apply = module: let
- inherit (hostArgs.config) system;
- in
+ apply =
+ module:
+ let
+ inherit (hostArgs.config) system;
+ in
config.nixpkgs.buildUsing.lib.nixosSystem {
inherit system;
modules = [
- (module // {key = "attr<host.nixos>";})
- (config.nixos // {key = "attr<fleet.nixos>";})
+ (module // { key = "attr<host.nixos>"; })
+ (config.nixos // { key = "attr<fleet.nixos>"; })
];
specialArgs = {
inherit fleetLib inputs 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);
+ 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
+ );
};
};
};
@@ -80,8 +89,7 @@
});
};
imports = [
- (mkRemovedOptionModule ["nixosModules"] "replaced with nixos.imports.")
+ (mkRemovedOptionModule [ "nixosModules" ] "replaced with nixos.imports.")
];
- config.nixos.imports =
- import ./nixos/module-list.nix;
+ config.nixos.imports = import ./nixos/module-list.nix;
}
modules/nixos/nix-sign.nixdiffbeforeafterboth--- a/modules/nixos/nix-sign.nix
+++ b/modules/nixos/nix-sign.nix
@@ -3,15 +3,17 @@
lib,
config,
...
-}: let
+}:
+let
inherit (lib.modules) mkIf;
hasPersistentHostname = config.networking.hostName != "";
-in {
+in
+{
# https://github.com/NixOS/nix/issues/3023
systemd.services.generate-nix-cache-key = mkIf hasPersistentHostname {
- wantedBy = ["multi-user.target"];
+ wantedBy = [ "multi-user.target" ];
serviceConfig.Type = "oneshot";
- path = [config.nix.package];
+ path = [ config.nix.package ];
script = ''
[[ -f /etc/nix/private-key ]] && exit
nix-store --generate-binary-cache-key ${config.networking.hostName}-1 /etc/nix/private-key /etc/nix/public-key
modules/nixos/online.nixdiffbeforeafterboth--- a/modules/nixos/online.nix
+++ b/modules/nixos/online.nix
@@ -2,29 +2,41 @@
config,
lib,
...
-}: let
+}:
+let
inherit (lib.options) mkOption;
- inherit (lib.types) attrsOf str submodule either listOf lines bool;
+ inherit (lib.types)
+ attrsOf
+ str
+ submodule
+ either
+ listOf
+ lines
+ bool
+ ;
inherit (lib.attrsets) mapAttrs;
inherit (lib.trivial) isString;
-in {
+in
+{
options.system.onlineActivationScripts = mkOption {
- default = {};
- type = attrsOf (either str (submodule {
- options = {
- deps = mkOption {
- type = listOf str;
- default = [];
+ default = { };
+ type = attrsOf (
+ either str (submodule {
+ options = {
+ deps = mkOption {
+ type = listOf str;
+ default = [ ];
+ };
+ text = mkOption {
+ type = lines;
+ };
+ supportsDryActivation = mkOption {
+ type = bool;
+ default = false;
+ };
};
- text = mkOption {
- type = lines;
- };
- supportsDryActivation = mkOption {
- type = bool;
- default = false;
- };
- };
- }));
+ })
+ );
description = ''
Same as activation scripts, but only ran on online activation (i.e when operator is actively running fleet deploy, and not on system restart)
@@ -32,42 +44,40 @@
we should not apply outdated ceph monmap.
'';
- apply = set:
+ apply =
+ set:
mapAttrs (
name: value:
- if isString value
- then {
+ if isString value then
+ {
+ text = ''
+ if [ ! -z ''${FLEET_ONLINE_ACTIVATION+x} ]; then
+ ${value}
+ fi
+ '';
+ deps = [ "onlineActivation" ];
+ }
+ else
+ value
+ // {
+ deps = [ "onlineActivation" ] ++ value.deps;
text = ''
if [ ! -z ''${FLEET_ONLINE_ACTIVATION+x} ]; then
- ${value}
+ ${value.text}
fi
'';
- deps = ["onlineActivation"];
}
- else
- value
- // {
- deps = ["onlineActivation"] ++ value.deps;
- text = ''
- if [ ! -z ''${FLEET_ONLINE_ACTIVATION+x} ]; then
- ${value.text}
- fi
- '';
- }
- )
- set;
+ ) set;
};
- config.system.activationScripts =
- {
- onlineActivation = {
- text = ''
- if [ ! -z ''${FLEET_ONLINE_ACTIVATION+x} ]; then
- 1>&2 echo "online activation; hello, fleet!"
- fi
- '';
- supportsDryActivation = true;
- };
- }
- // config.system.onlineActivationScripts;
+ config.system.activationScripts = {
+ onlineActivation = {
+ text = ''
+ if [ ! -z ''${FLEET_ONLINE_ACTIVATION+x} ]; then
+ 1>&2 echo "online activation; hello, fleet!"
+ fi
+ '';
+ supportsDryActivation = true;
+ };
+ } // config.system.onlineActivationScripts;
}
modules/nixos/rollback.nixdiffbeforeafterboth--- a/modules/nixos/rollback.nix
+++ b/modules/nixos/rollback.nix
@@ -1,5 +1,6 @@
# Tied to build_systems.rs
-{config, ...}: {
+{ config, ... }:
+{
# TODO: Make it work with systemd-initrd approach.
# In this case we can't just switch generation and re-run activation script, since the root filesystem might not be
# mounted yet. We need to explicitly remove the last generation, and this needs deeper integration with systemd/grub/
@@ -36,7 +37,7 @@
systemd.timers.rollback-watchdog = {
description = "Timer for rollback watchdog";
- wantedBy = ["timers.target"];
+ wantedBy = [ "timers.target" ];
timerConfig = {
OnActiveSec = "3min";
RemainAfterElapse = false;
modules/nixos/secrets.nixdiffbeforeafterboth--- a/modules/nixos/secrets.nix
+++ b/modules/nixos/secrets.nix
@@ -4,125 +4,149 @@
config,
pkgs,
...
-}: let
+}:
+let
inherit (builtins) hashString;
inherit (lib.stringsWithDeps) stringAfter;
inherit (lib.options) mkOption literalExpression;
inherit (lib.lists) optional;
inherit (lib.attrsets) mapAttrs;
inherit (lib.modules) mkIf;
- inherit (lib.types) submodule str attrsOf nullOr unspecified lazyAttrsOf uniq functionTo package;
+ inherit (lib.types)
+ submodule
+ str
+ attrsOf
+ nullOr
+ unspecified
+ lazyAttrsOf
+ uniq
+ functionTo
+ package
+ ;
inherit (fleetLib.strings) decodeRawSecret;
sysConfig = config;
- secretPartType = secretName:
- submodule ({config, ...}: let
- partName = config._module.args.name;
- in {
+ secretPartType =
+ secretName:
+ submodule (
+ { config, ... }:
+ let
+ partName = config._module.args.name;
+ in
+ {
+ options = {
+ raw = mkOption {
+ type = str;
+ internal = true;
+ description = "Encoded & Encrypted secret part data, passed from fleet.nix";
+ };
+ hash = mkOption {
+ type = str;
+ description = "Hash of secret in encoded format";
+ };
+ path = mkOption {
+ type = str;
+ description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";
+ };
+ stablePath = mkOption {
+ type = str;
+ description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";
+ };
+ data = mkOption {
+ type = str;
+ description = "Secret public data (only available for plaintext)";
+ };
+ };
+ config = {
+ hash = hashString "sha1" config.raw;
+ data = decodeRawSecret config.raw;
+ path = "/run/secrets/${secretName}/${config.hash}-${partName}";
+ stablePath = "/run/secrets/${secretName}/${partName}";
+ };
+ }
+ );
+ secretType = submodule (
+ { config, ... }:
+ let
+ secretName = config._module.args.name;
+ in
+ {
+ freeformType = lazyAttrsOf (secretPartType secretName);
options = {
- raw = mkOption {
- type = str;
- internal = true;
- description = "Encoded & Encrypted secret part data, passed from fleet.nix";
+ shared = mkOption {
+ description = "Is this secret owned by this machine, or propagated from shared secrets";
+ default = false;
+ };
+
+ generator = mkOption {
+ type = uniq (nullOr (functionTo package));
+ description = "Derivation to evaluate for secret generation";
+ default = null;
};
- hash = mkOption {
+ mode = mkOption {
type = str;
- description = "Hash of secret in encoded format";
+ description = "Secret mode";
+ default = "0440";
};
- path = mkOption {
+ owner = mkOption {
type = str;
- description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";
+ description = "Owner of the secret";
+ default = "root";
};
- stablePath = mkOption {
+ group = mkOption {
type = str;
- description = "Path to secret part, incorporating data hash (thus it will be updated on secret change)";
+ description = "Group of the secret";
+ default = sysConfig.users.users.${config.owner}.group;
+ defaultText = literalExpression "config.users.users.$${owner}.group";
};
- data = mkOption {
- type = str;
- description = "Secret public data (only available for plaintext)";
+ expectedGenerationData = mkOption {
+ type = unspecified;
+ description = "Data that gets embedded into secret part";
+ default = null;
};
- };
- config = {
- hash = hashString "sha1" config.raw;
- data = decodeRawSecret config.raw;
- path = "/run/secrets/${secretName}/${config.hash}-${partName}";
- stablePath = "/run/secrets/${secretName}/${partName}";
};
- });
- secretType = submodule ({config, ...}: let
- secretName = config._module.args.name;
- in {
- freeformType = lazyAttrsOf (secretPartType secretName);
- options = {
- shared = mkOption {
- description = "Is this secret owned by this machine, or propagated from shared secrets";
- default = false;
- };
-
- generator = mkOption {
- type = uniq (nullOr (functionTo package));
- description = "Derivation to evaluate for secret generation";
- default = null;
- };
- mode = mkOption {
- type = str;
- description = "Secret mode";
- default = "0440";
- };
- owner = mkOption {
- type = str;
- description = "Owner of the secret";
- default = "root";
- };
- group = mkOption {
- type = str;
- description = "Group of the secret";
- default = sysConfig.users.users.${config.owner}.group;
- defaultText = literalExpression "config.users.users.$${owner}.group";
- };
- expectedGenerationData = mkOption {
- type = unspecified;
- description = "Data that gets embedded into secret part";
- default = null;
- };
- };
- });
+ }
+ );
processPart = part: {
inherit (part) raw path stablePath;
};
- processSecret = secret:
+ processSecret =
+ secret:
{
inherit (secret) group mode owner;
}
- // (mapAttrs (_: processPart) (removeAttrs secret [
- "shared"
- "generator"
- "mode"
- "group"
- "owner"
- "expectedGenerationData"
- ]));
+ // (mapAttrs (_: processPart) (
+ removeAttrs secret [
+ "shared"
+ "generator"
+ "mode"
+ "group"
+ "owner"
+ "expectedGenerationData"
+ ]
+ ));
secretsFile = pkgs.writeTextFile {
name = "secrets.json";
- text =
- builtins.toJSON (mapAttrs (_: processSecret)
- config.secrets);
+ text = builtins.toJSON (mapAttrs (_: processSecret) config.secrets);
};
- useSysusers = (config.systemd ? sysusers && config.systemd.sysusers.enable) || (config ? userborn && config.userborn.enable);
-in {
+ useSysusers =
+ (config.systemd ? sysusers && config.systemd.sysusers.enable)
+ || (config ? userborn && config.userborn.enable);
+in
+{
options = {
secrets = mkOption {
type = attrsOf secretType;
- default = {};
+ default = { };
description = "Host-local secrets";
};
};
config = {
- environment.systemPackages = [pkgs.fleet-install-secrets];
+ environment.systemPackages = [ pkgs.fleet-install-secrets ];
systemd.services.fleet-install-secrets = mkIf useSysusers {
- wantedBy = ["sysinit.target"];
- after = ["systemd-sysusers.service"];
+ wantedBy = [ "sysinit.target" ];
+ after = [ "systemd-sysusers.service" ];
restartTriggers = [
secretsFile
];
@@ -139,10 +163,9 @@
ExecStart = "${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}";
};
};
- system.activationScripts.decryptSecrets =
- mkIf (!useSysusers)
- (
- stringAfter (
+ system.activationScripts.decryptSecrets = mkIf (!useSysusers) (
+ stringAfter
+ (
[
# secrets are owned by user/group, thus we need to refer to those
"users"
@@ -153,10 +176,11 @@
# but with impermanence we expect that the host-key is installed by
# persist-file activation script.
++ (optional (config.system.activationScripts ? "persist-files") "persist-files")
- ) ''
+ )
+ ''
1>&2 echo "setting up secrets"
${pkgs.fleet-install-secrets}/bin/fleet-install-secrets install ${secretsFile}
''
- );
+ );
};
}
modules/nixpkgs.nixdiffbeforeafterboth--- a/modules/nixpkgs.nix
+++ b/modules/nixpkgs.nix
@@ -3,7 +3,8 @@
fleetLib,
config,
...
-}: let
+}:
+let
inherit (lib.options) mkOption literalExpression;
inherit (lib.types) path;
inherit (lib.modules) mkRemovedOptionModule;
@@ -11,7 +12,8 @@
inherit (fleetLib.types) listOfOverlay;
_file = ./nixpkgs.lib;
-in {
+in
+{
options = {
nixpkgs = {
buildUsing = mkOption {
@@ -48,7 +50,10 @@
inherit _file;
nixpkgs.overlays = config.nixpkgs.overlays;
imports = [
- (mkRemovedOptionModule ["nixpkgs" "buildUsing"] "this option should be specified at the host level, not the nixosModules level")
+ (mkRemovedOptionModule [
+ "nixpkgs"
+ "buildUsing"
+ ] "this option should be specified at the host level, not the nixosModules level")
];
};
};
modules/secrets-data.nixdiffbeforeafterboth--- a/modules/secrets-data.nix
+++ b/modules/secrets-data.nix
@@ -3,11 +3,25 @@
fleetLib,
config,
...
-}: let
+}:
+let
inherit (fleetLib.options) mkDataOption;
inherit (lib.options) mkOption;
- inherit (lib.types) nullOr listOf str attrsOf submodule bool unspecified;
- inherit (lib.attrsets) mapAttrsToList mapAttrs filterAttrs genAttrs;
+ inherit (lib.types)
+ nullOr
+ listOf
+ str
+ attrsOf
+ submodule
+ bool
+ unspecified
+ ;
+ inherit (lib.attrsets)
+ mapAttrsToList
+ mapAttrs
+ filterAttrs
+ genAttrs
+ ;
inherit (lib.lists) sort unique concatLists;
inherit (lib.strings) toJSON;
@@ -43,7 +57,7 @@
If owners differ from expected owners, the secret is considered outdated
and requires regeneration or re-encryption.
'';
- default = [];
+ default = [ ];
};
generationData = mkOption {
type = unspecified;
@@ -51,7 +65,7 @@
default = null;
};
};
- config = {};
+ config = { };
};
hostSecretData = {
@@ -78,46 +92,56 @@
default = null;
};
};
- config = {};
+ config = { };
};
-in {
- options.data = mkDataOption ({config, ...}: {
- options = {
- sharedSecrets = mkOption {
- type = attrsOf (submodule sharedSecretData);
- default = {};
- description = "Shared secret data.";
+in
+{
+ options.data = mkDataOption (
+ { config, ... }:
+ {
+ options = {
+ sharedSecrets = mkOption {
+ type = attrsOf (submodule sharedSecretData);
+ default = { };
+ description = "Shared secret data.";
+ };
+ hostSecrets = mkOption {
+ type = attrsOf (attrsOf (submodule hostSecretData));
+ default = { };
+ description = "Host-specific secrets.";
+ internal = true;
+ };
};
- hostSecrets = mkOption {
- type = attrsOf (attrsOf (submodule hostSecretData));
- default = {};
- description = "Host-specific secrets.";
- internal = true;
- };
- };
- config.hostSecrets = let
- hostsWithSharedSecrets = unique (concatLists (mapAttrsToList (_: s: s.owners) config.sharedSecrets));
- secretsHavingHost = host: filterAttrs (_: secret: lib.elem host secret.owners) config.sharedSecrets;
- toHostSecret = _: secret: (removeAttrs secret ["owners"]) // {shared = true;};
- in
- genAttrs hostsWithSharedSecrets (host: mapAttrs toHostSecret (secretsHavingHost host));
- });
+ config.hostSecrets =
+ let
+ hostsWithSharedSecrets = unique (
+ concatLists (mapAttrsToList (_: s: s.owners) config.sharedSecrets)
+ );
+ secretsHavingHost = host: filterAttrs (_: secret: lib.elem host secret.owners) config.sharedSecrets;
+ toHostSecret = _: secret: (removeAttrs secret [ "owners" ]) // { shared = true; };
+ in
+ genAttrs hostsWithSharedSecrets (host: mapAttrs toHostSecret (secretsHavingHost host));
+ }
+ );
config = {
assertions =
- (mapAttrsToList
- (name: secret: {
- assertion = secret.expectedOwners == null || sort (a: b: a < b) config.data.sharedSecrets.${name}.owners == sort (a: b: a < b) secret.expectedOwners;
- 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";
- })
- config.sharedSecrets)
- ++ (mapAttrsToList
- (name: secret: {
- # TODO: Same aassertion should be in host secrets
- assertion = config.data.sharedSecrets.${name}.generationData == secret.expectedGenerationData;
- message = "Shared secret ${name} has unexpected generation data ${toJSON secret.expectedGenerationData} != ${toJSON config.data.sharedSecrets.${name}.expectedGenerationData}. Run fleet secrets regenerate to fix";
- })
- config.sharedSecrets);
- sharedSecrets =
- mapAttrs (_: _: {}) config.data.sharedSecrets;
+ (mapAttrsToList (name: secret: {
+ assertion =
+ secret.expectedOwners == null
+ ||
+ sort (a: b: a < b) (config.data.sharedSecrets.${name} or { owners = [ ]; }).owners
+ == sort (a: b: a < b) secret.expectedOwners;
+ 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";
+ }) config.sharedSecrets)
+ ++ (mapAttrsToList (name: secret: {
+ # TODO: Same aassertion should be in host secrets
+ assertion = config.data.sharedSecrets.${name}.generationData == secret.expectedGenerationData;
+ message = "Shared secret ${name} has unexpected generation data ${toJSON secret.expectedGenerationData} != ${
+ toJSON config.data.sharedSecrets.${name}.expectedGenerationData
+ }. Run fleet secrets regenerate to fix";
+ }) config.sharedSecrets);
+ sharedSecrets = mapAttrs (_: _: { }) config.data.sharedSecrets;
};
}
modules/secrets.nixdiffbeforeafterboth12 options = {26 options = {13 expectedOwners = mkOption {27 expectedOwners = mkOption {14 type = nullOr (listOf str);28 type = nullOr (listOf str);15 description = ''29 description = ''16 Specifies the list of hosts authorized to decrypt and access this shared secret.30 Specifies the list of hosts authorized to decrypt and access this shared secret.173118 When null, secret ownership is managed manually via fleet.nix and CLI.32 When null, secret ownership is managed manually via fleet.nix and CLI.19 Decrypted secrets will be stored at /run/secrets/$\{name} on authorized hosts.33 Decrypted secrets will be stored at /run/secrets/$\{name} on authorized hosts.20 '';34 '';21 default = null;35 default = null;22 };36 };23 regenerateOnOwnerAdded = mkOption {37 regenerateOnOwnerAdded = mkOption {24 type = bool;38 type = bool;25 description = ''39 description = ''26 Controls whether the secret must be regenerated when new owners are added.40 Controls whether the secret must be regenerated when new owners are added.274128 Set to true when the secret contains owner-specific references (e.g., X.509 Subject Alternative Names).42 Set to true when the secret contains owner-specific references (e.g., X.509 Subject Alternative Names).29 When true, adding a new owner will trigger secret regeneration instead of simple re-encryption.43 When true, adding a new owner will trigger secret regeneration instead of simple re-encryption.30 '';44 '';31 };45 };32 regenerateOnOwnerRemoved = mkOption {46 regenerateOnOwnerRemoved = mkOption {33 default = config.regenerateOnOwnerAdded;47 default = config.regenerateOnOwnerAdded;34 defaultText = literalExpression "regenerateOnOwnerAdded";48 defaultText = literalExpression "regenerateOnOwnerAdded";35 type = bool;49 type = bool;36 description = ''50 description = ''37 Determines secret behavior when owners are removed from the configuration.51 Determines secret behavior when owners are removed from the configuration.385239 Typically mirrors regenerateOnOwnerAdded. Override cautiously.53 Typically mirrors regenerateOnOwnerAdded. Override cautiously.40 Set to false if host permissions are revoked through alternative mechanisms like firewall rules.54 Set to false if host permissions are revoked through alternative mechanisms like firewall rules.41 '';55 '';42 };56 };43 generator = mkOption {57 generator = mkOption {44 type = uniq (nullOr (functionTo package));58 type = uniq (nullOr (functionTo package));45 description = ''59 description = ''46 Function evaluating to nix derivation responsible for (re)generating the secret's content.60 Function evaluating to nix derivation responsible for (re)generating the secret's content.476148 An input to this function - `pkgs` of a generator host with implementation-defined representation of extra encryption data,62 An input to this function - `pkgs` of a generator host with implementation-defined representation of extra encryption data,49 use `mkSecretGenerator` helpers to implement own generators.63 use `mkSecretGenerator` helpers to implement own generators.50 '';64 '';51 default = null;65 default = null;52 };66 };53 expectedGenerationData = mkOption {67 expectedGenerationData = mkOption {83 # (Some secrets-encryption-in-git/managed PKI solution is expected)106 # (Some secrets-encryption-in-git/managed PKI solution is expected)84 impureOn ? null,107 impureOn ? null,85 }:108 }:86 (prev.writeShellScript "impureGenerator.sh" ''109 (prev.writeShellScript "impureGenerator.sh" ''87 #!/bin/sh110 #!/bin/sh88 set -eu111 set -eu8911290 export GENERATOR_HELPER_IDENTITIES="${concatStringsSep "\n" recipients}";113 export GENERATOR_HELPER_IDENTITIES="${concatStringsSep "\n" recipients}";91 export PATH=${final.fleet-generator-helper}/bin:$PATH114 export PATH=${final.fleet-generator-helper}/bin:$PATH9211593 # TODO: Provide tempdir from outside, to make it securely erasurable as needed?116 # TODO: Provide tempdir from outside, to make it securely erasurable as needed?94 tmp=$(mktemp -d)117 tmp=$(mktemp -d)95 cd $tmp118 cd $tmp96 # cd /var/empty119 # cd /var/empty9712098 created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")121 created_at=$(date -u +"%Y-%m-%dT%H:%M:%S.%NZ")99122100 ${script}123 ${script}101124102 if ! test -d $out; then125 if ! test -d $out; then103 echo "impure generator script did not produce expected \$out output"126 echo "impure generator script did not produce expected \$out output"104 exit 1127 exit 1105 fi128 fi106129107 echo -n $created_at > $out/created_at130 echo -n $created_at > $out/created_at108 echo -n SUCCESS > $out/marker131 echo -n SUCCESS > $out/marker109 '')132 '').overrideAttrs110 .overrideAttrs (old: {133 (old: {111 passthru = {134 passthru = {112 inherit impureOn;135 inherit impureOn;pkgs/default.nixdiffbeforeafterboth--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,8 +1,9 @@
{
callPackage,
craneLib,
-}: {
- fleet = callPackage ./fleet.nix {inherit craneLib;};
- fleet-install-secrets = callPackage ./fleet-install-secrets.nix {inherit craneLib;};
- fleet-generator-helper = callPackage ./fleet-generator-helper.nix {inherit craneLib;};
+}:
+{
+ fleet = callPackage ./fleet.nix { inherit craneLib; };
+ fleet-install-secrets = callPackage ./fleet-install-secrets.nix { inherit craneLib; };
+ fleet-generator-helper = callPackage ./fleet-generator-helper.nix { inherit craneLib; };
}
pkgs/fleet-generator-helper.nixdiffbeforeafterboth--- a/pkgs/fleet-generator-helper.nix
+++ b/pkgs/fleet-generator-helper.nix
@@ -1,4 +1,4 @@
-{craneLib}:
+{ craneLib }:
craneLib.buildPackage rec {
pname = "fleet-generator-helper";
pkgs/fleet-install-secrets.nixdiffbeforeafterboth--- a/pkgs/fleet-install-secrets.nix
+++ b/pkgs/fleet-install-secrets.nix
@@ -1,4 +1,4 @@
-{craneLib}:
+{ craneLib }:
craneLib.buildPackage rec {
pname = "fleet-install-secrets";
pkgs/fleet.nixdiffbeforeafterboth--- a/pkgs/fleet.nix
+++ b/pkgs/fleet.nix
@@ -10,7 +10,7 @@
cargoExtraArgs = "--locked -p ${pname}";
- nativeBuildInputs = [installShellFiles];
+ nativeBuildInputs = [ installShellFiles ];
postInstall = ''
for shell in bash fish zsh; do
scripts/install-trusted-cert.shdiffbeforeafterboth--- a/scripts/install-trusted-cert.sh
+++ b/scripts/install-trusted-cert.sh
@@ -11,7 +11,7 @@
echo remote_conf = \"\"\"
echo "$remote_conf"
echo \"\"\"
-echo "$remote_conf" > "$edited_conf"
+echo "$remote_conf" >"$edited_conf"
sed -i 's/\. Do not edit it!/\. Then it was altered by install-trusted-cert. Do not edit!/g' "$edited_conf"
sed -i "s|^trusted-public-keys =.*|& $pubkey|g" "$edited_conf"
@@ -22,5 +22,5 @@
# Make nix.conf editable
ssh "$1" sudo mv /etc/nix/nix.conf /etc/nix/nix.conf.bk
ssh "$1" sudo cp /etc/nix/nix.conf.bk /etc/nix/nix.conf
-ssh "$1" "cat | sudo dd of=/etc/nix/nix.conf" < "$edited_conf"
+ssh "$1" "cat | sudo dd of=/etc/nix/nix.conf" <"$edited_conf"
ssh "$1" sudo systemctl restart nix-daemon
treefmt.nixdiffbeforeafterboth--- /dev/null
+++ b/treefmt.nix
@@ -0,0 +1,12 @@
+{
+ settings.global.excludes = [
+ "*.adoc"
+ "*.png"
+ "crates/nixlike/fuzz/.gitignore"
+ ];
+
+ programs.nixfmt.enable = true;
+ programs.shfmt.enable = true;
+ programs.rustfmt.enable = true;
+ programs.taplo.enable = true;
+}