diff --git a/flake.nix b/flake.nix index 4320abbd9..c54f46344 100644 --- a/flake.nix +++ b/flake.nix @@ -124,11 +124,13 @@ x86_64-linux = import ./hosts/nixos { inherit inputs; username = "shunkakinoki"; + stateVersion = "24.05"; }; runner = import ./hosts/nixos { inherit inputs; isRunner = true; username = "runner"; + stateVersion = "24.05"; }; matic = import ./named-hosts/matic { inherit inputs; diff --git a/home-manager/modules/xremap/default.nix b/home-manager/modules/xremap/default.nix index a8173f5fe..96d81cefe 100644 --- a/home-manager/modules/xremap/default.nix +++ b/home-manager/modules/xremap/default.nix @@ -87,6 +87,10 @@ let "${hyperPrefix}c" = "C-Shift-c"; "${hyperPrefix}v" = "C-Shift-v"; }; + # Slack: same mapping as global but isolated so Slack-specific workarounds + # (modifier leak, thread mark-as-read on bare `c`/`Esc`) can be tuned here + # without affecting other apps. See commits e60e0df, 95679b8, 48ad8f5. + slackRemap = globalRemap; in { config = lib.mkMerge [ @@ -109,6 +113,13 @@ in application.only = [ "com.mitchellh.ghostty" ]; remap = ghosttyRemap; } + { + # Slack: isolated block so modifier-leak / thread mark-as-read + # workarounds can be tuned without affecting other apps. + name = "Framework Command (Slack)"; + application.only = [ "Slack" ]; + remap = slackRemap; + } { # Global: no application filter — applies unconditionally so window detection # failures don't cause raw Hyper events to leak through to apps (e.g. Slack). diff --git a/home-manager/programs/fish/functions/_pixelh_function.fish b/home-manager/programs/fish/functions/_pixelh_function.fish index 9f707d026..e69de29bb 100644 --- a/home-manager/programs/fish/functions/_pixelh_function.fish +++ b/home-manager/programs/fish/functions/_pixelh_function.fish @@ -1,18 +0,0 @@ -function _pixelh_function --description "Run Pi headlessly with the local Qwen model" - # Prompt for input and run Pi in print mode with the local Qwen model - # Usage: pixelh - - set -l prompt - if test (count $argv) -gt 0 - set prompt (string join " " $argv) - else - read -P "Prompt: " prompt - end - - if test -z "$prompt" - echo "No prompt provided, aborting." >&2 - return 1 - end - - pi --model 'lmstudio/qwen3.5-0.8b-optiq' -p "$prompt" -end diff --git a/hosts/nixos/default.nix b/hosts/nixos/default.nix index 6cf8ce4f6..4b09ef6bc 100644 --- a/hosts/nixos/default.nix +++ b/hosts/nixos/default.nix @@ -1,123 +1,131 @@ +# Shared NixOS system builder. +# All NixOS hosts call this with their specific modules. +# When no modules are passed, includes generic config (x86_64-linux/runner). { inputs, username, hostname ? "x86_64-linux", isRunner ? false, + system ? "x86_64-linux", + stateVersion ? "24.11", + userExtraGroups ? [ ], + userInitialPassword ? null, + modules ? null, + specialArgs ? { }, }: let - inherit (inputs) nixpkgs home-manager; - system = "x86_64-linux"; nixpkgsConfig = import ../../lib/nixpkgs-config.nix { - nixpkgsLib = nixpkgs.lib; + nixpkgsLib = inputs.nixpkgs.lib; }; overlays = import ../../overlays { inherit inputs; }; - pkgs = import nixpkgs { + pkgs = import inputs.nixpkgs { inherit system overlays; config = nixpkgsConfig; }; - configuration = + + # Shared base: every NixOS host gets this + baseModule = { lib, ... }: { - boot.loader.grub.enable = true; - boot.loader.grub.device = "/dev/sda"; - boot.loader.grub.useOSProber = true; - boot.loader.systemd-boot.configurationLimit = 10; - networking.hostName = hostname; + networking.networkmanager.enable = true; + + programs.fish.enable = true; + users.users.${username} = { isNormalUser = true; extraGroups = [ "wheel" "networkmanager" - ]; + ] + ++ userExtraGroups; home = "/home/${username}"; - hashedPassword = if isRunner then "" else null; - openssh.authorizedKeys.keys = [ ]; + shell = pkgs.fish; + } + // lib.optionalAttrs (userInitialPassword != null) { + initialPassword = userInitialPassword; }; - users.users.root.hashedPassword = if isRunner then "" else null; - security.sudo.wheelNeedsPassword = false; - virtualisation = lib.mkIf isRunner { - vmware.guest.enable = true; - - libvirtd.enable = true; - - virtualbox.guest.enable = false; - - vmVariant = { - virtualisation = { - memorySize = 4096; - cores = 2; - }; - virtualisation.graphics = false; - virtualisation.sharedDirectories = { - shared = { - source = "$PWD"; - target = "/mnt/shared"; - }; - }; - }; - }; - - environment.systemPackages = with pkgs; [ - curl - git - home-manager - vim - wget - zellij - ]; - - services.getty.autologinUser = lib.mkIf isRunner "root"; - - boot.loader.timeout = lib.mkIf isRunner 0; - nix = { + channel.enable = false; settings = { experimental-features = [ "nix-command" "flakes" ]; + nix-path = lib.mkForce "nixpkgs=/etc/nix/inputs/nixpkgs"; substituters = [ "https://cache.nixos.org" ]; trusted-users = [ "root" username + "@wheel" ]; }; package = pkgs.nixVersions.stable; }; - boot.consoleLogLevel = 7; - services.journald.extraConfig = "Storage=volatile"; + environment.etc."nix/inputs/nixpkgs".source = "${inputs.nixpkgs}"; - system.stateVersion = "24.05"; + system.stateVersion = stateVersion; }; -in -nixpkgs.lib.nixosSystem { - inherit system; - inherit (nixpkgs) lib; - specialArgs = { - inherit username isRunner; - }; - modules = [ - configuration - { - fileSystems."/" = { - device = "/dev/sda1"; - fsType = "ext4"; - }; - nixpkgs.pkgs = pkgs; + # Generic config for x86_64-linux/runner (used when modules == null) + genericModules = [ + ( + { lib, ... }: + { + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/sda"; + boot.loader.grub.useOSProber = true; + boot.loader.systemd-boot.configurationLimit = 10; - fonts.packages = with pkgs; [ - nerd-fonts.jetbrains-mono - ]; - } - home-manager.nixosModules.home-manager + users.users.${username} = { + hashedPassword = if isRunner then "" else null; + openssh.authorizedKeys.keys = [ ]; + }; + + users.users.root.hashedPassword = if isRunner then "" else null; + + virtualisation = lib.mkIf isRunner { + vmware.guest.enable = true; + libvirtd.enable = true; + virtualbox.guest.enable = false; + vmVariant = { + virtualisation = { + memorySize = 4096; + cores = 2; + }; + virtualisation.graphics = false; + virtualisation.sharedDirectories = { + shared = { + source = "$PWD"; + target = "/mnt/shared"; + }; + }; + }; + }; + + services.getty.autologinUser = lib.mkIf isRunner "root"; + boot.loader.timeout = lib.mkIf isRunner 0; + + boot.consoleLogLevel = 7; + services.journald.extraConfig = "Storage=volatile"; + + fileSystems."/" = { + device = "/dev/sda1"; + fsType = "ext4"; + }; + + fonts.packages = with pkgs; [ + nerd-fonts.jetbrains-mono + ]; + } + ) + inputs.home-manager.nixosModules.home-manager { home-manager.backupFileExtension = "hm-backup"; home-manager.extraSpecialArgs = { inherit inputs; }; @@ -125,10 +133,26 @@ nixpkgs.lib.nixosSystem { home-manager.useUserPackages = true; home-manager.users."${username}" = import ../../home-manager { inherit inputs username; - inherit (nixpkgs) lib; + inherit (inputs.nixpkgs) lib; inherit pkgs; config = { }; }; } ]; +in +inputs.nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit + inputs + username + isRunner + ; + } + // specialArgs; + modules = [ + { nixpkgs.pkgs = pkgs; } + baseModule + ] + ++ (if modules == null then genericModules else modules); } diff --git a/lib/host.nix b/lib/host.nix index e5112cfb5..ec4fb8b1f 100644 --- a/lib/host.nix +++ b/lib/host.nix @@ -8,6 +8,9 @@ # Detect if running on matic (Framework 13) isMatic = builtins.getEnv "HOSTNAME" == "matic" || builtins.getEnv "HOST" == "matic"; + # Detect if running on viper (VM) + isViper = builtins.getEnv "HOSTNAME" == "viper" || builtins.getEnv "HOST" == "viper"; + # Desktop machines with GUI - default false, override in named-hosts isDesktop = false; @@ -23,6 +26,8 @@ "galactica" else if builtins.getEnv "HOSTNAME" == "matic" || builtins.getEnv "HOST" == "matic" then "matic" + else if builtins.getEnv "HOSTNAME" == "viper" || builtins.getEnv "HOST" == "viper" then + "viper" else "unknown"; } diff --git a/named-hosts/matic/default.nix b/named-hosts/matic/default.nix index 5549d7fea..9e301141b 100644 --- a/named-hosts/matic/default.nix +++ b/named-hosts/matic/default.nix @@ -4,25 +4,17 @@ ... }: let - system = "x86_64-linux"; - nixpkgsConfig = import ../../lib/nixpkgs-config.nix { - nixpkgsLib = inputs.nixpkgs.lib; - }; - overlays = import ../../overlays { inherit inputs; }; - pkgs = import inputs.nixpkgs { - inherit system overlays; - config = nixpkgsConfig; - }; - - # Check if falcon .deb exists (for conditional import) - # In CI, this will be false; locally with .deb present, it will be true falconDebExists = builtins.pathExists /etc/nixos/falcon-sensor.deb; in -inputs.nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs username; - }; +import ../../hosts/nixos { + inherit inputs username; + hostname = "matic"; + userExtraGroups = [ + "input" + "video" + "audio" + "docker" + ]; modules = [ # Framework 13" AMD AI 300 hardware support inputs.nixos-hardware.nixosModules.framework-amd-ai-300-series @@ -33,23 +25,15 @@ inputs.nixpkgs.lib.nixosSystem { # Kolide launcher ./kolide.nix - # Base system configuration + # System configuration ( - { config, lib, ... }: { - imports = [ - (import ../shared/linux-base.nix { - inherit inputs pkgs username; - hostname = "matic"; - userExtraGroups = [ - "input" - "video" - "audio" - "docker" - ]; - }) - ]; - + config, + lib, + pkgs, + ... + }: + { # Boot loader (EFI/systemd-boot) boot.loader.systemd-boot.enable = true; boot.loader.systemd-boot.configurationLimit = 10; @@ -91,7 +75,7 @@ inputs.nixpkgs.lib.nixosSystem { # Home Manager activation can take a long time (npm globals, cargo installs, etc.) systemd.services."home-manager-${username}".serviceConfig.TimeoutStartSec = lib.mkForce "30m"; - # Immutable root — prevents rm -rf / by blocking top-level entry removal + # Immutable root - prevents rm -rf / by blocking top-level entry removal systemd.services.immutable-root = { description = "Set immutable flag on /"; wantedBy = [ "multi-user.target" ]; @@ -143,7 +127,7 @@ inputs.nixpkgs.lib.nixosSystem { # so there are no timing/retry issues. Runs as root (can access TPM), then uses # runuser to speak the control socket protocol as the target user (SO_PEERCRED). # - # Credential stored at /etc/credstore.encrypted/gnome-keyring.cred — create once with: + # Credential stored at /etc/credstore.encrypted/gnome-keyring.cred - create once with: # sudo bash -c 'mkdir -p /etc/credstore.encrypted && \ # systemd-ask-password "Keyring password:" | \ # systemd-creds encrypt --name=gnome-keyring --with-key=tpm2+host \ @@ -166,10 +150,10 @@ inputs.nixpkgs.lib.nixosSystem { # # Protocol (all big-endian): # 1. connect to $XDG_RUNTIME_DIR/keyring/control (UNIX stream) - # 2. send \x00 — daemon reads our UID via SO_PEERCRED + # 2. send \x00 - daemon reads our UID via SO_PEERCRED # 3. send [oplen:4][op=1:4][pwlen:4][password bytes] # where oplen = 8 + 4 + len(password) - # 4. read [8:4][result:4] — result 0 = OK + # 4. read [8:4][result:4] - result 0 = OK unlockPy = pkgs.writeScript "unlock-gnome-keyring.py" ( builtins.readFile ( pkgs.replaceVars ./unlock-gnome-keyring.py { @@ -274,8 +258,8 @@ inputs.nixpkgs.lib.nixosSystem { systemd.services.greetd.wants = [ "fprintd.service" ]; # Disk management - services.gvfs.enable = true; # For automounting external drives in Nautilus and managing disk permissions - services.udisks2.enable = true; # For better integration with external drives, including NTFS support and proper permissions handling + services.gvfs.enable = true; + services.udisks2.enable = true; # Provide Hyprland session file for tuigreet to discover environment.etc."greetd/wayland-sessions/hyprland.desktop".text = '' @@ -325,7 +309,6 @@ inputs.nixpkgs.lib.nixosSystem { # Enable nix-ld for running dynamically linked binaries (CrowdStrike, Kolide, etc.) programs.nix-ld.enable = true; programs.nix-ld.libraries = with pkgs; [ - # Common libraries needed by security tools curl glibc libgcc @@ -333,208 +316,211 @@ inputs.nixpkgs.lib.nixosSystem { openssl zlib ]; - } ) # Fonts - { - nixpkgs.pkgs = pkgs; - - fonts.fontconfig.enable = true; - fonts.packages = with pkgs; [ - inter - ipaexfont - ipafont - joypixels - nerd-fonts.jetbrains-mono - noto-fonts-cjk-sans - noto-fonts-cjk-serif - noto-fonts-color-emoji - ]; - fonts.fontconfig.defaultFonts = { - serif = [ - "Noto Serif CJK JP" - "DejaVu Serif" - ]; - sansSerif = [ - "Inter" - "Noto Sans CJK JP" - "DejaVu Sans" - ]; - monospace = [ - "JetBrainsMono Nerd Font" - "Noto Sans Mono CJK JP" - ]; - emoji = [ - "JoyPixels" - "Noto Color Emoji" + ( + { pkgs, ... }: + { + fonts.fontconfig.enable = true; + fonts.packages = with pkgs; [ + inter + ipaexfont + ipafont + joypixels + nerd-fonts.jetbrains-mono + noto-fonts-cjk-sans + noto-fonts-cjk-serif + noto-fonts-color-emoji ]; - }; - } + fonts.fontconfig.defaultFonts = { + serif = [ + "Noto Serif CJK JP" + "DejaVu Serif" + ]; + sansSerif = [ + "Inter" + "Noto Sans CJK JP" + "DejaVu Sans" + ]; + monospace = [ + "JetBrainsMono Nerd Font" + "Noto Sans Mono CJK JP" + ]; + emoji = [ + "JoyPixels" + "Noto Color Emoji" + ]; + }; + } + ) # Home Manager integration inputs.home-manager.nixosModules.home-manager - { - home-manager.backupFileExtension = "hm-backup"; - home-manager.extraSpecialArgs = { - # Override host detection for matic (isDesktop = true) - inputs = inputs // { - host = (import ../../lib/host.nix) // { - isDesktop = true; + ( + { pkgs, ... }: + { + home-manager.backupFileExtension = "hm-backup"; + home-manager.extraSpecialArgs = { + inherit pkgs; + inputs = inputs // { + host = (import ../../lib/host.nix) // { + isDesktop = true; + }; }; }; - }; - home-manager.useGlobalPkgs = true; - home-manager.useUserPackages = true; - home-manager.users.${username} = - { config, lib, ... }: - { - imports = [ - (import ../../home-manager { - inherit username; - # Override host detection for matic (isDesktop = true) - inputs = inputs // { - host = (import ../../lib/host.nix) // { - isDesktop = true; + home-manager.useGlobalPkgs = true; + home-manager.useUserPackages = true; + home-manager.users.${username} = + { + config, + lib, + pkgs, + ... + }: + { + imports = [ + (import ../../home-manager { + inherit username pkgs; + inputs = inputs // { + host = (import ../../lib/host.nix) // { + isDesktop = true; + }; }; - }; - inherit (inputs.nixpkgs) lib; - inherit pkgs; - config = { }; - }) - ]; - - # Animated wallpaper via Wallpaper Engine - services.linux-wallpaperengine = { - enable = true; - assetsPath = "${config.home.homeDirectory}/.local/share/Steam/steamapps/common/wallpaper_engine/assets"; - wallpapers = [ - { - monitor = "eDP-1"; - wallpaperId = "2826529529"; - scaling = "fill"; - fps = 1; - audio.silent = true; - extraOptions = [ - "--no-audio-processing" - "--disable-mouse" - "--disable-parallax" - "--disable-particles" - ]; - } + inherit (inputs.nixpkgs) lib; + config = { }; + }) ]; - }; - # Force RADV (hardware Vulkan) for wallpaper engine instead of lavapipe (software rendering) - systemd.user.services.linux-wallpaperengine.Service.Environment = [ - "VK_DRIVER_FILES=/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json" - ]; + # Animated wallpaper via Wallpaper Engine + services.linux-wallpaperengine = { + enable = true; + assetsPath = "${config.home.homeDirectory}/.local/share/Steam/steamapps/common/wallpaper_engine/assets"; + wallpapers = [ + { + monitor = "eDP-1"; + wallpaperId = "2826529529"; + scaling = "fill"; + fps = 1; + audio.silent = true; + extraOptions = [ + "--no-audio-processing" + "--disable-mouse" + "--disable-parallax" + "--disable-particles" + ]; + } + ]; + }; - home.sessionVariables = { - VK_DRIVER_FILES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json"; - }; + # Force RADV (hardware Vulkan) for wallpaper engine instead of lavapipe (software rendering) + systemd.user.services.linux-wallpaperengine.Service.Environment = [ + "VK_DRIVER_FILES=/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json" + ]; - # Pause animated wallpaper on battery to save power (SIGSTOP/SIGCONT) - systemd.user.services.wallpaper-power-monitor = { - Unit = { - Description = "Pause wallpaper engine on battery, resume on AC"; - After = [ "linux-wallpaperengine.service" ]; - BindsTo = [ "linux-wallpaperengine.service" ]; + home.sessionVariables = { + VK_DRIVER_FILES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json"; }; - Service = { - Type = "simple"; - Restart = "on-failure"; - RestartSec = 5; - ExecStart = pkgs.writeShellScript "wallpaper-power-check" ( - builtins.readFile ( - pkgs.replaceVars ../../scripts/wallpaper-power-check.sh { - ac_supply_path = "/sys/class/power_supply/ACAD/online"; - systemctl = "${pkgs.systemd}/bin/systemctl"; - kill = "${pkgs.coreutils}/bin/kill"; - sleep = "${pkgs.coreutils}/bin/sleep"; + + # Pause animated wallpaper on battery to save power (SIGSTOP/SIGCONT) + systemd.user.services.wallpaper-power-monitor = { + Unit = { + Description = "Pause wallpaper engine on battery, resume on AC"; + After = [ "linux-wallpaperengine.service" ]; + BindsTo = [ "linux-wallpaperengine.service" ]; + }; + Service = { + Type = "simple"; + Restart = "on-failure"; + RestartSec = 5; + ExecStart = pkgs.writeShellScript "wallpaper-power-check" ( + builtins.readFile ( + pkgs.replaceVars ../../scripts/wallpaper-power-check.sh { + ac_supply_path = "/sys/class/power_supply/ACAD/online"; + systemctl = "${pkgs.systemd}/bin/systemctl"; + kill = "${pkgs.coreutils}/bin/kill"; + sleep = "${pkgs.coreutils}/bin/sleep"; + } + ) + ); + }; + Install.WantedBy = [ "linux-wallpaperengine.service" ]; + }; + + # Agenix configuration for GitHub SSH key + age.identityPaths = [ "/home/${username}/.ssh/id_ed25519" ]; + age.secrets = builtins.mapAttrs ( + name: value: + { + inherit (value) file; + } + // ( + if name == "keys/id_github.age" then + { + path = "/home/${username}/.ssh/id_ed25519_github"; + mode = "0600"; } - ) - ); + else + { } + ) + ) (import ./secrets.nix); + + # Ensure SSH directory exists before agenix tries to deploy secrets + home.activation.ensureSshDirectory = lib.hm.dag.entryBefore [ "writeBoundary" ] '' + $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/ensure-directory.sh}" "700" "${config.home.homeDirectory}/.ssh" + ''; + + # Ensure agenix config directory exists + home.activation.ensureAgenixDirectory = lib.hm.dag.entryBefore [ "writeBoundary" ] '' + $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/ensure-directory.sh}" "700" "${config.home.homeDirectory}/.config/agenix" + ''; + + # Manually deploy agenix secrets during activation + home.activation.deployAgenixSecrets = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/deploy-agenix-secret.sh}" \ + "${config.home.homeDirectory}/.ssh/id_ed25519_github" \ + "${builtins.toString ../galactica/keys/id_ed25519.age}" \ + "${config.home.homeDirectory}/.ssh/id_ed25519" \ + "${pkgs.rage}/bin/rage" + ''; + + # Import GPG key from agenix (all systems with dotfiles) + home.activation.importGpgKey = lib.hm.dag.entryAfter [ "linkGeneration" ] '' + $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/import-gpg-key.sh}" \ + "${config.home.homeDirectory}/dotfiles/named-hosts/galactica/keys/gpg.age" \ + "${config.home.homeDirectory}/.ssh/id_ed25519" \ + "${config.home.homeDirectory}/.config/agenix" \ + "${pkgs.rage}/bin/rage" \ + "${pkgs.gnupg}/bin/gpg" \ + "C2E97FCFF482925D" + ''; + + # GPG configuration for commit signing + programs.gpg = { + enable = true; + settings = { + default-key = "shunkakinoki@gmail.com"; + }; }; - Install.WantedBy = [ "linux-wallpaperengine.service" ]; - }; - # Agenix configuration for GitHub SSH key - age.identityPaths = [ "/home/${username}/.ssh/id_ed25519" ]; - age.secrets = builtins.mapAttrs ( - name: value: - { - inherit (value) file; - } - // ( - if name == "keys/id_github.age" then - { - # Deploy GitHub SSH key to ~/.ssh/ with correct permissions - path = "/home/${username}/.ssh/id_ed25519_github"; - mode = "0600"; - } - else - { } - ) - ) (import ./secrets.nix); - - # Ensure SSH directory exists before agenix tries to deploy secrets - home.activation.ensureSshDirectory = lib.hm.dag.entryBefore [ "writeBoundary" ] '' - $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/ensure-directory.sh}" "700" "${config.home.homeDirectory}/.ssh" - ''; - - # Ensure agenix config directory exists - home.activation.ensureAgenixDirectory = lib.hm.dag.entryBefore [ "writeBoundary" ] '' - $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/ensure-directory.sh}" "700" "${config.home.homeDirectory}/.config/agenix" - ''; - - # Manually deploy agenix secrets during activation - # This ensures secrets are deployed even if the agenix activation hook doesn't run properly - home.activation.deployAgenixSecrets = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/deploy-agenix-secret.sh}" \ - "${config.home.homeDirectory}/.ssh/id_ed25519_github" \ - "${builtins.toString ../galactica/keys/id_ed25519.age}" \ - "${config.home.homeDirectory}/.ssh/id_ed25519" \ - "${pkgs.rage}/bin/rage" - ''; - - # Import GPG key from agenix (all systems with dotfiles) - # Fails silently if SSH key isn't authorized to decrypt - home.activation.importGpgKey = lib.hm.dag.entryAfter [ "linkGeneration" ] '' - $DRY_RUN_CMD ${pkgs.bash}/bin/bash "${../../home-manager/activation/import-gpg-key.sh}" \ - "${config.home.homeDirectory}/dotfiles/named-hosts/galactica/keys/gpg.age" \ - "${config.home.homeDirectory}/.ssh/id_ed25519" \ - "${config.home.homeDirectory}/.config/agenix" \ - "${pkgs.rage}/bin/rage" \ - "${pkgs.gnupg}/bin/gpg" \ - "C2E97FCFF482925D" - ''; - - # GPG configuration for commit signing - programs.gpg = { - enable = true; - settings = { - default-key = "shunkakinoki@gmail.com"; + # GPG agent configuration + services.gpg-agent = { + enable = true; + enableSshSupport = false; + pinentry.package = pkgs.pinentry-gnome3; + defaultCacheTtl = 2147483647; + maxCacheTtl = 2147483647; }; - }; - # GPG agent configuration - services.gpg-agent = { - enable = true; - enableSshSupport = false; - pinentry.package = pkgs.pinentry-gnome3; - defaultCacheTtl = 2147483647; # max (effectively forever) - maxCacheTtl = 2147483647; # max (effectively forever) + # GPG_TTY is set in fish shell init instead of sessionVariables + # because it needs to be evaluated dynamically per shell session + programs.fish.interactiveShellInit = lib.mkAfter '' + set -gx GPG_TTY (tty) + ''; }; - - # GPG_TTY is set in fish shell init instead of sessionVariables - # because it needs to be evaluated dynamically per shell session - programs.fish.interactiveShellInit = lib.mkAfter '' - set -gx GPG_TTY (tty) - ''; - }; - } + } + ) ] - ++ (if falconDebExists then [ ./falcon.nix ] else [ ]); # CrowdStrike Falcon (only if .deb exists) + ++ (if falconDebExists then [ ./falcon.nix ] else [ ]); } diff --git a/named-hosts/matic/iso.nix b/named-hosts/matic/iso.nix index 93223fa2f..6a49b6aa4 100644 --- a/named-hosts/matic/iso.nix +++ b/named-hosts/matic/iso.nix @@ -3,27 +3,25 @@ username, ... }: -let - system = "x86_64-linux"; - nixpkgsConfig = import ../../lib/nixpkgs-config.nix { - nixpkgsLib = inputs.nixpkgs.lib; - }; - overlays = import ../../overlays { inherit inputs; }; - pkgs = import inputs.nixpkgs { - inherit system overlays; - config = nixpkgsConfig; - }; -in -inputs.nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs username; - }; +import ../../hosts/nixos { + inherit inputs username; + hostname = "matic"; + userInitialPassword = "changemeow"; modules = [ - (import ../shared/live-iso.nix { - inherit inputs pkgs username; - hostname = "matic"; - userInitialPassword = "changemeow"; - }) + "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" + "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/channel.nix" + ( + { lib, pkgs, ... }: + { + # ISO bootstrap - no home-manager available + environment.systemPackages = with pkgs; [ + curl + git + vim + ]; + image.fileName = "matic.iso"; + services.getty.helpLine = lib.mkForce ""; + } + ) ]; } diff --git a/named-hosts/shared/linux-base.nix b/named-hosts/shared/linux-base.nix deleted file mode 100644 index 5daa9da0b..000000000 --- a/named-hosts/shared/linux-base.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ - inputs, - pkgs, - username, - hostname, - userExtraGroups ? [ ], - userInitialPassword ? "changemeow", - stateVersion ? "24.11", -}: -{ lib, ... }: -{ - networking.hostName = hostname; - networking.networkmanager.enable = true; - - programs.fish.enable = true; - - users.users.${username} = { - isNormalUser = true; - extraGroups = [ - "wheel" - "networkmanager" - ] - ++ userExtraGroups; - home = "/home/${username}"; - shell = pkgs.fish; - initialPassword = userInitialPassword; - }; - - security.sudo.wheelNeedsPassword = false; - - nix = { - channel.enable = false; - settings = { - nix-path = lib.mkForce "nixpkgs=/etc/nix/inputs/nixpkgs"; - trusted-users = [ - username - "@wheel" - "root" - ]; - }; - }; - - environment.etc."nix/inputs/nixpkgs".source = "${inputs.nixpkgs}"; - - system.stateVersion = stateVersion; -} diff --git a/named-hosts/shared/live-iso.nix b/named-hosts/shared/live-iso.nix deleted file mode 100644 index eeca7f6a4..000000000 --- a/named-hosts/shared/live-iso.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ - inputs, - pkgs, - username, - hostname, - userInitialPassword, - isoName ? "${hostname}.iso", -}: -{ lib, ... }: -{ - imports = [ - "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" - "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/channel.nix" - (import ./linux-base.nix { - inherit - inputs - pkgs - username - hostname - userInitialPassword - ; - }) - ]; - - environment.systemPackages = with pkgs; [ - curl - git - vim - ]; - - image.fileName = isoName; - services.getty.helpLine = lib.mkForce ""; -} diff --git a/named-hosts/viper/default.nix b/named-hosts/viper/default.nix index 81b77456d..0c33b5da7 100644 --- a/named-hosts/viper/default.nix +++ b/named-hosts/viper/default.nix @@ -3,31 +3,15 @@ username, ... }: -let - system = "x86_64-linux"; - nixpkgsConfig = import ../../lib/nixpkgs-config.nix { - nixpkgsLib = inputs.nixpkgs.lib; - }; - overlays = import ../../overlays { inherit inputs; }; - pkgs = import inputs.nixpkgs { - inherit system overlays; - config = nixpkgsConfig; - }; -in -inputs.nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs username; - }; +import ../../hosts/nixos { + inherit inputs username; + hostname = "viper"; + userInitialPassword = "test"; modules = [ - (import ../shared/linux-base.nix { - inherit inputs pkgs username; - hostname = "viper"; - userInitialPassword = "test"; - }) ( { lib, + pkgs, modulesPath, ... }: @@ -43,6 +27,7 @@ inputs.nixpkgs.lib.nixosSystem { fsType = "ext4"; }; + # No home-manager on this host; install essentials at system level environment.systemPackages = with pkgs; [ curl git diff --git a/named-hosts/viper/iso.nix b/named-hosts/viper/iso.nix index 5cd4d9626..94f368c39 100644 --- a/named-hosts/viper/iso.nix +++ b/named-hosts/viper/iso.nix @@ -3,27 +3,25 @@ username, ... }: -let - system = "x86_64-linux"; - nixpkgsConfig = import ../../lib/nixpkgs-config.nix { - nixpkgsLib = inputs.nixpkgs.lib; - }; - overlays = import ../../overlays { inherit inputs; }; - pkgs = import inputs.nixpkgs { - inherit system overlays; - config = nixpkgsConfig; - }; -in -inputs.nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs username; - }; +import ../../hosts/nixos { + inherit inputs username; + hostname = "viper"; + userInitialPassword = "test"; modules = [ - (import ../shared/live-iso.nix { - inherit inputs pkgs username; - hostname = "viper"; - userInitialPassword = "test"; - }) + "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" + "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/channel.nix" + ( + { lib, pkgs, ... }: + { + # ISO bootstrap - no home-manager available + environment.systemPackages = with pkgs; [ + curl + git + vim + ]; + image.fileName = "viper.iso"; + services.getty.helpLine = lib.mkForce ""; + } + ) ]; } diff --git a/tests/lib.nix b/tests/lib.nix index 2769ef679..a650d32af 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -44,6 +44,12 @@ in else ''echo "FAIL: host.isMatic must exist and be a boolean" && exit 1'' } + ${ + if host ? isViper && builtins.isBool host.isViper then + ''echo "lib/host.nix: isViper is a boolean"'' + else + ''echo "FAIL: host.isViper must exist and be a boolean" && exit 1'' + } ${ if host ? nodeName && builtins.isString host.nodeName then ''echo "lib/host.nix: nodeName is a string (value: ${host.nodeName})"''