refactor: make bootstrap read config from flake

This commit is contained in:
Swarsel 2024-12-24 16:01:33 +01:00
parent 5637ab54fc
commit ae63e40f04
Signed by: swarsel
GPG key ID: 26A54C31F2A4FD84
16 changed files with 481 additions and 428 deletions

View file

@ -7,7 +7,7 @@ keys:
- &swarsel 4BE7925262289B476DBBC17B76FD3810215AE097
- &hosts
- &winters age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63
- &toto age1dmxw76fzr958zl23ad5h7gvtnurr8n5ajlqchgx76k6z5yj3z4zsn592fq
- &toto age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
- &surface age1zlnxraee6tddr07xn59mx5rdexw8qxryd53eqlsajasfhfy78fkq705dfg
- &nbl age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy
- &sync age1glge4e97vgqzh332mqs5990vteezu2m8k4wq3z35jk0q8czw3gks2d7a3h

View file

@ -982,7 +982,10 @@ The interesting part is in the start:
systemFunc = func;
in
systemFunc {
specialArgs = { inherit inputs outputs self; };
specialArgs = {
inherit inputs outputs self;
lib = lib.extend (_: _: { swarselsystems = import ./lib { inherit lib; }; });
};
modules = [ ./hosts/${if isNixos then "nixos" else "darwin"}/${host} ];
};
};
@ -1202,6 +1205,9 @@ My work machine. Built for more security, this is the gold standard of my config
{ self, inputs, outputs, config, pkgs, lib, ... }:
let
profilesPath = "${self}/profiles";
sharedOptions = {
isBtrfs = true;
};
in
{
@ -1279,19 +1285,17 @@ My work machine. Built for more security, this is the gold standard of my config
'';
};
swarselsystems = {
swarselsystems = lib.recursiveUpdate {
wallpaper = self + /wallpaper/lenovowp.png;
hasBluetooth = true;
hasFingerprint = true;
impermanence = false;
isBtrfs = true;
isImpermanence = false;
isCrypted = true;
};
} sharedOptions;
home-manager.users.swarsel.swarselsystems = {
home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate {
isLaptop = true;
isNixos = true;
isBtrfs = true;
flakePath = "/home/swarsel/.dotfiles";
cpuCount = 16;
# temperatureHwmon = {
@ -1416,7 +1420,7 @@ My work machine. Built for more security, this is the gold standard of my config
ans = ". ~/.venvs/ansible/bin/activate";
ans2-15 = ". ~/.venvs/ansible2.15.0/bin/activate";
};
};
} sharedOptions;
}
@ -1478,7 +1482,7 @@ This is my main server that I run at home. It handles most tasks that require bi
swarselsystems = {
hasBluetooth = false;
hasFingerprint = false;
impermanence = false;
isImpermanence = false;
isBtrfs = false;
flakePath = "/home/swarsel/.dotfiles";
server = {
@ -1713,7 +1717,7 @@ This machine mainly acts as an external sync helper. It manages the following th
swarselsystems = {
hasBluetooth = false;
hasFingerprint = false;
impermanence = false;
isImpermanence = false;
isBtrfs = false;
flakePath = "/root/.dotfiles";
server = {
@ -1735,21 +1739,15 @@ This is a slim setup for developing base configuration.
{ self, inputs, outputs, config, pkgs, lib, ... }:
let
profilesPath = "${self}/profiles";
sharedOptions = {
isBtrfs = true;
};
in
{
imports = [
inputs.disko.nixosModules.disko
"${self}/hosts/nixos/toto/disk-config.nix"
{
_module.args = {
withSwap = true;
swapSize = "8";
rootDisk = "/dev/vda";
withImpermanence = true;
withEncryption = true;
};
}
./hardware-configuration.nix
inputs.sops-nix.nixosModules.sops
@ -1810,20 +1808,21 @@ This is a slim setup for developing base configuration.
firewall.enable = false;
};
swarselsystems = {
swarselsystems = lib.recursiveUpdate {
wallpaper = self + /wallpaper/lenovowp.png;
impermanence = true;
isBtrfs = true;
isImpermanence = true;
isCrypted = true;
initialSetup = true;
};
isSwap = true;
swapSize = "8G";
rootDisk = "/dev/vda";
} sharedOptions;
home-manager.users.swarsel.swarselsystems = {
home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate {
isLaptop = false;
isNixos = true;
isBtrfs = true;
flakePath = "/home/swarsel/.dotfiles";
};
} sharedOptions;
}
@ -2800,8 +2799,6 @@ This program sets up a new NixOS host.
echo " -u <target_user> specify target_user with sudo access. nix-config will be cloned to their home."
echo " Default='${target_user}'."
echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}."
echo " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path."
echo " --encryption Use this flag if the target machine has full disk encryption enabled."
echo " --debug Enable debug mode."
echo " -h | --help Print this help."
exit 0
@ -2886,16 +2883,6 @@ This program sets up a new NixOS host.
shift
ssh_port=$1
;;
--temp-override)
shift
temp=$1
;;
--impermanence)
persist_dir="/persist"
;;
--encryption)
disk_encryption=1
;;
--debug)
set -x
;;
@ -2908,6 +2895,37 @@ This program sets up a new NixOS host.
shift
done
green "~SwarselSystems~ remote installer"
green "Reading system information for $target_hostname ..."
DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)"
green "Root Disk: $DISK"
CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)"
if [[ $CRYPTED == "true" ]]; then
green "Encryption: ✓"
disk_encryption=1
else
red "Encryption: X"
disk_encryption=0
fi
IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)"
if [[ $IMPERMANENCE == "true" ]]; then
green "Impermanence: ✓"
persist_dir="/persist"
else
red "Impermanence: X"
persist_dir=""
fi
SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)"
if [[ $SWAP == "true" ]]; then
green "Swap: ✓"
else
red "Swap: X"
fi
ssh_cmd="ssh -oport=${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination"
# ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value
ssh_root_cmd=${ssh_cmd/${target_user}@/root@}
@ -3067,6 +3085,10 @@ This program sets up a new NixOS host.
fi
#+end_src
#+RESULTS:
| trap: | undefined | signal: | exit | | | | |
| [ | Babel | evaluation | exited | with | code | 1 | ] |
#+begin_src nix :tangle pkgs/bootstrap/default.nix
@ -3538,8 +3560,7 @@ let
"wallpaper"
"hardware"
"setup"
"impermanence"
"filesystem"
"server"
"input"
];
@ -3603,22 +3624,45 @@ I usually use =mutableUsers = false= in my NixOS configuration. However, on a ne
#+begin_src nix :tangle modules/nixos/setup.nix
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.swarselsystems.flakePath = mkOption {
type = types.str;
options.swarselsystems.user = lib.mkOption {
type = lib.types.str;
default = "swarsel";
};
options.swarselsystems.flakePath = lib.mkOption {
type = lib.types.str;
default = "";
};
options.swarselsystems.withHomeManager = mkOption {
type = types.bool;
options.swarselsystems.withHomeManager = lib.mkOption {
type = lib.types.bool;
default = true;
};
options.swarselsystems.isSwap = lib.mkOption {
type = lib.types.bool;
default = true;
};
options.swarselsystems.swapSize = lib.mkOption {
type = lib.types.str;
default = "8G";
};
options.swarselsystems.rootDisk = lib.mkOption {
type = lib.types.str;
default = "";
};
options.swarselsystems.isCrypted = lib.mkEnableOption "uses full disk encryption";
options.swarselsystems.isPublic = lib.mkEnableOption "is a public machine (no secrets)";
options.swarselsystems.initialSetup = lib.mkEnableOption "initial setup (no sops keys available)";
options.swarselsystems.isBtrfs = lib.mkEnableOption "use btrfs filesystem";
options.swarselsystems.isImpermanence = lib.mkEnableOption "use impermanence on this system";
}
#+end_src
***** Server
#+begin_src nix :tangle modules/nixos/server.nix
{ lib, ... }:
{
options.swarselsystems.server.enable = lib.mkEnableOption "is a server machine";
options.swarselsystems.server.kavita = lib.mkEnableOption "enable kavita on server";
options.swarselsystems.server.jellyfin = lib.mkEnableOption "enable jellyfin on server";
@ -3661,36 +3705,6 @@ This section is for everything input-related on the NixOS side. At the moment, t
}
#+end_src
***** Impermanence
:PROPERTIES:
:CUSTOM_ID: h:e591075d-4a77-4add-bbc8-b711998fa97f
:END:
Option to enable impermanence configurations. This could also be done via optional imports, but impermanence is a "big enough" change to warrant a line in the machine =default.nix=.
#+begin_src nix :tangle modules/nixos/impermanence.nix
{ lib, ... }:
{
options.swarselsystems.impermanence = lib.mkEnableOption "use impermanence on this system";
}
#+end_src
***** Filesystem
:PROPERTIES:
:CUSTOM_ID: h:f77358ee-a80c-403a-be9d-04e7052bc556
:END:
This lets me quickly set flags for "special" file systems. These options mostly function in conjunction with other settings (for example, the =isBtrfs= function is mostly used for impermanence configuration).
#+begin_src nix :tangle modules/nixos/filesystem.nix
{ lib, ... }:
{
options.swarselsystems.isBtrfs = lib.mkEnableOption "use btrfs filesystem";
}
#+end_src
**** home-manager
:PROPERTIES:
:CUSTOM_ID: h:ced5841f-c088-4d88-b3a1-7d62aad8837b
@ -5541,16 +5555,12 @@ Normally, doing that also resets the lecture that happens on the first use of =s
{ config, lib, ... }:
let
mkIfElse = p: yes: no: if p then yes else no;
mkIfElseList = p: yes: no: lib.mkMerge [
(lib.mkIf p yes)
(lib.mkIf (!p) no)
];
mapperTarget = mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos";
in
{
security.sudo.extraConfig = lib.mkIf config.swarselsystems.impermanence ''
security.sudo.extraConfig = lib.mkIf config.swarselsystems.isImpermanence ''
# rollback results in sudo lectures after each reboot
Defaults lecture = never
'';
@ -5561,12 +5571,12 @@ Normally, doing that also resets the lecture that happens on the first use of =s
boot.initrd.systemd.enable = true;
boot.initrd.systemd.services.rollback = lib.mkIf config.swarselsystems.impermanence {
boot.initrd.systemd.services.rollback = lib.mkIf config.swarselsystems.isImpermanence {
description = "Rollback BTRFS root subvolume to a pristine state";
wantedBy = [ "initrd.target" ];
# make sure it's done after encryption
# i.e. LUKS/TPM process
after = mkIfElseList config.swarselsystems.isCrypted [ "systemd-cryptsetup@cryptroot.service" ] [ "dev-disk-by\\x2dlabel-nixos.device" ];
after = lib.swarselsystems.mkIfElseList config.swarselsystems.isCrypted [ "systemd-cryptsetup@cryptroot.service" ] [ "dev-disk-by\\x2dlabel-nixos.device" ];
requires = lib.mkIf (!config.swarselsystems.isCrypted) [ "dev-disk-by\\x2dlabel-nixos.device" ];
# mount the root fs before clearing
before = [ "sysroot.mount" ];
@ -5609,7 +5619,7 @@ Normally, doing that also resets the lecture that happens on the first use of =s
};
environment.persistence."/persist" = lib.mkIf config.swarselsystems.impermanence {
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
hideMounts = true;
directories =
[

View file

@ -151,7 +151,10 @@
systemFunc = func;
in
systemFunc {
specialArgs = { inherit inputs outputs self; };
specialArgs = {
inherit inputs outputs self;
lib = lib.extend (_: _: { swarselsystems = import ./lib { inherit lib; }; });
};
modules = [ ./hosts/${if isNixos then "nixos" else "darwin"}/${host} ];
};
};

View file

@ -1,6 +1,9 @@
{ self, inputs, outputs, config, pkgs, lib, ... }:
let
profilesPath = "${self}/profiles";
sharedOptions = {
isBtrfs = true;
};
in
{
@ -78,19 +81,20 @@ in
'';
};
swarselsystems = {
swarselsystems = lib.recursiveUpdate
{
wallpaper = self + /wallpaper/lenovowp.png;
hasBluetooth = true;
hasFingerprint = true;
impermanence = false;
isBtrfs = true;
isImpermanence = false;
isCrypted = true;
};
}
sharedOptions;
home-manager.users.swarsel.swarselsystems = {
home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate
{
isLaptop = true;
isNixos = true;
isBtrfs = true;
flakePath = "/home/swarsel/.dotfiles";
cpuCount = 16;
# temperatureHwmon = {
@ -215,5 +219,6 @@ in
ans = ". ~/.venvs/ansible/bin/activate";
ans2-15 = ". ~/.venvs/ansible2.15.0/bin/activate";
};
};
}
sharedOptions;
}

View file

@ -79,7 +79,7 @@ in
swarselsystems = {
hasBluetooth = false;
hasFingerprint = false;
impermanence = false;
isImpermanence = false;
isBtrfs = false;
flakePath = "/root/.dotfiles";
server = {

View file

@ -1,21 +1,15 @@
{ self, inputs, outputs, config, pkgs, lib, ... }:
let
profilesPath = "${self}/profiles";
sharedOptions = {
isBtrfs = true;
};
in
{
imports = [
inputs.disko.nixosModules.disko
"${self}/hosts/nixos/toto/disk-config.nix"
{
_module.args = {
withSwap = true;
swapSize = "8";
rootDisk = "/dev/vda";
withImpermanence = true;
withEncryption = true;
};
}
./hardware-configuration.nix
inputs.sops-nix.nixosModules.sops
@ -76,19 +70,24 @@ in
firewall.enable = false;
};
swarselsystems = {
swarselsystems = lib.recursiveUpdate
{
wallpaper = self + /wallpaper/lenovowp.png;
impermanence = true;
isBtrfs = true;
isImpermanence = true;
isCrypted = true;
initialSetup = true;
};
isSwap = true;
swapSize = "8G";
rootDisk = "/dev/vda";
}
sharedOptions;
home-manager.users.swarsel.swarselsystems = {
home-manager.users.swarsel.swarselsystems = lib.recursiveUpdate
{
isLaptop = false;
isNixos = true;
isBtrfs = true;
flakePath = "/home/swarsel/.dotfiles";
};
}
sharedOptions;
}

View file

@ -1,11 +1,8 @@
# NOTE: ... is needed because dikso passes diskoFile
{ lib
, pkgs
, config
, rootDisk
, swapSize ? "8"
, withSwap ? true
, withEncryption ? true
, withImpermanence ? true
, ...
}:
let
@ -20,7 +17,7 @@ let
"noatime"
];
};
"/home" = lib.mkIf withImpermanence {
"/home" = lib.mkIf config.swarselsystems.isImpermanence {
mountpoint = "/home";
mountOptions = [
"subvol=home"
@ -28,7 +25,7 @@ let
"noatime"
];
};
"/persist" = lib.mkIf withImpermanence {
"/persist" = lib.mkIf config.swarselsystems.isImpermanence {
mountpoint = "/persist";
mountOptions = [
"subvol=persist"
@ -36,7 +33,7 @@ let
"noatime"
];
};
"/log" = lib.mkIf withImpermanence {
"/log" = lib.mkIf config.swarselsystems.isImpermanence {
mountpoint = "/var/log";
mountOptions = [
"subvol=log"
@ -52,9 +49,9 @@ let
"noatime"
];
};
"/swap" = lib.mkIf withSwap {
"/swap" = lib.mkIf config.swarselsystems.isSwap {
mountpoint = "/.swapvol";
swap.swapfile.size = "${swapSize}G";
swap.swapfile.size = config.swarselsystems.swapSize;
};
};
in
@ -63,7 +60,7 @@ in
disk = {
disk0 = {
type = "disk";
device = rootDisk;
device = config.swarselsystems.rootDisk;
content = {
type = "gpt";
partitions = {
@ -79,11 +76,11 @@ in
mountOptions = [ "defaults" ];
};
};
root = lib.mkIf (!withEncryption) {
root = lib.mkIf (!config.swarselsystems.isCrypted) {
size = "100%";
content = {
inherit type subvolumes extraArgs;
postCreateHook = lib.mkIf withImpermanence ''
postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
MNTPOINT=$(mktemp -d)
mount "/dev/disk/by-label/nixos" "$MNTPOINT" -o subvolid=5
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
@ -91,7 +88,7 @@ in
'';
};
};
luks = lib.mkIf withEncryption {
luks = lib.mkIf config.swarselsystems.isCrypted {
size = "100%";
content = {
type = "luks";
@ -107,7 +104,7 @@ in
};
content = {
inherit type subvolumes extraArgs;
postCreateHook = lib.mkIf withImpermanence ''
postCreateHook = lib.mkIf config.swarselsystems.isImpermanence ''
MNTPOINT=$(mktemp -d)
mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvolid=5
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
@ -122,8 +119,8 @@ in
};
};
fileSystems."/persist".neededForBoot = lib.mkIf withImpermanence true;
fileSystems."/home".neededForBoot = lib.mkIf withImpermanence true;
fileSystems."/persist".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
fileSystems."/home".neededForBoot = lib.mkIf config.swarselsystems.isImpermanence true;
environment.systemPackages = [
pkgs.yubikey-manager

View file

@ -46,7 +46,7 @@ in
swarselsystems = {
hasBluetooth = false;
hasFingerprint = false;
impermanence = false;
isImpermanence = false;
isBtrfs = false;
flakePath = "/home/swarsel/.dotfiles";
server = {

7
lib/default.nix Normal file
View file

@ -0,0 +1,7 @@
{ lib, ... }:
{
mkIfElseList = p: yes: no: lib.mkMerge [
(lib.mkIf p yes)
(lib.mkIf (!p) no)
];
}

View file

@ -3,8 +3,7 @@ let
"wallpaper"
"hardware"
"setup"
"impermanence"
"filesystem"
"server"
"input"
];

22
modules/nixos/server.nix Normal file
View file

@ -0,0 +1,22 @@
{ lib, ... }:
{
options.swarselsystems.server.enable = lib.mkEnableOption "is a server machine";
options.swarselsystems.server.kavita = lib.mkEnableOption "enable kavita on server";
options.swarselsystems.server.jellyfin = lib.mkEnableOption "enable jellyfin on server";
options.swarselsystems.server.navidrome = lib.mkEnableOption "enable navidrome on server";
options.swarselsystems.server.spotifyd = lib.mkEnableOption "enable spotifyd on server";
options.swarselsystems.server.mpd = lib.mkEnableOption "enable mpd on server";
options.swarselsystems.server.matrix = lib.mkEnableOption "enable matrix on server";
options.swarselsystems.server.nextcloud = lib.mkEnableOption "enable nextcloud on server";
options.swarselsystems.server.immich = lib.mkEnableOption "enable immich on server";
options.swarselsystems.server.paperless = lib.mkEnableOption "enable paperless on server";
options.swarselsystems.server.transmission = lib.mkEnableOption "enable transmission and friends on server";
options.swarselsystems.server.syncthing = lib.mkEnableOption "enable syncthing on server";
options.swarselsystems.server.restic = lib.mkEnableOption "enable restic backups on server";
options.swarselsystems.server.monitoring = lib.mkEnableOption "enable monitoring on server";
options.swarselsystems.server.jenkins = lib.mkEnableOption "enable jenkins on server";
options.swarselsystems.server.emacs = lib.mkEnableOption "enable emacs server on server";
options.swarselsystems.server.forgejo = lib.mkEnableOption "enable forgejo on server";
options.swarselsystems.server.ankisync = lib.mkEnableOption "enable ankisync on server";
options.swarselsystems.server.freshrss = lib.mkEnableOption "enable freshrss on server";
}

View file

@ -1,37 +1,33 @@
{ lib, ... }:
let
inherit (lib) mkOption types;
in
{
options.swarselsystems.flakePath = mkOption {
type = types.str;
options.swarselsystems.user = lib.mkOption {
type = lib.types.str;
default = "swarsel";
};
options.swarselsystems.flakePath = lib.mkOption {
type = lib.types.str;
default = "";
};
options.swarselsystems.withHomeManager = mkOption {
type = types.bool;
options.swarselsystems.withHomeManager = lib.mkOption {
type = lib.types.bool;
default = true;
};
options.swarselsystems.isSwap = lib.mkOption {
type = lib.types.bool;
default = true;
};
options.swarselsystems.swapSize = lib.mkOption {
type = lib.types.str;
default = "8G";
};
options.swarselsystems.rootDisk = lib.mkOption {
type = lib.types.str;
default = "";
};
options.swarselsystems.isCrypted = lib.mkEnableOption "uses full disk encryption";
options.swarselsystems.isPublic = lib.mkEnableOption "is a public machine (no secrets)";
options.swarselsystems.initialSetup = lib.mkEnableOption "initial setup (no sops keys available)";
options.swarselsystems.server.enable = lib.mkEnableOption "is a server machine";
options.swarselsystems.server.kavita = lib.mkEnableOption "enable kavita on server";
options.swarselsystems.server.jellyfin = lib.mkEnableOption "enable jellyfin on server";
options.swarselsystems.server.navidrome = lib.mkEnableOption "enable navidrome on server";
options.swarselsystems.server.spotifyd = lib.mkEnableOption "enable spotifyd on server";
options.swarselsystems.server.mpd = lib.mkEnableOption "enable mpd on server";
options.swarselsystems.server.matrix = lib.mkEnableOption "enable matrix on server";
options.swarselsystems.server.nextcloud = lib.mkEnableOption "enable nextcloud on server";
options.swarselsystems.server.immich = lib.mkEnableOption "enable immich on server";
options.swarselsystems.server.paperless = lib.mkEnableOption "enable paperless on server";
options.swarselsystems.server.transmission = lib.mkEnableOption "enable transmission and friends on server";
options.swarselsystems.server.syncthing = lib.mkEnableOption "enable syncthing on server";
options.swarselsystems.server.restic = lib.mkEnableOption "enable restic backups on server";
options.swarselsystems.server.monitoring = lib.mkEnableOption "enable monitoring on server";
options.swarselsystems.server.jenkins = lib.mkEnableOption "enable jenkins on server";
options.swarselsystems.server.emacs = lib.mkEnableOption "enable emacs server on server";
options.swarselsystems.server.forgejo = lib.mkEnableOption "enable forgejo on server";
options.swarselsystems.server.ankisync = lib.mkEnableOption "enable ankisync on server";
options.swarselsystems.server.freshrss = lib.mkEnableOption "enable freshrss on server";
options.swarselsystems.isBtrfs = lib.mkEnableOption "use btrfs filesystem";
options.swarselsystems.isImpermanence = lib.mkEnableOption "use impermanence on this system";
}

View file

@ -1,16 +1,12 @@
{ config, lib, ... }:
let
mkIfElse = p: yes: no: if p then yes else no;
mkIfElseList = p: yes: no: lib.mkMerge [
(lib.mkIf p yes)
(lib.mkIf (!p) no)
];
mapperTarget = mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos";
in
{
security.sudo.extraConfig = lib.mkIf config.swarselsystems.impermanence ''
security.sudo.extraConfig = lib.mkIf config.swarselsystems.isImpermanence ''
# rollback results in sudo lectures after each reboot
Defaults lecture = never
'';
@ -21,12 +17,12 @@ in
boot.initrd.systemd.enable = true;
boot.initrd.systemd.services.rollback = lib.mkIf config.swarselsystems.impermanence {
boot.initrd.systemd.services.rollback = lib.mkIf config.swarselsystems.isImpermanence {
description = "Rollback BTRFS root subvolume to a pristine state";
wantedBy = [ "initrd.target" ];
# make sure it's done after encryption
# i.e. LUKS/TPM process
after = mkIfElseList config.swarselsystems.isCrypted [ "systemd-cryptsetup@cryptroot.service" ] [ "dev-disk-by\\x2dlabel-nixos.device" ];
after = lib.swarselsystems.mkIfElseList config.swarselsystems.isCrypted [ "systemd-cryptsetup@cryptroot.service" ] [ "dev-disk-by\\x2dlabel-nixos.device" ];
requires = lib.mkIf (!config.swarselsystems.isCrypted) [ "dev-disk-by\\x2dlabel-nixos.device" ];
# mount the root fs before clearing
before = [ "sysroot.mount" ];
@ -69,7 +65,7 @@ in
};
environment.persistence."/persist" = lib.mkIf config.swarselsystems.impermanence {
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
hideMounts = true;
directories =
[

View file

@ -24,8 +24,6 @@ function help_and_exit() {
echo " -u <target_user> specify target_user with sudo access. nix-config will be cloned to their home."
echo " Default='${target_user}'."
echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}."
echo " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path."
echo " --encryption Use this flag if the target machine has full disk encryption enabled."
echo " --debug Enable debug mode."
echo " -h | --help Print this help."
exit 0
@ -110,16 +108,6 @@ while [[ $# -gt 0 ]]; do
shift
ssh_port=$1
;;
--temp-override)
shift
temp=$1
;;
--impermanence)
persist_dir="/persist"
;;
--encryption)
disk_encryption=1
;;
--debug)
set -x
;;
@ -132,6 +120,37 @@ while [[ $# -gt 0 ]]; do
shift
done
green "~SwarselSystems~ remote installer"
green "Reading system information for $target_hostname ..."
DISK="$(nix eval --raw ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.rootDisk)"
green "Root Disk: $DISK"
CRYPTED="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isCrypted)"
if [[ $CRYPTED == "true" ]]; then
green "Encryption: ✓"
disk_encryption=1
else
red "Encryption: X"
disk_encryption=0
fi
IMPERMANENCE="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isImpermanence)"
if [[ $IMPERMANENCE == "true" ]]; then
green "Impermanence: ✓"
persist_dir="/persist"
else
red "Impermanence: X"
persist_dir=""
fi
SWAP="$(nix eval ~/.dotfiles#nixosConfigurations."$target_hostname".config.swarselsystems.isSwap)"
if [[ $SWAP == "true" ]]; then
green "Swap: ✓"
else
red "Swap: X"
fi
ssh_cmd="ssh -oport=${ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -t $target_user@$target_destination"
# ssh_root_cmd=$(echo "$ssh_cmd" | sed "s|${target_user}@|root@|") # uses @ in the sed switch to avoid it triggering on the $ssh_key value
ssh_root_cmd=${ssh_cmd/${target_user}@/root@}

View file

@ -9,62 +9,62 @@ sops:
- recipient: age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpd0JYN2tiNW1IRHJtcXlX
SEQvOUVZYjJzb1ZVamdpbG91OXZpMkhWTkQ4CjVsTlp3eTR0OENhanh4clR5OXJX
NnU2QVdVbXVRTXRJWlgwSGFkdEMyWjAKLS0tIG5NQzFqREIrWmZBUGZSVVU5RWVE
VzlnVmhzc2U3d3B4aEs2a0dCaHJQbHMKpDLehdlCXhnEKOjzFr7rliJtETSsyUDp
HixMSMosuN3xs7+7nodPBHsX7Z9kvbwV60inqzHUWsq4SzHrqQozbg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpRko1ZnZsMUM2L1VmNGQ4
MnhOZTZmdlBLQ2dra0xMY3E0NmZPQUpuU1Q4CjNDSDNnVGNCV05aUWpWRnZkWEt2
Y1FlbEdTZ290SjRKc1hKRzN0bUNwVDAKLS0tIHFjVEk0S045NGgzMUFDUitIdEx4
dlRRWUtiYldYQ3V0QzFyRHNIblNFNm8KkPXunwFKo/4klAZhkAXikg7UpuFC1EP/
kf6roOcQx41hPSqAWzivySwPgRUO3iygFw4jonYaFZJik/wIo9OulA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1dmxw76fzr958zl23ad5h7gvtnurr8n5ajlqchgx76k6z5yj3z4zsn592fq
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVcTIwWVl5VHlnUUFuMkky
N1BBNnNBVkJVKzZqeXRiVVJ2OUNoUjIraWtrClE2NDJYTng3S2dHL29wcm5NRkxY
L1NZY21xd09FUDN0QTdsTEVpZjNoWXMKLS0tIFlTWFNEcmwwNnRuYmhCcTVUZXAx
cW04RVNxeDlkcDZmT3JadUNDQUdXRlEKnXWWqgObJStUF0DdWKX2M71UYk/6n4wX
XdmPH0crXBelfwmSvX1+Pkwj+JowzXmMaVR0Y0XC2SMXdzWShhk40w==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYUmhXcS8rWmNQUGVudGxP
STZPaVB3VlFHYXhDbUZYdjhENFFOL1FCUEZVClJ2cFhwNlRpVnAzRThQZ1FuNHNi
T3pyWm5aNDVaUnJHcjYzWVVOUHBwWUEKLS0tIFdKSXF5TGw2aDJ3NGdhZ0RGWGpu
MjBYTktmeE9EcDNad0VKV1dhME9UbVkKYrDIQ8/DfeJ/3ITfw9/51i2N44hqnIi3
4hHKaefSiHU0glUHUdYhg/F17Hgh5MuhZ0LB4dfIYngWNgFDwnC4aQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1zlnxraee6tddr07xn59mx5rdexw8qxryd53eqlsajasfhfy78fkq705dfg
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjcUZGcTBmR2ZHRW0rcVRj
cCt1Wi9JNWJpbEtNVmVwWmJBN2VLM05SVlRRCkdOMVhFTXd3QUJFWGZyTys0NXgv
Y1MwL2pWNmZiUGdCTnpDR1RqOHQ2UDgKLS0tIFFrUDg5eFpWcXpNOERWZzJTa1ph
SlQxWE5VWlFHVlY0VE1zTjFUa054bG8KjXhLyIPnL/nGAR9l2d+J2s29ZxjzH5+U
BtavBDsS1/Ldsu4OQsY7TFJrTdOzMMRsNVWedprFyJjx0o8FO9AwWw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNWFNvaE5VQms2VFNOK25D
NTdocVF5QTMwSDEreE02cWVVaHIyQ2dqcVRnClB4QzAzTkRVb1hSL1VjYW5IOEIr
SG9adlpacGd1ck8vTU1IOTNyS2Y4cjAKLS0tIDQxT3lOUjhpQ1FNNGZKbnpXOVJG
aS9qY0crYXpsSFRxT280VzllTE1kdWcKoaATszZ1H4b05vpEzQXkffJuwQESbTyW
nBE5WYRqUHBFWeve1Ssq3AaYpNEht+MAYA0YlA3TsJc5scSbkFXi4g==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-07-16T23:56:59Z"
mac: ENC[AES256_GCM,data:bo8SHGmkNGQqR8nnlIKvAMzd+4vWJ19u9Kga2U1mOEYKMCyZ2nTXju6e327ppmx6KJUnzzieS7F8myE/5jzfd1+LyAN7QlL1xixtyLZH784Eh3c3Rd3sXKO/Tuj00gSsz8PsXzq8VK5RdR6NggxhMM6l3Mji4mTQibEzFQ0XPwo=,iv:6mAVBuMwxkO/ms0O/lpLEAg9lzVtZywMbwhL7diB4Z4=,tag:oGnwY5Ikc8qOrwNyiWqtGg==,type:str]
pgp:
- created_at: "2024-12-24T11:28:02Z"
- created_at: "2024-12-24T14:59:45Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTAQ/6Avc2srb+MID5p6jRKpQwe5aOM67Tp1XwvtwvDuN94zcP
XUVWj05wbqgbbFtp2xDiO2OcBgWD46RzK0S7od6bsBDAhZyjHE8azfJonsE0NItD
H0crDyCdlQThEG5pNY3ScByaMpHVZpFuv7B/Kc2En1mWVABAeTppOJeVXFXjAX6l
ENk5z3h5IdGDdNtMXBPh6kOW8UAlfS2BvwCUH9/3QnhdXMEB4CuYSf4QM5gKUXpB
Lhe+USkwjSlFgjVokMkgu/FGBY7WKErXyo6ydvMWGM0I+ezoOWF87EwTEFo2DO5Q
suR9IxsPfWwbLZxAGL8wBIOJ5UqBAKzsXwRB7MjwYpB2nxefVD0YFq9n7sxj8Y7x
pc/JrXqJRbNgVGhnzY+Vz0JIDs5MyRO1FAmOHmFNFvZ9uxX1yhuZODdLIu6cfcjN
ESah7Z1uVSuX2Ijo/oFQlrh4es78WBmI54Z7Ql27SS105sx/iPpKan9Zo6FhzTd+
ZRDUGEeb8DTCTVoewArL7g4QHvTdq+BIs/uhZwR2J3rtV8tz9lArvXKkQGYqUcQJ
PP+7mBIh88qr/N5WxtdkhmjCZPymLujdSeOOlf0yBohulSF6xVt3llmDbwwcikmJ
xE0/Fi4QGo78OVUHv52L++QnsPhCYW+U7sTEr0VMti9xxWZl7gL43AmZksyYg4KF
AgwDC9FRLmchgYQBEACkJfB+MdBopReg67q0X1XeGrQAdHt9skuSQ/6yoNNDdWaS
/3ox47NZCT63FwcoNWjQJEMi6SfHHR1AlQ7wlV0XjYiuoGtzI+/bcCZFeWSIO0K+
hi7G8uOENSw7SDapOF3WyR1vBghXNSlJoeG3RCMQ6Pq+CFa5iwVIZbd/a6WRMuvV
issNDMZjeKxOYqis0DtxEtjbGMBG/aTalil2QOxgA9ePt8ssvcvIkFz9fR10sE5/
plptogWqhHsMrIf6vTRuIwYDojsR8N2bFeY1WQHuz54trqC/jbJ4ouf303GY20aU
f2a946hVyJ6L5SJmNSoTK7sFQNdrcBBHrnn1qOyfHae1mLb8VzXHd17nUzkWl35h
cwN7OITIzi7623r3e/5XIZyyXD1kjWTl+Ko/dNtKa6r9Dla0GpPnrw9bYELLXXQo
6M8GuCkiZmofH0bMRPFyXYntwBRkJcuxmhTaqbrklsjprarxSUYnpI1yBwHar7Q9
+EABsFEIYqflS1ZwtvSjCP0Om+KwB/TyZha6uzzXw01W3wXZ0KwuMqugr3RZUW8F
radD+l7ftXx6dSZeYtqdV9a/j8XckAZvqScDTJivtbn3uSYqE0YREJTqtB4v9XBc
Wsn1uWiZhAUun3sp7BnXmBvUKj9n4JXSENo2rdLXaAc1q/b558TwWFiGQwPwHtJe
AY7U7Ka2f/1QiFg+irc8SVXf2QA5X7QB7Khn2DaK4wv4JjGIexX1U2cpH5CAqW+V
EMIxOk/AZpuS6+WPVqF7uW8a3cmZY9tEU1BmMRQ/11K7+RRiF6fGsAPw5yaySA==
=HWX2
hQIMAwDh3VI7VctTARAAk4nNktWj0SF7nbb9/Fg8BW5KuO0aBINoExyIC+Lvgaoz
Bs5G4twnhGnH5J667yId4JpwFKrLi4sGzVoO3pvbhAhjJE2Ea3vVA4vse43XGBJb
z2IXWuDaWxu+fVWpGpu+2GDvIyMCFUMGVK3PjF5Gc1sq5wratMLZMEOfo3lG1gfm
IQvBiyi21F3lEDrI0sbBry+5BuWmvvz6GlaITCSzzmU1LygSvv2S0S7KsV7E8ldC
NAa9e5/NFwpmauATNSuLJfWIHNuwLCDSx1DbinIKu/ADgmCn4kvyXmFiTC4kmfKo
76It/qrWDgCK8ApNbQeNxzWgTCNgqGYcgL08sQC6T6J5kIdG3QhZfVHFFe9dQO8S
pB0H7O7j8ZCnXkd2IBUoXg2RP+BvWCyU6NB6YMZkcfIXvvJHsfNTODdOi5IRfyUC
9BaRhGTuFh1ggtdNWSjkI5ccYm5HEEawLds7oZ013qV8T+myoERIS5ZLVkpTr5nT
Xurx/EmHxPZsXCsBp+vrFgfzFq3P5raDDK/AADXOk3oWVRy+5+6iHT+M8yNdGqYU
AmXhQra2rqCVearYkJ/4IfsHFGy2Dzvyd0a1GqLtVoQaHlP5QjVXcqNJAmEbuN6y
j4neGeCxfnla53PfeuKa6mhOcfupmosfaebDajHvj0224G0oXcZ0LA/vrLdnuXSF
AgwDC9FRLmchgYQBD/9rPvTgOfuhtiY1M4mOgOUlUSELgsslPVuDgeioErWfVHMf
/krx1wLn/+sVPBqQ3e3fleVRauAnzEgZSsdyAwscmpX1GQwGFIsxwgWeIU16xxjL
fa44twBualtyjp2iCslT3jUgNqpNLFlRSQicNCpcNVAgP2Ycxrar9X5v6hhOuf9A
SERsp0i3A/zueW76QA1gGQhe/1uX+TuRxrC1cUT59pYSjWhIWATO/HkK3pE19IAe
Ioq/eMrY19a/BcbAJ9TE/HUQ6ENrr9gUuTD+hwE3F3cLUWb1tR8ambRwLKB5V94l
GMGan/vOtPqeDiJKQfXvwXPzbyRkVMc1Mnxmtmb4maoyG3Jj7Lqc3UGISVco8yNv
EJIn75ZpPZjBmQdVBcKLE07pvWxIAaDvEdkNY6bBLsClqkMtHudE0/wfhRZpqG1l
cVe6kyYJGg8kDR0RrGWfuE+ruDfHmsme/xE1HcTxt2iIgV+RBMeGFZ7rCyUX2mFZ
0GnFmh/clrVbSisHbyILokWmCkdofUDbTNAKEV6nStvFBW8o4U18KpL2hTgdGrOl
fTDSATTYR5ljxlRzI3+lWD6qfDbNftPOgPwnKNhBm8bnPKB8ZgcSjwCpcI2daMY7
ghAZTNoZJrkkCmE/5TswjmvEvez0psSorFIw60ZuwboE87zAHyUzH3vWkI6p1tJc
AZzPeodzalKAdYZ3EfldCzFBj1ZepHcdG4T9xmos6wS6U19vGQgZUhI4JXt6rXsr
G08XWuBwp064gFfREDkNMuYI3Tgc73r+J6mvyvycoqYi069ici4T+U7Zw6w=
=8uFY
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted

View file

@ -34,71 +34,71 @@ sops:
- recipient: age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0WXZ1RC9WV2lUQnNkOCs5
Y0xIQzdsSlhnS2RMaTE1NGhPREkyblVvMVdvCnpaRXVDOXAwK0ErVU9EVEoxZnUy
eXFid0g1VXJLSFJIbklrYWpiMWZiWFEKLS0tIGdzZzNyam5kM3BROXJCL0ZCemxT
VjF4RHQ2anZUbGNXUlNCUEJXNkhBUUEK0m8++qCry3GPrVy3AKieBWBUjX01Bexe
82GKZqeezxZIud3BJmWKW7KtoAQ5KxC8rLhJzJIczGPbHiVgKx1WNw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLbm9WeGd0U0NEMzhpTDhE
SzBpRG5Xc1VUeFdSaXRjMHBKNVltNTY4dHcwCm5DRzFSdG9ML2h2QVlYNm5pUC9Z
TTh4TDB2bjhWdWFNQ2ozN09sZWw1WTAKLS0tIDUrcHVmWUc3dkxSS3MrZXB6ZHNi
QzZVR3p2VlRyZjNqZk9ZTDBXOWdxYnMK3ZT951oj6lSP+3a1sQL88GUE/jlhfoWy
tkoKh2wNofg3BX9jMCgWm2LFcYxX1fMOoxhXxK2XNEV5et8gxHIxEw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1dmxw76fzr958zl23ad5h7gvtnurr8n5ajlqchgx76k6z5yj3z4zsn592fq
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVVXo1T2lWdEEwWjRPRUxk
S3gvcGN0cXRLaW0yOUNqUUUvMEh1TzhsZlhBCmZFUFhIRVZGL2c2RmR2UHNRUVZC
RWlMTnVIMjJGaFU2andyejk3dWttUm8KLS0tIFBoRDNDQ1MrNVhXRzRtTTdveDNI
eWdaL0ZGczNodVEySWxvVUlqc2hBN00KRjokYKoTskN+d1yhzeOBfFFA3csnMsmx
UYtzuycE2+9qPv0nrQ5AtNqkdsPuLNnF9D0QXRyzSsqJ67axELehpw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiZTlsOG02b2h3a1FaVW03
RTFHOXhnaU94elNxNU5jV3hYUWczS25NOGdNClFRYUdoN2pDeEQyenhyYTNDMGxE
U3Z1elFwVlRXNCtpSlF6TmNYMEgyem8KLS0tIHYrZjB2NVhUdFFXcmFVNnJyd3NM
eHpZOStRRWZROU9qd3FZUXU5amhsWjgKIx6s5IpwAkcdRgqjlmMqQTGgx7abZ7OU
C5BWpFIARLNUcBOKdORT8fT1m1EnmXKawxitVPHrhAJibvi9XuZIWw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1zlnxraee6tddr07xn59mx5rdexw8qxryd53eqlsajasfhfy78fkq705dfg
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJRUd6SkFyaHZLTnJGK05v
ZGZ4NGgreE9ueWZ5b2tzVHRUcmdZTnYxRzJJCmRkbmhXQXBXaG1Hc3ovem9PSUdE
dGZrcERvTlBIOFpHQUNmUXNpcHJaN1EKLS0tIDJtVC94YXh0dUZjcjhDcFJpbTdN
alNjWnJLSVlTNVliRERwdlpQYU9EaWMKynCfIpvVraG6HZMtExcE+qf7EbXPra3t
Bo0BO1fgh+Z1pdxYa71ruFdfBF4BqtRlLlJKqKfIjLmNU1mEh3Wv1Q==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsNm5GWTZabmx0Lzd4VFNH
cFRRYUpCeTMxQ01LOThNRzY1T1FiWmt2TUVjClNWbDBnQk9lSmE1MVhieXh0ZENw
TjN0NnZlTlFMYmoyRTh0NDJHWTRUU2sKLS0tIEVCZElydnI3V0pBQ205b1hqV1U3
aDdsUWc0bkdrcFBZeHhFc3hHeGhvL3MKt1sJlwjY4zc07tIp6qihcGu8UMdgr968
KYSO3fGr6XfRWwfzVb9h7FBsWK8ttar0tCK1JF9Hjjp0W9Oqu+AQGA==
-----END AGE ENCRYPTED FILE-----
- recipient: age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuUzhpKzdZdHNZRXNFTG1Z
OHVMTUNrMmNnWU9JQTFFbExpTkZ5ZnlDUEdRCmk3eEZHZlBuTTIxVS84Q2ExNzVo
OGhOU0NUTCsweVZYcStRd0NXOEhkYm8KLS0tIE50NTExZFM3akJXMDNHMVhkaysz
OFBJMWZNcEtUWkVWdk1SRTVreUJaVFUK6oMy5pliMIBJ3juN7E2UKU+OzN7iYJy/
aB2MpEUc0ABd47X5aWgUTmz+bK6hSewiji9LM1mPQOeaqLMeNrrKpg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2cFFqMDJ5SUQrT1c0VHRH
MmhYbFJBcjZJTjlFNHBtTk9uWTl0dnNud0Q0ClJBVkhzWXNqdGZIWE9DR3pzMDdq
cXBwWWJKWlhwM2RVTCtHbU4yZjdCdVEKLS0tIEFwZFIzakNHT2ovNmoxUGtXTUFD
RVdWbGt0aHcrUGlNWTdUZ2xMa25mYlUKY6AOmHg9+ApJXeoyliXxvqtjwaVLSjH0
6cuZSd05iOSHpR2vbg9jvRiXKXBS6DSN/BoIn+JUif8jY8cTQCMqDQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-12-18T22:08:25Z"
mac: ENC[AES256_GCM,data:vU+7/VLEzwDOrScD/HTo9JBf4ixtmcBmjtSUEtaVHwZuPMJ0OpydwcBPYKvhvU6z9xNecCcuiY7beJ5sq7fnv8XY66TOZWq/2tTZPXdJwpfAyHqBhf7uoCiOmSl53tpWzUFbfT8fQQwjKmBO1079Op24WNWzG3w0i9BsoYTYrpY=,iv:9bLlRg28paoitcK1lFc4ipsgMVvr/zECNozwXU2qJTM=,tag:uRviXeIlwUnvJqHwWuoYcA==,type:str]
pgp:
- created_at: "2024-12-24T11:28:03Z"
- created_at: "2024-12-24T14:59:46Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTAQ/9HoMF738rlJqCMcu93+1YivUw/dv6Wspi6v7rXQxh2vmI
dicHIjmcLyiTIW+58sPF5cFN3FLYc4869xVtZntTDmZdY1qy7v9QxiWWN5EXnxzu
mjpO7Y8SZI51+MN4nQC/rsczizzR+eesduQ6vOU3ikPApThu/sAFjXMG3GuT7lTv
kqoSxJ0WHeq3EvJF2uIyUN1HQA5Dvs0UJJuMmctdexCiMm4DUyXHIXLPyhxgcVq1
svAc9Z74egY88U4kTKBH5nyOhGC0M9rnxUDGYYtpcFnKFx1utJ2+ouWrCQMrJs/f
YzsNJiespTpjxc0gMbf2oAvs2Kpjo2YwPooR8B17qF+xvy+EKYLHcKTW+Fb6C0TX
6f4fRzTb29wSfKoQ9wOTwHKbWIYGMzxerGPb8zuDM0g97rKNV7Ki4Mtgm0wz6kAX
4UhSWwNblFhGIgS3RbWHTrLxKqieTJKzGK+8is1Q2g+j7YDJ+Xblvz9ABOcB6hBK
I9yiDkIhYLIWLabooB9K8ZZKHJPqFr490EcBrB0njqbxJCIyibak0Jj7uFG3GVIN
VK1tZ1sGIDpTmXXQPqL4NQcRQvQeYa8GiPPpvE9xCwO2pYLrphiTjkqBl+CMISbJ
prliFTiaXcAfRQ9NHDF0+cZ2BfZEkvYQYmJ5a9FouMvYs41YnlUdlSLxR4sK/3SF
AgwDC9FRLmchgYQBD/wJTOUINZ2O48gVobDo8/Brnisz8NO7NiQh+rP838gV9IgC
Fm1wNzbyNOCZBRcAWERbI6kXm1NafgmsiXX034R3l0uX5eo8GZod1Qz+Vu/VsVJY
8KnSO5PuPvP/70ThkWakTbeHK/NulElmNtLn2eDy182es89rWdDl4IDiioV5n+L9
z5kxlS2yxOjZo5fg/8wRXm1QWmjgO9L+TNWFVkiYtQwuHKIfUXTMfPPdshSj4Tan
VZtCAwCux63UECjhpJZlFVgiZWJHunvvNfj3org2Z8Sqg0h4bLsThKC9zHRp2Iwf
obKTsCucl5ZlYpqq5R12EJqIzfCVRsagU/+61JOcYMcSZhJ0M3ilNpYyI6GdM+Kt
3XuUHi3v7c0S1WeOgZEIc2DP7fD6ELWMnonIxUxRnyp0ftM2lZdbFhNDdwOZMS6V
4nGpnmWxci4KwEQURbmOgrk0OQgTaLvAzInY4K+BczAvt3xMneW5D8Cd+w6rVi/C
lnPvJSCiS+uGanayPBM4mXuWYa1fCWbQSya5TO0zOR4zaMwdT7RLFKJrv0h0XMAu
GAwA0ItXgBOaR4Wy0xW+AH0LfHQ0Zmc/rNI3h4j7niMM5WlqsK105z25luuXFZQ6
zp1Lg+MCreRcp79fIxiHanViMIOm0PS+8tfAPpPX6MnYJTFcUFsvcFLheTdHptJe
AenP7NdSJT8+vB8J9rS0VN+GmHURCfivGnM+Ndbzsem3qrn75tDsuOGhZu9CDzhd
2clc09BsOc6koKXLBd640i5beK0PZSJQ6qTR9+PHrwiwR05qdgv5H3nW+LtPmw==
=KXeu
hQIMAwDh3VI7VctTAQ//cov1yOeIduJaYdeIBJI50V7bh1XSLOQ9JG7xoYEDIiE+
a8ud6HP7hD+EmAqMLXFL1A/H0ELds+5qvVv3N/F7e3nkPdB/8/DHoBwpndFQ+DVQ
wJDUfchB5edzpKxRB2LfKGKiOG+yQXu2gf9s19yIrsLF/P8pXwjBRv+O4VmNvanh
hGq/+jVGGyXw8q9hjKpKNozNfsLQy0vXUZSi7b+CB9Uu0pWig+eAj9jsKC3ah6qq
Ahokko8bbLgor4cOLpNI48CDwA2gWZ3FxNHS34k+dQddXCOUF8/WcCFq4iFpWUaG
o+ZhyNFfnx3xIybPOfDZTIVLL0vBQcSC4hQFQoJ1TILtnPhTOJl/oTCfNuZ2WUDQ
LeJvicx0tAB4N8Luvpx8wPYkm7CvhXzEfztAOZZNBps3FNDKcM5d/LfraxHvwVlP
jzWfdz9jLhZiGMyZmgk6E4mA0AD4jpntmr4bpH4qpIdw9UNSNxivGa5K13hctIe2
RM33UetGvvJxvheBQKCgonozsnq0dmNIk1nFum4mb4eUKWM45yLqfLH5dhtmqGdY
5D2o8fSH7Gmp2oba/+cFxYXn7UY3rKITpMCSAFrl0OofMn+xefHG4Tu1L95kkr2I
iqCOAPmdfHIFhLNX908LTnU36vocLAH6HvT18sx5b1/tfQlws974s53wLFX4m0iF
AgwDC9FRLmchgYQBD/95NdfcrvDd6SE30FsJEXmiQhAYMzw75TiDeD07MtadbFlW
xDylS9J9Ej5a95oWv1PGwIRpF0F0FRbcQZY610F+D5CQYYEh2VdYXTKrI+Bd2UrJ
HGhB7vd2wpgrgaApmfDyKfsyxZvmUrHEnx7wyYjk86qU+wv/qNf71QNCbgi/eLhp
bS+lWB1/QvbqTWi/M9uymmmR5x+vo8QYjlDZBsSn6ukm4YzwQaf8RBxMsPGE3PI6
UXWmN9jNcHfkIisVY0JkFxsAwq/216f5V50xEPaaD48Dk5cO/QADdr8UsrNx9XZB
NWV9G44wl0UscXqWG/mpKDs7mnK4HsZSFF7VyYT6qq7ZySpGwN06WrfyGybYfjpn
AZ0IQlJW5dDtNpvLODDDJkSaMWSbe9LqIUHnbPIQHn3/bgk70wYCu7C9xhif+dzl
cczt8DASz1H9AnMquB4gamn2YdHK4UDgkOtmh0FhSkiw/XCJg+Mp5EpSShSofdnL
am8i4utT+8AOGCzEPeoQlRUGcwVmN4594SUhhXWk/bnrzxLkoz1PMD3LiD175CA8
CQ37mmAVHirpgMQY6OoaEMRTe18Y96keHQOaAUYFD5fKjlS8dMes7r8Oe79vH1fQ
Gkb1o9/QZOa9M7dErP6bhfhlb4GUpdFfZSxVhL6x+Y55sC7Jax39B2H9TNoBqdJe
AUEbEnvgoh2J7hgYibS4eGKZcDJnb5k0jKLGY/mMEJWLsKHYtQN4JIgG2Yj0bCc1
Xsv8AzgIAKtWxkl9E9CAb5dg4PB7yZDolFvnoKlcS0+4yqOWJZLjemu+ZwGGYw==
=pQM4
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted