diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index c833eeb..0fff946 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ result *.~undo-tree~ *.iso .pre-commit-config.yaml +.direnv diff --git a/.sops.yaml b/.sops.yaml index f83caff..d061e5e 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -21,6 +21,16 @@ creation_rules: - *toto - *surface - *nbl + - path_regex: secrets/repo/[^/]+$ + key_groups: + - pgp: + - *swarsel + age: + - *winters + - *toto + - *surface + - *nbl + - *sync - path_regex: secrets/certs/[^/]+\.(yaml|json|env|ini)$ key_groups: - pgp: diff --git a/SwarselSystems.org b/SwarselSystems.org index a1395a8..6ab6a75 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -340,66 +340,74 @@ In this section I am creating some attributes that define general concepts of my They are defined in [[#h:5e3e21e0-57af-4dad-b32f-6400af9b7aab][Overlays (additions, overrides, nixpkgs-stable)]]. The way this is handled was simplified in =647a2ae feat: simplify overlay structure=; however, the old structure might be easier to understand as a reference. #+begin_src nix :tangle no :noweb-ref flakeoutputgeneral - inherit lib; + inherit lib; - # nixosModules = import ./modules/nixos { inherit lib; }; - # homeModules = import ./modules/home { inherit lib; }; - packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - overlays = import ./overlays { inherit self lib inputs; }; + # nixosModules = import ./modules/nixos { inherit lib; }; + # homeModules = import ./modules/home { inherit lib; }; + packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); + formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); + overlays = import ./overlays { inherit self lib inputs; }; - apps = lib.swarselsystems.forAllSystems (system: - let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in - - appSet // { - default = appSet.swarsel-bootstrap; - } - ); - - devShells = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - pkgs.statix - pkgs.deadnix - pkgs.nixpkgs-fmt + apps = lib.swarselsystems.forAllSystems (system: + let + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" ]; - }; - } - ); + appSet = lib.swarselsystems.mkApps system appNames self; + in - templates = import ./templates { inherit lib; }; + appSet // { + default = appSet.swarsel-bootstrap; + } + ); - checks = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); + devShells = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + checks = self.checks.${system}; + in + { + default = pkgs.mkShell { + NIX_CONFIG = '' + plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + buildInputs = [pkgs.nixVersions.latest pkgs.boost]; + patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; + })}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + inherit (checks.pre-commit-check) shellHook; - diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; + buildInputs = checks.pre-commit-check.enabledPackages; + nativeBuildInputs = [ + # (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. + pkgs.nix + pkgs.home-manager + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.statix + pkgs.deadnix + pkgs.nixpkgs-fmt + ]; + }; + } + ); + + templates = import ./templates { inherit lib; }; + + checks = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + in + import ./checks { inherit self inputs system pkgs; } + ); + + diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; #+end_src ** Pre-commit-hooks (Checks) @@ -849,7 +857,7 @@ My work machine. Built for more security, this is the gold standard of my config sharedOptions; home-manager.users."${primaryUser}" = { - home.stateVersion = lib.mkForce "23.05"; + # home.stateVersion = lib.mkForce "23.05"; swarselsystems = lib.recursiveUpdate { isLaptop = true; @@ -3685,6 +3693,136 @@ AppImage version of mgba in which the lua scripting works. #+end_src +**** swarsel-deploy + +#+begin_src nix :tangle pkgs/swarsel-deploy/default.nix + # heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix + { name, bc, nix-output-monitor, writeShellApplication, ... }: + writeShellApplication { + runtimeInputs = [ bc nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + shopt -s lastpipe # allow cmd | readarray + + function die() { + echo "error: $*" >&2 + exit 1 + } + function show_help() { + echo 'Usage: deploy [OPTIONS] [ACTION]' + echo "Builds, pushes and activates nixosConfigurations on target systems." + echo "" + echo 'ACTION:' + echo ' switch [default] Switch immediately to the new configuration and make it the boot default' + echo ' boot Make the configuration the new boot default' + echo " test Activate the configuration but don't make it the boot default" + echo " dry-activate Don't activate, just show what would be done" + echo "" + echo 'OPTIONS: [passed to nix build]' + } + + function time_start() { + T_START=$(date +%s.%N) + } + + function time_next() { + T_END=$(date +%s.%N) + T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1") + T_START="$T_END" + } + + cd ~/.dotfiles + USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) || + die "Could not determine current working directory. Something went very wrong." + [[ -e "$USER_FLAKE_DIR/flake.nix" ]] || + die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix." + cd "$USER_FLAKE_DIR" + + [[ $# -gt 0 ]] || { + show_help + exit 1 + } + + OPTIONS=() + POSITIONAL_ARGS=() + while [[ $# -gt 0 ]]; do + case "$1" in + "help" | "--help" | "-help" | "-h") + show_help + exit 1 + ;; + + -*) OPTIONS+=("$1") ;; + ,*) POSITIONAL_ARGS+=("$1") ;; + esac + shift + done + + [[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] || + die "Missing argument: " + [[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] || + die "Too many arguments given." + + tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS + ACTION="''${POSITIONAL_ARGS[1]-switch}" + + # Expand flake paths for hosts definitions + declare -A TOPLEVEL_FLAKE_PATHS + for host in "''${HOSTS[@]}"; do + TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel" + done + + time_start + + # Get outputs of all derivations (should be cached) + declare -A TOPLEVEL_STORE_PATHS + for host in "''${HOSTS[@]}"; do + toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}" + echo " Building 📦 $host" + nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json || + die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}" + TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel") + time_next + echo " Built ✅ $host ''${TOPLEVEL_STORE_PATHS["$host"]} in ''${T_LAST}s" + done + + current_host=$(hostname) + + for host in "''${HOSTS[@]}"; do + store_path="''${TOPLEVEL_STORE_PATHS["$host"]}" + + if [ "$host" = "$current_host" ]; then + echo -e "\033[1;36m Running locally for $host... \033[m" + ssh_prefix="sudo" + else + echo -e "\033[1;36m Copying \033[m➡️ \033[34m$host\033[m" + nix copy --to "ssh://$host" "$store_path" + time_next + echo -e "\033[1;32m Copied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + ssh_prefix="ssh $host --" + fi + + echo -e "\033[1;36m Applying \033[m⚙️ \033[34m$host\033[m" + prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system) + $ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" || + die "Failed to set system profile" + $ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" || + echo "Error while activating new system" >&2 + + if [[ -n $prev_system ]]; then + $ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true + fi + + time_next + echo -e "\033[1;32m Applied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + done + cd - + ''; + } + +#+end_src + **** sshrm This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually. @@ -3886,6 +4024,10 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a autologin = lib.mkDefault true; nswitch-rcm = lib.mkDefault true; }; + + server = { + ssh = lib.mkDefault true; + }; }; }; @@ -4490,8 +4632,6 @@ TODO { home-manager.users."${linuxUser}".imports = [ # put home-manager imports here that are for all normal hosts - inputs.sops-nix.homeManagerModules.sops - inputs.nix-index-database.hmModules.nix-index "${self}/modules/home/common" "${self}/modules/home/server" "${self}/modules/home/optional" @@ -4597,6 +4737,83 @@ TODO } #+end_src +*** Auxiliary files +**** extra-builtins + +#+begin_src nix :tangle nix/extra-builtins.nix + +{ exec, ... }: +let + assertMsg = pred: msg: pred || builtins.throw msg; + hasSuffix = + suffix: content: + let + lenContent = builtins.stringLength content; + lenSuffix = builtins.stringLength suffix; + in + lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix; +in +{ + # Instead of calling sops directly here, we call a wrapper script that will cache the output + # in a predictable path in /tmp, which allows us to only require the password for each encrypted + # file once. + sopsImportEncrypted = + nixFile: + assert assertMsg (builtins.isPath nixFile) + "The file to decrypt must be given as a path to prevent impurity."; + assert assertMsg (hasSuffix ".nix.age" nixFile) + "The content of the decrypted file must be a nix expression and should therefore end in .nix.age"; + exec [ + ./sops-decrypt-and-cache.sh + nixFile + ]; +} + +#+end_src +**** sops-decrypt-and-cache + +#+begin_src shell :tangle nix/sops-decrypt-and-cache.sh + #!/usr/bin/env bash + + set -euo pipefail + + print_out_path=false + if [[ $1 == "--print-out-path" ]]; then + print_out_path=true + shift + fi + + file="$1" + shift + + basename="$file" + # store path prefix or ./ if applicable + [[ $file == "/nix/store/"* ]] && basename="${basename#*"-"}" + [[ $file == "./"* ]] && basename="${basename#"./"}" + + # Calculate a unique content-based identifier (relocations of + # the source file in the nix store should not affect caching) + new_name="$(sha512sum "$file")" + new_name="${new_name:0:32}-${basename//"/"/"%"}" + + # Derive the path where the decrypted file will be stored + out="/var/tmp/nix-import-encrypted/$UID/$new_name" + umask 077 + mkdir -p "$(dirname "$out")" + + # Decrypt only if necessary + if [[ ! -e $out ]]; then + agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) + SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" + fi + + # Print out path or decrypted content + if [[ $print_out_path == true ]]; then + echo "$out" + else + cat "$out" + fi +#+end_src ** NixOS :PROPERTIES: :CUSTOM_ID: h:6da812f5-358c-49cb-aff2-0a94f20d70b3 @@ -4858,6 +5075,14 @@ We enable the use of =home-manager= as a NixoS module. A nice trick here is the home-manager = lib.mkIf config.swarselsystems.withHomeManager { useGlobalPkgs = true; useUserPackages = true; + verbose = true; + sharedModules = [ + inputs.nix-index-database.hmModules.nix-index + inputs.sops-nix.homeManagerModules.sops + { + home.stateVersion = lib.mkDefault config.system.stateVersion; + } + ]; extraSpecialArgs = { inherit (inputs) self; }; }; }; @@ -6450,7 +6675,7 @@ This dynamically uses systemd boot or Lanzaboote depending on `config.swarselsys lanzaboote = lib.mkIf (!config.swarselsystems.initialSetup && config.swarselsystems.isSecureBoot) { enable = true; pkiBundle = "/var/lib/sbctl"; - configurationLimit = 3; + configurationLimit = 6; }; }; }; @@ -6555,6 +6780,7 @@ Here we just define some aliases for rebuilding the system, and we allow some in environment.systemPackages = with pkgs; [ gnupg nix-index + nvd ssh-to-age git emacs @@ -6695,6 +6921,8 @@ Here we just define some aliases for rebuilding the system, and we allow some in :CUSTOM_ID: h:f3db197d-1d03-4bf8-b59f-f9891b358f0b :END: +Here I am forcing =startWhenNeeded= to false so that the value will not be set to true in containers = this would be a problem because it would delay ssh host key generation. + #+begin_src nix :tangle modules/nixos/server/ssh.nix { self, lib, config, ... }: { @@ -6702,6 +6930,18 @@ Here we just define some aliases for rebuilding the system, and we allow some in config = lib.mkIf config.swarselsystems.modules.server.ssh { services.openssh = { enable = true; + startWhenNeeded = lib.mkForce false; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "yes"; + }; + hostKeys = [ + { + path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; }; users.users."${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = [ (self + /secrets/keys/ssh/yubikey.pub) @@ -10166,6 +10406,7 @@ This is just a separate container for derivations defined in [[#h:64a5cc16-6b16- fhs swarsel-bootstrap swarsel-displaypower + swarsel-deploy swarselzellij sshrm @@ -10266,7 +10507,7 @@ It is very convenient to have SSH aliases in place for machines that I use. This }; "winters" = { hostname = "192.168.1.2"; - user = "swarsel"; + user = "root"; }; "minecraft" = { hostname = "130.61.119.129"; @@ -10943,8 +11184,10 @@ Currently I only use it as before with =initExtra= though. { hg = "history | grep"; hmswitch = "home-manager --flake ${flakePath}#$(whoami)@$(hostname) switch |& nom"; - nswitch = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v switch |& nom --json"; - nboot = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v boot |& nom --json"; + # nswitch = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v switch |& nom --json"; + nswitch = "swarsel-deploy $(hostname) switch"; + # nboot = "sudo nixos-rebuild --flake ${flakePath}#$(hostname) --show-trace --log-format internal-json -v boot |& nom --json"; + nboot = "swarsel-deploy $(hostname) boot"; magit = "emacsclient -nc -e \"(magit-status)\""; config = "git --git-dir=$HOME/.cfg/ --work-tree=$HOME"; g = "git"; diff --git a/flake.nix b/flake.nix index 25133aa..86872ec 100644 --- a/flake.nix +++ b/flake.nix @@ -128,10 +128,18 @@ in { default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; + NIX_CONFIG = '' + plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + buildInputs = [pkgs.nixVersions.latest pkgs.boost]; + patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; + })}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; inherit (checks.pre-commit-check) shellHook; + buildInputs = checks.pre-commit-check.enabledPackages; nativeBuildInputs = [ + # (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. pkgs.nix pkgs.home-manager pkgs.git diff --git a/index.html b/index.html index af9257c..6132682 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - + SwarselSystems: NixOS + Emacs Configuration @@ -263,9 +263,9 @@
  • 3.1.4.3. Home-manager only (default non-NixOS)
  • 3.1.4.4. ChaosTheatre (Demo Physical/VM)
  • @@ -305,7 +305,8 @@
  • 3.2.1.27. fhs
  • 3.2.1.28. swarsel-displaypower
  • 3.2.1.29. swarsel-mgba
  • -
  • 3.2.1.30. sshrm
  • +
  • 3.2.1.30. swarsel-deploy
  • +
  • 3.2.1.31. sshrm
  • 3.2.2. Overlays (additions, overrides, nixpkgs-stable)
  • @@ -313,33 +314,39 @@
  • 3.2.4. Library functions
  • +
  • 3.2.5. Auxiliary files + +
  • 3.3. NixOS @@ -356,51 +363,49 @@
  • 3.3.1.8. User setup, Make users non-mutable
  • 3.3.1.9. Environment setup
  • 3.3.1.10. Security
  • -
  • 3.3.1.11. Enable automatic garbage collection
  • -
  • 3.3.1.12. Enable automatic store optimisation
  • -
  • 3.3.1.13. Reduce systemd timeouts
  • -
  • 3.3.1.14. Hardware settings
  • -
  • 3.3.1.15. Pulseaudio
  • -
  • 3.3.1.16. Pipewire
  • -
  • 3.3.1.17. Common network settings
  • -
  • 3.3.1.18. Time, locale settings
  • -
  • 3.3.1.19. sops
  • -
  • 3.3.1.20. Theme (stylix)
  • -
  • 3.3.1.21. Programs (including zsh setup) +
  • 3.3.1.11. Reduce systemd timeouts
  • +
  • 3.3.1.12. Hardware settings
  • +
  • 3.3.1.13. Pulseaudio
  • +
  • 3.3.1.14. Pipewire
  • +
  • 3.3.1.15. Common network settings
  • +
  • 3.3.1.16. Time, locale settings
  • +
  • 3.3.1.17. sops
  • +
  • 3.3.1.18. Theme (stylix)
  • +
  • 3.3.1.19. Programs (including zsh setup)
  • -
  • 3.3.1.22. Services +
  • 3.3.1.20. Services
  • -
  • 3.3.1.23. Hardware compatibility settings (Yubikey, Ledger, Keyboards) - udev rules +
  • 3.3.1.21. Hardware compatibility settings (Yubikey, Ledger, Keyboards) - udev rules
  • -
  • 3.3.1.24. System Login
  • -
  • 3.3.1.25. nix-ld
  • -
  • 3.3.1.26. Impermanence
  • -
  • 3.3.1.27. Summary of nixos-rebuild diff
  • -
  • 3.3.1.28. gnome-keyring
  • -
  • 3.3.1.29. Sway
  • -
  • 3.3.1.30. xdg-portal
  • -
  • 3.3.1.31. Podmam (distrobox)
  • -
  • 3.3.1.32. Appimage
  • -
  • 3.3.1.33. Handle lid switch correctly
  • -
  • 3.3.1.34. Low battery notification
  • -
  • 3.3.1.35. Lanzaboote
  • +
  • 3.3.1.22. System Login
  • +
  • 3.3.1.23. nix-ld
  • +
  • 3.3.1.24. Impermanence
  • +
  • 3.3.1.25. Summary of nixos-rebuild diff
  • +
  • 3.3.1.26. gnome-keyring
  • +
  • 3.3.1.27. Sway
  • +
  • 3.3.1.28. xdg-portal
  • +
  • 3.3.1.29. Podmam (distrobox)
  • +
  • 3.3.1.30. Appimage
  • +
  • 3.3.1.31. Handle lid switch correctly
  • +
  • 3.3.1.32. Low battery notification
  • +
  • 3.3.1.33. Lanzaboote
  • 3.3.2. Server @@ -431,7 +436,7 @@
  • 3.3.2.24. FreshRSS
  • 3.3.2.25. forgejo (git server)
  • 3.3.2.26. Anki Sync Server
  • -
  • 3.3.2.27. IDM (kanidm + oauth2-proxy)
  • +
  • 3.3.2.27. IDM (kanidm + oauth2-proxy)
  • 3.3.3. Darwin @@ -446,11 +451,11 @@
  • 3.3.4.3. VmWare
  • 3.3.4.4. Auto-login
  • 3.3.4.5. nswitch-rcm
  • -
  • 3.3.4.6. Framework
  • -
  • 3.3.4.7. AMD CPU
  • -
  • 3.3.4.8. AMD GPU
  • -
  • 3.3.4.9. Hibernation
  • -
  • 3.3.4.10. BTRFS
  • +
  • 3.3.4.6. Framework
  • +
  • 3.3.4.7. AMD CPU
  • +
  • 3.3.4.8. AMD GPU
  • +
  • 3.3.4.9. Hibernation
  • +
  • 3.3.4.10. BTRFS
  • 3.3.4.11. work
  • 3.3.4.12. Minimal Install
  • @@ -499,7 +504,7 @@
  • 3.4.1.29.1. gnome-keyring
  • 3.4.1.29.2. KDE Connect
  • 3.4.1.29.3. Mako
  • -
  • 3.4.1.29.4. SwayOSD
  • +
  • 3.4.1.29.4. SwayOSD
  • 3.4.1.29.5. yubikey-touch-detector
  • @@ -524,7 +529,7 @@ @@ -702,7 +707,7 @@ @@ -711,7 +716,7 @@

    -This file has 65085 words spanning 17158 lines and was last revised on 2025-06-10 00:08:59 +0200. +This file has 66261 words spanning 17435 lines and was last revised on 2025-06-11 02:13:52 +0200.

    @@ -764,7 +769,7 @@ This section defines my Emacs configuration. For a while, I considered to use ry

    -My emacs is built using the emacs-overlay nix flake, which builds a bleeding edge emacs on wayland (pgtk) with utilities like treesitter support. By executing the below source block, the current build setting can be updated at any time, and you can see my most up-to-date build options (last updated: 2025-06-10 00:08:59 +0200) +My emacs is built using the emacs-overlay nix flake, which builds a bleeding edge emacs on wayland (pgtk) with utilities like treesitter support. By executing the below source block, the current build setting can be updated at any time, and you can see my most up-to-date build options (last updated: 2025-06-11 02:13:52 +0200)

    @@ -974,66 +979,74 @@ In outputs = inputs@ [...], the inputs@ makes it so th in { - inherit lib; + inherit lib; - # nixosModules = import ./modules/nixos { inherit lib; }; - # homeModules = import ./modules/home { inherit lib; }; - packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); - formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); - overlays = import ./overlays { inherit self lib inputs; }; + # nixosModules = import ./modules/nixos { inherit lib; }; + # homeModules = import ./modules/home { inherit lib; }; + packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; }); + formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt); + overlays = import ./overlays { inherit self lib inputs; }; - apps = lib.swarselsystems.forAllSystems (system: - let - appNames = [ - "swarsel-bootstrap" - "swarsel-install" - "swarsel-rebuild" - "swarsel-postinstall" - ]; - appSet = lib.swarselsystems.mkApps system appNames self; - in - - appSet // { - default = appSet.swarsel-bootstrap; - } - ); - - devShells = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - checks = self.checks.${system}; - in - { - default = pkgs.mkShell { - NIX_CONFIG = "experimental-features = nix-command flakes"; - inherit (checks.pre-commit-check) shellHook; - buildInputs = checks.pre-commit-check.enabledPackages; - nativeBuildInputs = [ - pkgs.nix - pkgs.home-manager - pkgs.git - pkgs.just - pkgs.age - pkgs.ssh-to-age - pkgs.sops - pkgs.statix - pkgs.deadnix - pkgs.nixpkgs-fmt + apps = lib.swarselsystems.forAllSystems (system: + let + appNames = [ + "swarsel-bootstrap" + "swarsel-install" + "swarsel-rebuild" + "swarsel-postinstall" ]; - }; - } - ); + appSet = lib.swarselsystems.mkApps system appNames self; + in - templates = import ./templates { inherit lib; }; + appSet // { + default = appSet.swarsel-bootstrap; + } + ); - checks = lib.swarselsystems.forAllSystems (system: - let - pkgs = lib.swarselsystems.pkgsFor.${system}; - in - import ./checks { inherit self inputs system pkgs; } - ); + devShells = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + checks = self.checks.${system}; + in + { + default = pkgs.mkShell { + NIX_CONFIG = '' + plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: { + buildInputs = [pkgs.nixVersions.latest pkgs.boost]; + patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ]; + })}/lib/nix/plugins + extra-builtins-file = ${self + /nix/extra-builtins.nix} + ''; + inherit (checks.pre-commit-check) shellHook; - diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; + buildInputs = checks.pre-commit-check.enabledPackages; + nativeBuildInputs = [ + # (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions. + pkgs.nix + pkgs.home-manager + pkgs.git + pkgs.just + pkgs.age + pkgs.ssh-to-age + pkgs.sops + pkgs.statix + pkgs.deadnix + pkgs.nixpkgs-fmt + ]; + }; + } + ); + + templates = import ./templates { inherit lib; }; + + checks = lib.swarselsystems.forAllSystems (system: + let + pkgs = lib.swarselsystems.pkgsFor.${system}; + in + import ./checks { inherit self inputs system pkgs; } + ); + + diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix; nixosConfigurations = lib.swarselsystems.mkFullHostConfigs (lib.swarselsystems.readHosts "nixos") "nixos"; @@ -1274,66 +1287,74 @@ They are defined in Overlays (
    -
    inherit lib;
    +
      inherit lib;
     
    -# nixosModules = import ./modules/nixos { inherit lib; };
    -# homeModules = import ./modules/home { inherit lib; };
    -packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; });
    -formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt);
    -overlays = import ./overlays { inherit self lib inputs; };
    +  # nixosModules = import ./modules/nixos { inherit lib; };
    +  # homeModules = import ./modules/home { inherit lib; };
    +  packages = lib.swarselsystems.forEachSystem (pkgs: import ./pkgs { inherit lib pkgs; });
    +  formatter = lib.swarselsystems.forEachSystem (pkgs: pkgs.nixpkgs-fmt);
    +  overlays = import ./overlays { inherit self lib inputs; };
     
    -apps = lib.swarselsystems.forAllSystems (system:
    -  let
    -    appNames = [
    -      "swarsel-bootstrap"
    -      "swarsel-install"
    -      "swarsel-rebuild"
    -      "swarsel-postinstall"
    -    ];
    -    appSet = lib.swarselsystems.mkApps system appNames self;
    -  in
    -
    -  appSet // {
    -    default = appSet.swarsel-bootstrap;
    -  }
    -);
    -
    -devShells = lib.swarselsystems.forAllSystems (system:
    -  let
    -    pkgs = lib.swarselsystems.pkgsFor.${system};
    -    checks = self.checks.${system};
    -  in
    -  {
    -    default = pkgs.mkShell {
    -      NIX_CONFIG = "experimental-features = nix-command flakes";
    -      inherit (checks.pre-commit-check) shellHook;
    -      buildInputs = checks.pre-commit-check.enabledPackages;
    -      nativeBuildInputs = [
    -        pkgs.nix
    -        pkgs.home-manager
    -        pkgs.git
    -        pkgs.just
    -        pkgs.age
    -        pkgs.ssh-to-age
    -        pkgs.sops
    -        pkgs.statix
    -        pkgs.deadnix
    -        pkgs.nixpkgs-fmt
    +  apps = lib.swarselsystems.forAllSystems (system:
    +    let
    +      appNames = [
    +        "swarsel-bootstrap"
    +        "swarsel-install"
    +        "swarsel-rebuild"
    +        "swarsel-postinstall"
           ];
    -    };
    -  }
    -);
    +      appSet = lib.swarselsystems.mkApps system appNames self;
    +    in
     
    -templates = import ./templates { inherit lib; };
    +    appSet // {
    +      default = appSet.swarsel-bootstrap;
    +    }
    +  );
     
    -checks = lib.swarselsystems.forAllSystems (system:
    -  let
    -    pkgs = lib.swarselsystems.pkgsFor.${system};
    -  in
    -  import ./checks { inherit self inputs system pkgs; }
    -);
    +  devShells = lib.swarselsystems.forAllSystems (system:
    +    let
    +      pkgs = lib.swarselsystems.pkgsFor.${system};
    +      checks = self.checks.${system};
    +    in
    +    {
    +      default = pkgs.mkShell {
    +        NIX_CONFIG = ''
    +          plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: {
    +            buildInputs = [pkgs.nixVersions.latest pkgs.boost];
    +            patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ];
    +          })}/lib/nix/plugins
    +          extra-builtins-file = ${self + /nix/extra-builtins.nix}
    +        '';
    +        inherit (checks.pre-commit-check) shellHook;
     
    -diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix;
    +        buildInputs = checks.pre-commit-check.enabledPackages;
    +        nativeBuildInputs = [
    +# (builtins.trace "alarm: we pinned nix_2_24 because of https://github.com/shlevy/nix-plugins/issues/20" pkgs.nixVersions.nix_2_24) # Always use the nix version from this flake's nixpkgs version, so that nix-plugins (below) doesn't fail because of different nix versions.
    +          pkgs.nix
    +          pkgs.home-manager
    +          pkgs.git
    +          pkgs.just
    +          pkgs.age
    +          pkgs.ssh-to-age
    +          pkgs.sops
    +          pkgs.statix
    +          pkgs.deadnix
    +          pkgs.nixpkgs-fmt
    +        ];
    +      };
    +    }
    +  );
    +
    +  templates = import ./templates { inherit lib; };
    +
    +  checks = lib.swarselsystems.forAllSystems (system:
    +    let
    +      pkgs = lib.swarselsystems.pkgsFor.${system};
    +    in
    +    import ./checks { inherit self inputs system pkgs; }
    +  );
    +
    +  diskoConfigurations.default = import .templates/hosts/nixos/disk-config.nix;
     
    @@ -1806,7 +1827,7 @@ in sharedOptions; home-manager.users."${primaryUser}" = { - home.stateVersion = lib.mkForce "23.05"; + # home.stateVersion = lib.mkForce "23.05"; swarselsystems = lib.recursiveUpdate { isLaptop = true; @@ -2885,8 +2906,8 @@ This is just a demo host. It applies all the configuration found in the common p I also set the WLR_RENDERER_ALLOW_SOFTWARE=1 to allow this configuration to run in a virtualized environment. I also enable qemuGuest for a smoother experience when testing on QEMU.

    -
    -
    3.1.4.4.1. Main configuration
    +
    +
    3.1.4.4.1. Main configuration
    { self, inputs, config, pkgs, lib, primaryUser, ... }:
    @@ -2965,8 +2986,8 @@ in
     
    -
    -
    3.1.4.4.2. NixOS dummy options configuration
    +
    +
    3.1.4.4.2. NixOS dummy options configuration
    _:
    @@ -2976,8 +2997,8 @@ in
     
    -
    -
    3.1.4.4.3. home-manager dummy options configuration
    +
    +
    3.1.4.4.3. home-manager dummy options configuration
    _:
    @@ -4758,9 +4779,142 @@ appimageTools.wrapType2 {
     
    -
    -
    3.2.1.30. sshrm
    +
    +
    3.2.1.30. swarsel-deploy
    +
    +
    # heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix
    +{ name, bc, nix-output-monitor, writeShellApplication, ... }:
    +writeShellApplication {
    +  runtimeInputs = [ bc nix-output-monitor ];
    +  inherit name;
    +  text = ''
    +    set -euo pipefail
    +    shopt -s lastpipe # allow cmd | readarray
    +
    +    function die() {
    +        echo "error: $*" >&2
    +        exit 1
    +    }
    +    function show_help() {
    +        echo 'Usage: deploy [OPTIONS] <host,...> [ACTION]'
    +        echo "Builds, pushes and activates nixosConfigurations on target systems."
    +        echo ""
    +        echo 'ACTION:'
    +        echo '  switch          [default] Switch immediately to the new configuration and make it the boot default'
    +        echo '  boot            Make the configuration the new boot default'
    +        echo "  test            Activate the configuration but don't make it the boot default"
    +        echo "  dry-activate    Don't activate, just show what would be done"
    +        echo ""
    +        echo 'OPTIONS: [passed to nix build]'
    +    }
    +
    +    function time_start() {
    +        T_START=$(date +%s.%N)
    +    }
    +
    +    function time_next() {
    +        T_END=$(date +%s.%N)
    +        T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1")
    +        T_START="$T_END"
    +    }
    +
    +    cd ~/.dotfiles
    +    USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) ||
    +        die "Could not determine current working directory. Something went very wrong."
    +    [[ -e "$USER_FLAKE_DIR/flake.nix" ]] ||
    +        die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix."
    +    cd "$USER_FLAKE_DIR"
    +
    +    [[ $# -gt 0 ]] || {
    +        show_help
    +        exit 1
    +    }
    +
    +    OPTIONS=()
    +    POSITIONAL_ARGS=()
    +    while [[ $# -gt 0 ]]; do
    +        case "$1" in
    +        "help" | "--help" | "-help" | "-h")
    +            show_help
    +            exit 1
    +            ;;
    +
    +        -*) OPTIONS+=("$1") ;;
    +        *) POSITIONAL_ARGS+=("$1") ;;
    +        esac
    +        shift
    +    done
    +
    +    [[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] ||
    +        die "Missing argument: <hosts...>"
    +    [[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] ||
    +        die "Too many arguments given."
    +
    +    tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS
    +    ACTION="''${POSITIONAL_ARGS[1]-switch}"
    +
    +    # Expand flake paths for hosts definitions
    +    declare -A TOPLEVEL_FLAKE_PATHS
    +    for host in "''${HOSTS[@]}"; do
    +        TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel"
    +    done
    +
    +    time_start
    +
    +    # Get outputs of all derivations (should be cached)
    +    declare -A TOPLEVEL_STORE_PATHS
    +    for host in "''${HOSTS[@]}"; do
    +        toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}"
    +        echo "    Building 📦 $host"
    +        nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json ||
    +            die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}"
    +        TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel")
    +        time_next
    +        echo "       Built ✅ $host ''${TOPLEVEL_STORE_PATHS["$host"]} in ''${T_LAST}s"
    +    done
    +
    +    current_host=$(hostname)
    +
    +    for host in "''${HOSTS[@]}"; do
    +        store_path="''${TOPLEVEL_STORE_PATHS["$host"]}"
    +
    +        if [ "$host" = "$current_host" ]; then
    +            echo -e "\033[1;36m    Running locally for $host... \033[m"
    +            ssh_prefix="sudo"
    +        else
    +            echo -e "\033[1;36m     Copying \033[m➡️  \033[34m$host\033[m"
    +            nix copy --to "ssh://$host" "$store_path"
    +            time_next
    +            echo -e "\033[1;32m      Copied \033[m✅  \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m"
    +            ssh_prefix="ssh $host --"
    +        fi
    +
    +        echo -e "\033[1;36m    Applying \033[m⚙️  \033[34m$host\033[m"
    +        prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system)
    +        $ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" ||
    +            die "Failed to set system profile"
    +        $ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" ||
    +            echo "Error while activating new system" >&2
    +
    +        if [[ -n $prev_system ]]; then
    +            $ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true
    +        fi
    +
    +        time_next
    +        echo -e "\033[1;32m     Applied \033[m✅  \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m"
    +    done
    +    cd -
    +  '';
    +}
    +
    +
    +
    +
    +
    +
    +
    3.2.1.31. sshrm
    +

    This programs simply runs ssh-keygen on the last host that I tried to ssh into. I need this frequently when working with cloud-init usually.

    @@ -4916,8 +5070,8 @@ in
    -
    -
    3.2.3.1.1. Personal
    +
    +
    3.2.3.1.1. Personal
    { lib, config, ... }:
    @@ -4933,8 +5087,6 @@ in
           users = lib.mkDefault true;
           env = lib.mkDefault true;
           security = lib.mkDefault true;
    -      gc = lib.mkDefault true;
    -      storeOptimize = lib.mkDefault true;
           systemdTimeout = lib.mkDefault true;
           hardware = lib.mkDefault true;
           pulseaudio = lib.mkDefault true;
    @@ -4974,6 +5126,10 @@ in
             autologin = lib.mkDefault true;
             nswitch-rcm = lib.mkDefault true;
           };
    +
    +      server = {
    +        ssh = lib.mkDefault true;
    +      };
         };
     
       };
    @@ -4984,8 +5140,8 @@ in
     
    -
    -
    3.2.3.1.2. Chaostheatre
    +
    +
    3.2.3.1.2. Chaostheatre
    { lib, config, ... }:
    @@ -5001,8 +5157,6 @@ in
           users = lib.mkDefault true;
           env = lib.mkDefault true;
           security = lib.mkDefault true;
    -      gc = lib.mkDefault true;
    -      storeOptimize = lib.mkDefault true;
           systemdTimeout = lib.mkDefault true;
           hardware = lib.mkDefault true;
           pulseaudio = lib.mkDefault true;
    @@ -5049,8 +5203,8 @@ in
     
    -
    -
    3.2.3.1.3. toto
    +
    +
    3.2.3.1.3. toto
    { lib, config, ... }:
    @@ -5082,8 +5236,8 @@ in
     
    -
    -
    3.2.3.1.4. Work
    +
    +
    3.2.3.1.4. Work
    { lib, config, ... }:
    @@ -5104,8 +5258,8 @@ in
     
    -
    -
    3.2.3.1.5. Framework
    +
    +
    3.2.3.1.5. Framework
    { lib, config, ... }:
    @@ -5126,8 +5280,8 @@ in
     
    -
    -
    3.2.3.1.6. AMD CPU
    +
    +
    3.2.3.1.6. AMD CPU
    { lib, config, ... }:
    @@ -5148,8 +5302,8 @@ in
     
    -
    -
    3.2.3.1.7. AMD GPU
    +
    +
    3.2.3.1.7. AMD GPU
    { lib, config, ... }:
    @@ -5170,8 +5324,8 @@ in
     
    -
    -
    3.2.3.1.8. Hibernation
    +
    +
    3.2.3.1.8. Hibernation
    { lib, config, ... }:
    @@ -5192,8 +5346,8 @@ in
     
    -
    -
    3.2.3.1.9. BTRFS
    +
    +
    3.2.3.1.9. BTRFS
    { lib, config, ... }:
    @@ -5214,8 +5368,8 @@ in
     
    -
    -
    3.2.3.1.10. Local Server
    +
    +
    3.2.3.1.10. Local Server
    { lib, config, ... }:
    @@ -5229,8 +5383,6 @@ in
             home-manager = lib.mkDefault true;
             home-managerExtra = lib.mkDefault true;
             xserver = lib.mkDefault true;
    -        gc = lib.mkDefault true;
    -        storeOptimize = lib.mkDefault true;
             time = lib.mkDefault true;
             users = lib.mkDefault true;
             server = {
    @@ -5268,8 +5420,8 @@ in
     
    -
    -
    3.2.3.1.11. OCI Sync Server
    +
    +
    3.2.3.1.11. OCI Sync Server
    { lib, config, ... }:
    @@ -5283,8 +5435,6 @@ in
             home-manager = lib.mkDefault true;
             home-managerExtra = lib.mkDefault true;
             xserver = lib.mkDefault true;
    -        gc = lib.mkDefault true;
    -        storeOptimize = lib.mkDefault true;
             time = lib.mkDefault true;
             users = lib.mkDefault true;
             server = {
    @@ -5326,8 +5476,8 @@ in
     
    -
    -
    3.2.3.2.1. Personal
    +
    +
    3.2.3.2.1. Personal
    { lib, config, ... }:
    @@ -5384,8 +5534,8 @@ in
     
    -
    -
    3.2.3.2.2. Chaostheatre
    +
    +
    3.2.3.2.2. Chaostheatre
    { lib, config, ... }:
    @@ -5437,8 +5587,8 @@ in
     
    -
    -
    3.2.3.2.3. toto
    +
    +
    3.2.3.2.3. toto
    { lib, config, ... }:
    @@ -5458,8 +5608,8 @@ in
     
    -
    -
    3.2.3.2.4. Work
    +
    +
    3.2.3.2.4. Work
    { lib, config, ... }:
    @@ -5479,8 +5629,8 @@ in
     
    -
    -
    3.2.3.2.5. Framework
    +
    +
    3.2.3.2.5. Framework
    { lib, config, ... }:
    @@ -5501,8 +5651,8 @@ in
     
    -
    -
    3.2.3.2.6. Darwin
    +
    +
    3.2.3.2.6. Darwin
    { lib, config, ... }:
    @@ -5520,8 +5670,8 @@ in
     
    -
    -
    3.2.3.2.7. Local Server
    +
    +
    3.2.3.2.7. Local Server
    { lib, config, ... }:
    @@ -5645,8 +5795,6 @@ in
               {
                 home-manager.users."${linuxUser}".imports = [
                   # put home-manager imports here that are for all normal hosts
    -              inputs.sops-nix.homeManagerModules.sops
    -              inputs.nix-index-database.hmModules.nix-index
                   "${self}/modules/home/common"
                   "${self}/modules/home/server"
                   "${self}/modules/home/optional"
    @@ -5754,6 +5902,97 @@ in
     
    +
    +

    3.2.5. Auxiliary files

    +
    +
    +
    +
    3.2.5.1. extra-builtins
    +
    +
    +
    +{ exec, ... }:
    +let
    +  assertMsg = pred: msg: pred || builtins.throw msg;
    +  hasSuffix =
    +    suffix: content:
    +    let
    +      lenContent = builtins.stringLength content;
    +      lenSuffix = builtins.stringLength suffix;
    +    in
    +    lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix;
    +in
    +{
    +  # Instead of calling sops directly here, we call a wrapper script that will cache the output
    +  # in a predictable path in /tmp, which allows us to only require the password for each encrypted
    +  # file once.
    +  sopsImportEncrypted =
    +    nixFile:
    +    assert assertMsg (builtins.isPath nixFile)
    +      "The file to decrypt must be given as a path to prevent impurity.";
    +    assert assertMsg (hasSuffix ".nix.age" nixFile)
    +      "The content of the decrypted file must be a nix expression and should therefore end in .nix.age";
    +    exec (
    +      [
    +        ./sops-decrypt-and-cache.sh
    +        nixFile
    +      ]
    +    );
    +}
    +
    +
    +
    +
    +
    +
    +
    3.2.5.2. sops-decrypt-and-cache
    +
    +
    +
    #!/usr/bin/env bash
    +
    +set -euo pipefail
    +
    +print_out_path=false
    +if [[ "$1" == "--print-out-path" ]]; then
    +  print_out_path=true
    +  shift
    +fi
    +
    +file="$1"
    +shift
    +
    +basename="$file"
    +# store path prefix or ./ if applicable
    +[[ "$file" == "/nix/store/"* ]] && basename="${basename#*"-"}"
    +[[ "$file" == "./"* ]] && basename="${basename#"./"}"
    +
    +# Calculate a unique content-based identifier (relocations of
    +# the source file in the nix store should not affect caching)
    +new_name="$(sha512sum "$file")"
    +new_name="${new_name:0:32}-${basename//"/"/"%"}"
    +
    +# Derive the path where the decrypted file will be stored
    +out="/var/tmp/nix-import-encrypted/$UID/$new_name"
    +umask 077
    +mkdir -p "$(dirname "$out")"
    +
    +# Decrypt only if necessary
    +if [[ ! -e "$out" ]]; then
    +  agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key)
    +  SOPS_AGE_KEY="$agekey" sops decrypt "${args[@]}" --output "$out" "$file"
    +fi
    +
    +# Print out path or decrypted content
    +if [[ "$print_out_path" == true ]]; then
    +  echo "$out"
    +else
    +  cat "$out"
    +fi
    +
    +
    +
    +
    +

    3.3. NixOS

    @@ -5826,6 +6065,34 @@ I usually use mutableUsers = false in my NixOS configuration. Howev isImpermanence = lib.mkEnableOption "use impermanence on this system"; isSecureBoot = lib.mkEnableOption "use secure boot on this system"; + + globals = lib.mkOption { + default = { }; + type = lib.types.submodule { + options = { + + services = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule { + options = { + domain = lib.mkOption { + type = lib.types.str; + description = "Domain that the service runs under"; + }; + }; + } + ); + }; + domains = { + main = lib.mkOption { + type = lib.types.str; + description = "My main domain."; + }; + }; + + }; + }; + }; }; } @@ -5874,7 +6141,7 @@ A breakdown of the flags being set:
    -
    { lib, config, outputs, inputs, ... }:
    +
    { self, lib, pkgs, config, outputs, inputs, ... }:
     {
       options.swarselsystems.modules.general = lib.mkEnableOption "general nix settings";
       config = lib.mkIf config.swarselsystems.modules.general {
    @@ -5885,6 +6152,11 @@ A breakdown of the flags being set:
           };
         };
     
    +    environment.etc."nixos/configuration.nix".source = pkgs.writeText "configuration.nix" ''
    +      assert builtins.trace "This location is not used. The config is found in ${config.swarselsystems.flakePath}!" false;
    +      { }
    +    '';
    +
         nix =
           let
             flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs;
    @@ -5911,11 +6183,32 @@ A breakdown of the flags being set:
               max-jobs = 1;
               use-cgroups = lib.mkIf config.swarselsystems.isLinux true;
             };
    +        gc = {
    +          automatic = true;
    +          dates = "weekly";
    +          options = "--delete-older-than 10d";
    +        };
    +        optimise = {
    +          automatic = true;
    +          dates = "weekly";
    +        };
             channel.enable = false;
    -        registry = lib.mapAttrs (_: flake: { inherit flake; }) flakeInputs;
    +        # registry = lib.mapAttrs (_: flake: { inherit flake; }) flakeInputs;
    +        registry = rec {
    +          nixpkgs.flake = inputs.nixpkgs;
    +          p = nixpkgs;
    +        };
             nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs;
    +        # extraOptions = ''
    +        #   plugin-files = ${pkgs.nix-plugins.overrideAttrs (o: {
    +        #     buildInputs = [pkgs.nixVersions.latest pkgs.boost];
    +        #     patches = (o.patches or []) ++ [ "${self}/nix/nix-plugins.patch" ];
    +        #   })}/lib/nix/plugins
    +        #   extra-builtins-file = ${self + /nix/extra-builtins.nix}
    +        # '';
           };
     
    +    services.dbus.implementation = "broker";
         system.stateVersion = lib.mkDefault "23.05";
       };
     }
    @@ -5931,8 +6224,21 @@ Mostly used to install some compilers and lsp's that I want to have available wh
     

    -
    { lib, config, pkgs, ... }:
    +
    { self, lib, config, pkgs, ... }:
    +# let
    +  # Try to access the extra builtin we loaded via nix-plugins.
    +  # Throw an error if that doesn't exist.
    +  # sopsImportEncrypted =
    +  #   assert lib.assertMsg (builtins ? extraBuiltins.sopsImportEncrypted)
    +  #     "The extra builtin sopsImportEncrypted' is not available, so repo.secrets cannot be decrypted. Did you forget to add nix-plugins and point it to `./nix/extra-builtins.nix` ?";
    +  #   builtins.extraBuiltins.sopsImportEncrypted;
    +  # secretFile = ../../../secrets/repo/packages.nix.age;
    +# in
     {
    +  # imports = [
    +  #   (sopsImportEncrypted secretFile)
    +  # ];
    +
       options.swarselsystems.modules.packages = lib.mkEnableOption "install packages";
       config = lib.mkIf config.swarselsystems.modules.packages {
         environment.systemPackages = with pkgs; [
    @@ -6034,6 +6340,14 @@ We enable the use of home-manager as a NixoS module. A nice trick h
         home-manager = lib.mkIf config.swarselsystems.withHomeManager {
           useGlobalPkgs = true;
           useUserPackages = true;
    +      verbose = true;
    +      sharedModules = [
    +        inputs.nix-index-database.hmModules.nix-index
    +        inputs.sops-nix.homeManagerModules.sops
    +      {
    +        home.stateVersion = lib.mkDefault config.system.stateVersion;
    +      }
    +      ];
           extraSpecialArgs = { inherit (inputs) self; };
         };
       };
    @@ -6183,59 +6497,12 @@ Needed for control over system-wide privileges etc. Also I make sure that the ro
         };
       };
     }
    -
    -
    -
    -
    -
    -
    3.3.1.11. Enable automatic garbage collection
    -
    -

    -The nix store fills up over time, until /boot/efi is filled. This snippet cleans it automatically on a weekly basis. -

    - -
    -
    { lib, config, ... }:
    -{
    -  options.swarselsystems.modules.gc = lib.mkEnableOption "garbage collection config";
    -  config = lib.mkIf config.swarselsystems.modules.gc {
    -    nix.gc = {
    -      automatic = true;
    -      randomizedDelaySec = "14m";
    -      dates = "weekly";
    -      options = "--delete-older-than 10d";
    -    };
    -  };
    -}
    -
    -
    -
    -
    -
    -
    3.3.1.12. Enable automatic store optimisation
    -
    -

    -This enables hardlinking identical files in the nix store, to save on disk space. I have read this incurs a significant I/O overhead, I need to keep an eye on this. -

    - -
    -
    { lib, config, ... }:
    -{
    -  options.swarselsystems.modules.storeOptimize = lib.mkEnableOption "store optimization config";
    -  config = lib.mkIf config.swarselsystems.modules.storeOptimize {
    -    nix.optimise = {
    -      automatic = true;
    -      dates = [ "weekly" ];
    -    };
    -  };
    -}
    -
     
    -
    3.3.1.13. Reduce systemd timeouts
    +
    3.3.1.11. Reduce systemd timeouts

    There is a persistent bug over Linux kernels that makes the user wait 1m30s on system shutdown due to the reason a stop job is running for session 1 of user .... I do not want to wait that long and am confident no important data is lost by doing this. @@ -6258,7 +6525,7 @@ There is a persistent bug over Linux kernels that makes the user wait 1m30s on s

    -
    3.3.1.14. Hardware settings
    +
    3.3.1.12. Hardware settings

    Enable OpenGL, Sound, Bluetooth and various drivers. @@ -6318,7 +6585,7 @@ Enable OpenGL, Sound, Bluetooth and various drivers.

    -
    3.3.1.15. Pulseaudio
    +
    3.3.1.13. Pulseaudio

    This is only used on systems not running Pipewire. @@ -6342,7 +6609,7 @@ This is only used on systems not running Pipewire.

    -
    3.3.1.16. Pipewire
    +
    3.3.1.14. Pipewire

    Pipewire handles communication on Wayland. This enables several sound tools as well as screen sharing in combinaton with xdg-desktop-portal-wlr. @@ -6373,7 +6640,7 @@ Pipewire handles communication on Wayland. This enables several sound tools as w

    -
    3.3.1.17. Common network settings
    +
    3.3.1.15. Common network settings

    Here I only enable networkmanager and a few default networks. The rest of the network config is done separately in System specific configuration. @@ -6636,7 +6903,7 @@ Here I only enable networkmanager and a few default networks. The r

    -
    3.3.1.18. Time, locale settings
    +
    3.3.1.16. Time, locale settings

    Setup timezone and locale. I want to use the US layout, but have the rest adapted to my country and timezone. Also, there is an issue with running Windows/Linux dualboot on the same machine where the hardware clock desyncs between the two OS'es. We fix that bug here as well. @@ -6673,7 +6940,7 @@ Setup timezone and locale. I want to use the US layout, but have the rest adapte

    -
    3.3.1.19. sops
    +
    3.3.1.17. sops

    I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: @@ -6746,7 +7013,7 @@ in

    -
    3.3.1.21. Programs (including zsh setup)
    +
    3.3.1.19. Programs (including zsh setup)

    Some programs profit from being installed through dedicated NixOS settings on system-level; these go here. Notably the zsh setup goes here and cannot be deleted under any circumstances. @@ -6798,10 +7065,10 @@ Some programs profit from being installed through dedicated NixOS settings on sy

    -
    3.3.1.21.1. zsh
    +
    3.3.1.19.1. zsh

    -Do not touch this. +Here I disable global completion to prevent redundant compinit calls and cache invalidation that slow down shell startup (enabled on the home-manager side).

    @@ -6809,7 +7076,10 @@ Do not touch this. { options.swarselsystems.modules.zsh = lib.mkEnableOption "zsh base config"; config = lib.mkIf config.swarselsystems.modules.zsh { - programs.zsh.enable = true; + programs.zsh = { + enable = true; + enableCompletion = false; + }; users.defaultUserShell = pkgs.zsh; environment.shells = with pkgs; [ zsh ]; environment.pathsToLink = [ "/share/zsh" ]; @@ -6820,7 +7090,7 @@ Do not touch this.
    -
    3.3.1.21.2. syncthing
    +
    3.3.1.19.2. syncthing
    { lib, config, ... }:
    @@ -6885,14 +7155,14 @@ in
     
    -
    3.3.1.22. Services
    +
    3.3.1.20. Services

    Setting up some hardware services as well as keyboard related settings. Here we make sure that we can use the CAPS key as a ESC/CTRL double key, which is a lifesaver.

    -
    3.3.1.22.1. blueman
    +
    3.3.1.20.1. blueman

    Enables the blueman service including the nice system tray icon. @@ -6912,7 +7182,7 @@ Enables the blueman service including the nice system tray icon.

    -
    3.3.1.22.2. Network devices
    +
    3.3.1.20.2. Network devices

    In this section we enable compatibility with several network devices I have at home, mainly printers and scanners. @@ -6963,7 +7233,7 @@ Avahi is the service used for the network discovery.

    -
    3.3.1.22.3. enable GVfs
    +
    3.3.1.20.3. enable GVfs

    This is being set to allow myself to use all functions of nautilus in NixOS @@ -6982,7 +7252,7 @@ This is being set to allow myself to use all functions of nautilus in NixOS

    -
    3.3.1.22.4. interception-tools: Make CAPS work as ESC/CTRL
    +
    3.3.1.20.4. interception-tools: Make CAPS work as ESC/CTRL

    This is a super-convenient package that lets my remap my CAPS key to ESC if pressed shortly, and CTRL if being held. @@ -7026,7 +7296,7 @@ This is a super-convenient package that lets my remap my CAPS key t

    -
    3.3.1.22.5. power-profiles-daemon
    +
    3.3.1.20.5. power-profiles-daemon

    This enables power profile management. The available modes are: @@ -7054,9 +7324,9 @@ Most of the time I am using power-saver, however, it is good to be

    -
    -
    3.3.1.22.6. SwayOSD
    -
    +
    +
    3.3.1.20.6. SwayOSD
    +
    { lib, pkgs, config, ... }:
     {
    @@ -7086,11 +7356,11 @@ Most of the time I am using power-saver, however, it is good to be
     
    -
    3.3.1.23. Hardware compatibility settings (Yubikey, Ledger, Keyboards) - udev rules
    +
    3.3.1.21. Hardware compatibility settings (Yubikey, Ledger, Keyboards) - udev rules
    -
    3.3.1.23.1. Yubikey
    +
    3.3.1.21.1. Yubikey

    This takes care of the main Yubikey related configuration on the NixOS side - note that the starting of the gpg-agent is done in the sway settings, to also perform this step of the setup for non NixOS-machines at the same time. @@ -7130,7 +7400,7 @@ Also, since I use a GPG key in sops, it seems that scdaemon creates an instance

    -
    3.3.1.23.2. Ledger
    +
    3.3.1.21.2. Ledger

    This performs the necessary configuration to support this hardware. @@ -7154,7 +7424,7 @@ This performs the necessary configuration to support this hardware.

    -
    3.3.1.23.3. Keyboards
    +
    3.3.1.21.3. Keyboards

    This loads some udev rules that I need for my split keyboards. @@ -7178,7 +7448,7 @@ This loads some udev rules that I need for my split keyboards.

    -
    3.3.1.24. System Login
    +
    3.3.1.22. System Login

    This section houses the greetd related settings. I do not really want to use a display manager, but it is useful to have setup in some ways - in my case for starting sway on system startup. Notably the default user login setting that is commented out here goes into the system specific settings, make sure to update it there @@ -7189,6 +7459,16 @@ This section houses the greetd related settings. I do not really want to use a d { options.swarselsystems.modules.login = lib.mkEnableOption "login config"; config = lib.mkIf config.swarselsystems.modules.login { + + # services.displayManager.enable = true; + # programs.uwsm = { + # enable = true; + # waylandCompositors.sway = { + # prettyName = "Sway"; + # comment = "Sway"; + # binPath = lib.getExe pkgs.sway; + # }; + # }; services.greetd = { enable = true; settings = { @@ -7213,7 +7493,7 @@ This section houses the greetd related settings. I do not really want to use a d

    -
    3.3.1.25. nix-ld
    +
    3.3.1.23. nix-ld

    This provides libraries for binaries that are not patched for use on NixOS. This really makes the biggest gripe with NixOS go away, that being having to run a binary that is only found in a single spot. It is most of the times possible to patch such a file, but this makes such a situation take much less time to resolve. @@ -7346,7 +7626,7 @@ When a program does not work, start with nix-ldd <program>. T

    -
    3.3.1.26. Impermanence
    +
    3.3.1.24. Impermanence

    This is where the impermanence magic happens. When this is enabled, the root directory is rolled back to a blanket state on each reboot. @@ -7456,7 +7736,7 @@ in

    -
    3.3.1.27. Summary of nixos-rebuild diff
    +
    3.3.1.25. Summary of nixos-rebuild diff

    This snipped is added to the activation script that is run after every rebuild and shows what packages have been added and removed. This is actually not the optimal place to add that snipped, but the correct spot is in some perl file that I have not had the leisure to take a look at yet. @@ -7481,7 +7761,7 @@ This snipped is added to the activation script that is run after every rebuild a

    -
    3.3.1.28. gnome-keyring
    +
    3.3.1.26. gnome-keyring

    Used for storing sessions in e.g. Nextcloud. Using this on a system level keeps the login information when logging out of the session as well. @@ -7504,7 +7784,7 @@ Used for storing sessions in e.g. Nextcloud. Using this on a system level keeps

    -
    3.3.1.29. Sway
    +
    3.3.1.27. Sway

    This is used to better integrate Sway into the system on NixOS hosts. On the home-manager side, the package attribute will be null for such an host, using the systems derivation instead. @@ -7540,7 +7820,7 @@ This is used to better integrate Sway into the system on NixOS hosts. On the hom

    -
    3.3.1.30. xdg-portal
    +
    3.3.1.28. xdg-portal

    This allows me to use screen sharing on Wayland. The implementation is a bit crude and only the whole screen can be shared. However, most of the time that is all I need to do anyways. @@ -7572,7 +7852,7 @@ This allows me to use screen sharing on Wayland. The implementation is a bit cru

    -
    3.3.1.31. Podmam (distrobox)
    +
    3.3.1.29. Podmam (distrobox)

    I am using distrobox to quickly circumvent isses that I cannot immediately solve on NixOS. It is always the goal to quickly get things working on NixOS, but this prevents me from getting completely stuck. @@ -7600,7 +7880,7 @@ I am using distrobox to quickly circumvent isses that I cannot immediately solve

    -
    3.3.1.32. Appimage
    +
    3.3.1.30. Appimage

    Adds the necessary tools to allow .appimage programs easily. @@ -7623,7 +7903,7 @@ Adds the necessary tools to allow .appimage programs easily.

    -
    3.3.1.33. Handle lid switch correctly
    +
    3.3.1.31. Handle lid switch correctly

    This turns off the display when the lid is closed. @@ -7672,7 +7952,7 @@ This turns off the display when the lid is closed.

    -
    3.3.1.35. Lanzaboote
    +
    3.3.1.33. Lanzaboote

    This dynamically uses systemd boot or Lanzaboote depending on `config.swarselsystems.initialSetup` and `config.swarselsystems.isSecureBoot`. @@ -7732,7 +8012,7 @@ This dynamically uses systemd boot or Lanzaboote depending on `config.swarselsys lanzaboote = lib.mkIf (!config.swarselsystems.initialSetup && config.swarselsystems.isSecureBoot) { enable = true; pkiBundle = "/var/lib/sbctl"; - configurationLimit = 3; + configurationLimit = 6; }; }; }; @@ -7773,8 +8053,6 @@ in "${modulesPath}/nixos/common/home-manager.nix" "${modulesPath}/nixos/common/home-manager-extra.nix" "${modulesPath}/nixos/common/xserver.nix" - "${modulesPath}/nixos/common/gc.nix" - "${modulesPath}/nixos/common/store.nix" "${modulesPath}/nixos/common/time.nix" "${modulesPath}/nixos/common/users.nix" "${modulesPath}/nixos/common/nix-ld.nix" @@ -7846,6 +8124,7 @@ in environment.systemPackages = with pkgs; [ gnupg nix-index + nvd ssh-to-age git emacs @@ -7986,6 +8265,10 @@ in

    3.3.2.7. ssh
    +

    +Here I am forcing startWhenNeeded to false so that the value will not be set to true in containers = this would be a problem because it would delay ssh host key generation. +

    +
    { self, lib, config, ... }:
     {
    @@ -7993,6 +8276,18 @@ in
       config = lib.mkIf config.swarselsystems.modules.server.ssh {
         services.openssh = {
           enable = true;
    +      startWhenNeeded = lib.mkForce false;
    +      settings = {
    +        PasswordAuthentication = false;
    +        KbdInteractiveAuthentication = false;
    +        PermitRootLogin = "yes";
    +      };
    +      hostKeys = [
    +        {
    +          path = "/etc/ssh/ssh_host_ed25519_key";
    +          type = "ed25519";
    +        }
    +      ];
         };
         users.users."${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = [
           (self + /secrets/keys/ssh/yubikey.pub)
    @@ -9875,8 +10170,8 @@ in
     
    -
    -
    3.3.2.27. IDM (kanidm + oauth2-proxy)
    +
    +
    3.3.2.27. IDM (kanidm + oauth2-proxy)

    The forgejo configuration is a little broken and will show a 500 error when signing in through kanidm. However, when pressing back and refreshing the page, I am logged in. Currently I cannot be bothered to fix this. @@ -10400,6 +10695,10 @@ in config = lib.mkIf config.swarselsystems.modules.optional.autologin { services = { getty.autologinUser = mainUser; + # displayManager.autoLogin = lib.mkIf config.swarselsystems.modules.login { + # enable = true; + # user = mainUser; + # }; greetd.settings.initial_session.user = mainUser; }; }; @@ -10433,8 +10732,8 @@ This smashes Atmosphere 1.3.2 on the switch, which is what I am currenty using.

    -
    -
    3.3.4.6. Framework
    +
    +
    3.3.4.6. Framework

    This holds configuration that is specific to framework laptops. @@ -10472,8 +10771,8 @@ This holds configuration that is specific to framework laptops.

    -
    -
    3.3.4.7. AMD CPU
    +
    +
    3.3.4.7. AMD CPU
    { lib, config, ... }:
    @@ -10489,8 +10788,8 @@ This holds configuration that is specific to framework laptops.
     
    -
    -
    3.3.4.8. AMD GPU
    +
    +
    3.3.4.8. AMD GPU
    { lib, config, ... }:
    @@ -10512,8 +10811,8 @@ This holds configuration that is specific to framework laptops.
     
    -
    -
    3.3.4.9. Hibernation
    +
    +
    3.3.4.9. Hibernation
    { lib, config, ... }:
    @@ -10544,8 +10843,8 @@ This holds configuration that is specific to framework laptops.
     
    -
    -
    3.3.4.10. BTRFS
    +
    +
    3.3.4.10. BTRFS
    -
    -
    3.4.1.29.4. SwayOSD
    +
    +
    3.4.1.29.4. SwayOSD
    { lib, config, ... }:
    @@ -14743,8 +15046,8 @@ in
     
    -
    -
    3.4.4.3. Framework
    +
    +
    3.4.4.3. Framework

    This holds configuration that is specific to framework laptops. @@ -18584,8 +18887,8 @@ autocmd DocStart vc-impimba-1.m.imp.ac.at/ui/webconsole mode ignore

    -
    -

    6.3. tridactyl theme

    +
    +

    6.3. tridactyl theme

    @@ -19082,7 +19385,7 @@ sync USER HOST:
     
    diff --git a/lib/default.nix b/lib/default.nix index 5396f40..b3a6b25 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -71,8 +71,6 @@ in { home-manager.users."${linuxUser}".imports = [ # put home-manager imports here that are for all normal hosts - inputs.sops-nix.homeManagerModules.sops - inputs.nix-index-database.hmModules.nix-index "${self}/modules/home/common" "${self}/modules/home/server" "${self}/modules/home/optional" diff --git a/modules/home/common/custom-packages.nix b/modules/home/common/custom-packages.nix index cbb57dc..39fc054 100644 --- a/modules/home/common/custom-packages.nix +++ b/modules/home/common/custom-packages.nix @@ -24,6 +24,7 @@ fhs swarsel-bootstrap swarsel-displaypower + swarsel-deploy swarselzellij sshrm diff --git a/modules/home/common/ssh.nix b/modules/home/common/ssh.nix index af34294..f1b9f33 100644 --- a/modules/home/common/ssh.nix +++ b/modules/home/common/ssh.nix @@ -16,7 +16,7 @@ }; "winters" = { hostname = "192.168.1.2"; - user = "swarsel"; + user = "root"; }; "minecraft" = { hostname = "130.61.119.129"; diff --git a/modules/nixos/common/home-manager.nix b/modules/nixos/common/home-manager.nix index 070f94f..c6645d8 100644 --- a/modules/nixos/common/home-manager.nix +++ b/modules/nixos/common/home-manager.nix @@ -6,6 +6,14 @@ home-manager = lib.mkIf config.swarselsystems.withHomeManager { useGlobalPkgs = true; useUserPackages = true; + verbose = true; + sharedModules = [ + inputs.nix-index-database.hmModules.nix-index + inputs.sops-nix.homeManagerModules.sops + { + home.stateVersion = lib.mkDefault config.system.stateVersion; + } + ]; extraSpecialArgs = { inherit (inputs) self; }; }; }; diff --git a/modules/nixos/common/lanzaboote.nix b/modules/nixos/common/lanzaboote.nix index 6801eda..b0f3c94 100644 --- a/modules/nixos/common/lanzaboote.nix +++ b/modules/nixos/common/lanzaboote.nix @@ -10,7 +10,7 @@ lanzaboote = lib.mkIf (!config.swarselsystems.initialSetup && config.swarselsystems.isSecureBoot) { enable = true; pkiBundle = "/var/lib/sbctl"; - configurationLimit = 3; + configurationLimit = 6; }; }; }; diff --git a/modules/nixos/server/packages.nix b/modules/nixos/server/packages.nix index 61c8bf5..7094668 100644 --- a/modules/nixos/server/packages.nix +++ b/modules/nixos/server/packages.nix @@ -5,6 +5,7 @@ environment.systemPackages = with pkgs; [ gnupg nix-index + nvd ssh-to-age git emacs diff --git a/modules/nixos/server/ssh.nix b/modules/nixos/server/ssh.nix index 09f5eef..cb8b7ad 100644 --- a/modules/nixos/server/ssh.nix +++ b/modules/nixos/server/ssh.nix @@ -4,6 +4,18 @@ config = lib.mkIf config.swarselsystems.modules.server.ssh { services.openssh = { enable = true; + startWhenNeeded = lib.mkForce false; + settings = { + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + PermitRootLogin = "yes"; + }; + hostKeys = [ + { + path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } + ]; }; users.users."${config.swarselsystems.mainUser}".openssh.authorizedKeys.keyFiles = [ (self + /secrets/keys/ssh/yubikey.pub) diff --git a/nix/extra-builtins.nix b/nix/extra-builtins.nix new file mode 100644 index 0000000..b26b15f --- /dev/null +++ b/nix/extra-builtins.nix @@ -0,0 +1,26 @@ +{ exec, ... }: +let + assertMsg = pred: msg: pred || builtins.throw msg; + hasSuffix = + suffix: content: + let + lenContent = builtins.stringLength content; + lenSuffix = builtins.stringLength suffix; + in + lenContent >= lenSuffix && builtins.substring (lenContent - lenSuffix) lenContent content == suffix; +in +{ + # Instead of calling sops directly here, we call a wrapper script that will cache the output + # in a predictable path in /tmp, which allows us to only require the password for each encrypted + # file once. + sopsImportEncrypted = + nixFile: + assert assertMsg (builtins.isPath nixFile) + "The file to decrypt must be given as a path to prevent impurity."; + assert assertMsg (hasSuffix ".nix.age" nixFile) + "The content of the decrypted file must be a nix expression and should therefore end in .nix.age"; + exec [ + ./sops-decrypt-and-cache.sh + nixFile + ]; +} diff --git a/nix/nix-plugins.patch b/nix/nix-plugins.patch new file mode 100644 index 0000000..13e3082 --- /dev/null +++ b/nix/nix-plugins.patch @@ -0,0 +1,21 @@ +diff --git a/extra-builtins.cc b/extra-builtins.cc +index 3a0f90e..bb10f8b 100644 +--- a/extra-builtins.cc ++++ b/extra-builtins.cc +@@ -1,9 +1,9 @@ +-#include +-#include +-#include +-#include +-#include +-#include +-#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + #include "nix-plugins-config.h" diff --git a/nix/sops-decrypt-and-cache.sh b/nix/sops-decrypt-and-cache.sh new file mode 100755 index 0000000..37a80bc --- /dev/null +++ b/nix/sops-decrypt-and-cache.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -euo pipefail + +print_out_path=false +if [[ $1 == "--print-out-path" ]]; then + print_out_path=true + shift +fi + +file="$1" +shift + +basename="$file" +# store path prefix or ./ if applicable +[[ $file == "/nix/store/"* ]] && basename="${basename#*"-"}" +[[ $file == "./"* ]] && basename="${basename#"./"}" + +# Calculate a unique content-based identifier (relocations of +# the source file in the nix store should not affect caching) +new_name="$(sha512sum "$file")" +new_name="${new_name:0:32}-${basename//"/"/"%"}" + +# Derive the path where the decrypted file will be stored +out="/var/tmp/nix-import-encrypted/$UID/$new_name" +umask 077 +mkdir -p "$(dirname "$out")" + +# Decrypt only if necessary +if [[ ! -e $out ]]; then + agekey=$(sudo ssh-to-age -private-key -i /etc/ssh/sops || sudo ssh-to-age -private-key -i /etc/ssh/ssh_host_ed25519_key) + SOPS_AGE_KEY="$agekey" sops decrypt --output "$out" "$file" +fi + +# Print out path or decrypted content +if [[ $print_out_path == true ]]; then + echo "$out" +else + cat "$out" +fi diff --git a/pkgs/swarsel-deploy/default.nix b/pkgs/swarsel-deploy/default.nix new file mode 100644 index 0000000..fb197e4 --- /dev/null +++ b/pkgs/swarsel-deploy/default.nix @@ -0,0 +1,124 @@ +# heavily inspired from https://github.com/oddlama/nix-config/blob/d42cbde676001a7ad8a3cace156e050933a4dcc3/pkgs/deploy.nix +{ name, bc, nix-output-monitor, writeShellApplication, ... }: +writeShellApplication { + runtimeInputs = [ bc nix-output-monitor ]; + inherit name; + text = '' + set -euo pipefail + shopt -s lastpipe # allow cmd | readarray + + function die() { + echo "error: $*" >&2 + exit 1 + } + function show_help() { + echo 'Usage: deploy [OPTIONS] [ACTION]' + echo "Builds, pushes and activates nixosConfigurations on target systems." + echo "" + echo 'ACTION:' + echo ' switch [default] Switch immediately to the new configuration and make it the boot default' + echo ' boot Make the configuration the new boot default' + echo " test Activate the configuration but don't make it the boot default" + echo " dry-activate Don't activate, just show what would be done" + echo "" + echo 'OPTIONS: [passed to nix build]' + } + + function time_start() { + T_START=$(date +%s.%N) + } + + function time_next() { + T_END=$(date +%s.%N) + T_LAST=$(${bc}/bin/bc <<< "scale=1; ($T_END - $T_START)/1") + T_START="$T_END" + } + + cd ~/.dotfiles + USER_FLAKE_DIR=$(git rev-parse --show-toplevel 2> /dev/null || pwd) || + die "Could not determine current working directory. Something went very wrong." + [[ -e "$USER_FLAKE_DIR/flake.nix" ]] || + die "Could not determine location of your project's flake.nix. Please run this at or below your main directory containing the flake.nix." + cd "$USER_FLAKE_DIR" + + [[ $# -gt 0 ]] || { + show_help + exit 1 + } + + OPTIONS=() + POSITIONAL_ARGS=() + while [[ $# -gt 0 ]]; do + case "$1" in + "help" | "--help" | "-help" | "-h") + show_help + exit 1 + ;; + + -*) OPTIONS+=("$1") ;; + *) POSITIONAL_ARGS+=("$1") ;; + esac + shift + done + + [[ ''${#POSITIONAL_ARGS[@]} -ge 1 ]] || + die "Missing argument: " + [[ ''${#POSITIONAL_ARGS[@]} -le 2 ]] || + die "Too many arguments given." + + tr , '\n' <<< "''${POSITIONAL_ARGS[0]}" | sort -u | readarray -t HOSTS + ACTION="''${POSITIONAL_ARGS[1]-switch}" + + # Expand flake paths for hosts definitions + declare -A TOPLEVEL_FLAKE_PATHS + for host in "''${HOSTS[@]}"; do + TOPLEVEL_FLAKE_PATHS["$host"]=".#nixosConfigurations.$host.config.system.build.toplevel" + done + + time_start + + # Get outputs of all derivations (should be cached) + declare -A TOPLEVEL_STORE_PATHS + for host in "''${HOSTS[@]}"; do + toplevel="''${TOPLEVEL_FLAKE_PATHS["$host"]}" + echo " Building 📦 $host" + nix build --no-link "''${OPTIONS[@]}" --show-trace --log-format internal-json -v "$toplevel" |& ${nix-output-monitor}/bin/nom --json || + die "Failed to get derivation path for $host from ''${TOPLEVEL_FLAKE_PATHS["$host"]}" + TOPLEVEL_STORE_PATHS["$host"]=$(nix build --no-link --print-out-paths "''${OPTIONS[@]}" "$toplevel") + time_next + echo " Built ✅ $host ''${TOPLEVEL_STORE_PATHS["$host"]} in ''${T_LAST}s" + done + + current_host=$(hostname) + + for host in "''${HOSTS[@]}"; do + store_path="''${TOPLEVEL_STORE_PATHS["$host"]}" + + if [ "$host" = "$current_host" ]; then + echo -e "\033[1;36m Running locally for $host... \033[m" + ssh_prefix="sudo" + else + echo -e "\033[1;36m Copying \033[m➡️ \033[34m$host\033[m" + nix copy --to "ssh://$host" "$store_path" + time_next + echo -e "\033[1;32m Copied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + ssh_prefix="ssh $host --" + fi + + echo -e "\033[1;36m Applying \033[m⚙️ \033[34m$host\033[m" + prev_system=$($ssh_prefix readlink -e /nix/var/nix/profiles/system) + $ssh_prefix /run/current-system/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set "$store_path" || + die "Failed to set system profile" + $ssh_prefix "$store_path"/bin/switch-to-configuration "$ACTION" || + echo "Error while activating new system" >&2 + + if [[ -n $prev_system ]]; then + $ssh_prefix nvd --color always diff "$prev_system" "$store_path" || true + fi + + time_next + echo -e "\033[1;32m Applied \033[m✅ \033[34m$host\033[m \033[90min ''${T_LAST}s\033[m" + done + cd - + ''; +} diff --git a/profiles/nixos/personal/default.nix b/profiles/nixos/personal/default.nix index 570fe3e..b8e83c7 100644 --- a/profiles/nixos/personal/default.nix +++ b/profiles/nixos/personal/default.nix @@ -52,6 +52,10 @@ autologin = lib.mkDefault true; nswitch-rcm = lib.mkDefault true; }; + + server = { + ssh = lib.mkDefault true; + }; }; }; diff --git a/secrets/repo/packages.nix.age b/secrets/repo/packages.nix.age new file mode 100644 index 0000000..295343d --- /dev/null +++ b/secrets/repo/packages.nix.age @@ -0,0 +1,38 @@ +{ + "data": "ENC[AES256_GCM,data:HOKAicZWRXn7EJdyLKfRuX1OFyWAZJKl5hteN3VzZfjlg+RuSg0/Q3xAxkc0spc2tUnwFLbtJsGkEip+ze9wpAYD6tvk9lDorgZY,iv:Yfz7LZcH0rVZ8cGCGiq0k03b1vB1H0b2pblXDjudMH8=,tag:IQW2IrBMcFBtbxx7SGg7vg==,type:str]", + "sops": { + "age": [ + { + "recipient": "age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3QjVKRENZV3d0TzlyNEhp\ndGcwaGNOT01wRlc5eW5JYjFHUUNONVFyNjM0CitnUHExUThpVmtkazFmOWt5N2J3\naGdoTUY3Y3JjL3hXRDVha3V1L3U4bFEKLS0tIGhjT3BGdWRZYkZCdHNRdDRMQnpi\nVi9hR2JTRVk2UUlQRHVXS0RLN2tpT3cKDSpdUF5s/rYEWRG9BDF53BAWzfkFAblH\nl+uwzdKc9+bxda5fwe7EFFxlJ+AYSqhyUcVqLV+NQO97avOdARadrg==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzc2lGU0ZUMmlHbXNXTzdi\ndzlkaVg0WC92ZUg1WXpPZnRJWU5aalRnVGxNCmJVQUVvM0lDSzMvWlZtcWtmZVVH\nYVI0dkpJa3hRTUI3VHFYSmpsZ1FhQWcKLS0tIHhHVHdyRzM5ZVhsbnBSZHdMSDRv\nMGNvaXNNdnoxM2RMNWJQd0gwZWdlYWcK4lGnEXO4D1cJV/U6yC7GRHhanVnDRCS4\nX3WZsvLHZob6bpmK+G/5zA+OQnmqXTSBNxgd3jMEHaJOMPAtVonyWA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1zlnxraee6tddr07xn59mx5rdexw8qxryd53eqlsajasfhfy78fkq705dfg", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArSGg4NmtiVzBwYUVlWDJ4\nK3h2OFBkbmI4aEpTMUlaQk5wcUluMU11TWlvCklCY0F2VUZEYVNCREdKdkJsbmww\nZjBJYjZGOHBhWk9sblRSM2x5NGNlRlkKLS0tIGpiQnY5QkNpVGpTWk1pV2kxNTN5\nRiswRlFJYktTYUwrd3lTUmFydTBRV0EKRX2dBU+aohpa03F54M1MgrGQtfxvW88n\nZI36m8M7EgA1ij6dhnlKxEDcYSIx/dd5cu+IMBujrDewuSaU7HhyNQ==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age16lnmuuxfuxxtty3atnhut8wseppwnhp7rdhmxqd5tdvs9qnjffjq42sqyy", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuaEpCNEpwNXhRQ1FQWi9W\nRVdXazVtS3BlVE5oRnd5Y1RkdUZ5Sm9HN1hnCm82YWhWRzQzNW1iZVFTTDJScDJy\nTHA5d1ZhTUlSNU9vUllqVG5NSmk4TXcKLS0tIHAwOFk3cFFuTXZrdUN4cjlaWTM4\nLzJWUk95QWROMFFsa3l2NmJhS2pEaTAKwjzQ+Fh1A8bE/Jajf3mviDgLE0ECv/u+\nDG9yegxklNGJr/F82bkYtCizruMMPrBUq9WiM58/og98IuuSC+D2MA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1glge4e97vgqzh332mqs5990vteezu2m8k4wq3z35jk0q8czw3gks2d7a3h", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnNENFYjZpZmZHaHdPU2pj\nelQvUWRjcENCSVVNSmU4MWwvVlRkbUFaajBZClhMR1d1VHIzSkdGMmx1bXo0R2t4\nUkMxN3d1WjlZOVRML0tOQmJQNEJ3VmsKLS0tIEt2ejYzUUVSOVZZMVh3blViM2xG\nNXdkZk91WndaYmRiN1dVaDhxZ1l5eDQKFTUi+3P9SBPrIyxPGs5E8BoYAVXXcJ6P\n+9yNQ465s7Zeq4ExVFleqleubhIfYlShxMyQlIbOeE8AVqubN7kyLQ==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-06-10T17:55:09Z", + "mac": "ENC[AES256_GCM,data:sh/ZOcT86S9gDWv2tzSefWR0jbT/1HsW1UGt67yxTFSp4w+koKk6fZxkRVBefu31DANObn1NR7re3xX3YPVRQ2oiov3tLg+hOmdBziXr7xg43vhWGQQTXk9/g7K3Bv9XCy+mISw2R92FZ4lmo9PhJV96aDnd+CUInR+OTHxfceU=,iv:efFyYq5rcQ97Y2sidFbdkiX9hndznR/doRNKz2r85iY=,tag:NzSxZWDlXi8q0+OWaRMK9Q==,type:str]", + "pgp": [ + { + "created_at": "2025-06-10T14:51:46Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwDh3VI7VctTAQ/9FPkVx1F30ZnXGBRkOmZkf7Gfh6K4o5JtI12cdZsajsjR\nwO8ScNT8H/imnShKGmchg/oaeq/3Tr9UJgwWm+RFeeJ/i0RbmsS+0gHVhoHKjQev\nF5Fa4s/Af1XJld6A+zOCAt9QJrNOxe1Wthrv8L4DbCpuO/bV8rurLC6k/2GXbHeO\nfVnCi0aptosxNz4C73HRLMCX7MNsE+uhiRA/kPpDzLmWvh4/6GE50874dakk8ygg\n6uQ7RRJ5ULoQKUxjvk++wvc8uhYuplcDe6pbbM3Q9NIzjEf1Ef2g6wGiXyZ+QpWU\ntE5ScTCDxzhcund8zgk/JNmajIhup3qQG64ex8rnhvlICtUWBtHVtRsf0nVvylCz\nuI2TN4KbuyuHU4lTVETCuML+8VI7zkGmUvh2Kp3ib7uXcnuFrakPy/cFWBBzd2a1\nebvYnoZL34uzXBrWXI9fidQWIiNpvqVbM2HnRC9dMyXGgP+Yr6IasX8g2tAAC6DY\nMw4IEBwtcCLxlGFYCxD47GcDCr6z95oC8Smg7L2x0KqyZEh3M6OS+z9HSVKy2Nz7\n0pFJwUQAqP3RZMLML/ZB+kcSx+g6I0tKGSegBIBHJ9Em8CTOWhuYTOu9DweRKtA7\nIx0DNBXtLn5nNNJlXJvaz55ggDtR2egoXiM9a+TDcW83qSRRNvtWYrkEuFrc7RmF\nAgwDC9FRLmchgYQBEACRk/NKKVN+qWu8EPuyAd3gkDOFPmKwnqZxYra86J0qpBr1\nNeCKGAFIV+VePnhDWW2KQeZYNpxQn4qJ5zaLO7cXMFwMhQgxmanih3lyS28Z5RkL\nm2xNnSr60M1qSm4Q04orv/WreBtzoAKWUh6mnXvf1Wldz1v2Bm2TT9GKkanb2EzB\noVr2tXTU3ZO2jbCeGab4c68RkzgGCK5RlJJhW05+9/b7gN2nK4GmxpWzlL6f62v9\n5ZJmMfJFvix6d0sE+1bToGL6SpM7jb51RlapUNXRXhG9z+74PwmwPPHNVzXlt8ne\nYzIYFpE7rTzP/0hYF0WnDIQANk/1nt7z6qV6cxD0tN88GPzMJYRuSYih4M8kNsiE\nkhxkKU4Aj7RjNwoMjTqquQtzmiL0Faak1HH22gr8jvLIwnVFtV70BndNro90a94Z\n1UZI+ip94DTRqRoCInLGcIO7LrDho6npOucusZtMObnzqxU2GDfoKWv+HW93boV8\nRvFv6bPGCmFvFbVnhO5UHV9E/8RVdIfYKavbo5w6qGy1DNPr3yrDeUP9k0dBV6sK\nhgTX5lxPPmO/U4DN1AltP3+LhjxhO9qGZ+rXSvjt38v/59gHq9JYtYZnaxQ0WxIU\nc/jWLPt5RKNmmXw4FFP5h4TotJXysxs9iPaH4t48zPbxoxYgzV7/NCMHNYgAANJe\nAUwDGCm5kyyzXDhiWG8xbZgwBBdsDnVWO7cCOQjzW1n+inZoNb4S+YjflVvckWdL\n89Lk0qtZceMis9AWYdF123jAH3okPDRjUtkLWy4dqjToqaYyQpG+YFMI+5j0ig==\n=JSDc\n-----END PGP MESSAGE-----", + "fp": "4BE7925262289B476DBBC17B76FD3810215AE097" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.10.2" + } +}