diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index 858a152..0000000 --- a/NOTES.md +++ /dev/null @@ -1,13 +0,0 @@ -# Notes -## 16-04 -- See if pinentry should be a variable and how pure ssh (no gpg anymore) handles pinentry. -- Reconsider placement and existence of system-base.nix -- Implement system-wide theming system -- Do we need separate stateVersions per host? -- pinentry.nix should not set programs consuming it explicitly, should probably be host-level concern or smoething. -- Primary email schema validation should not be located inside aspects like git.nix but somewhere in the schema definition probably -- assertions are defined, not sure if that actually does anything. - -Code style related todos: -Consistent rules/guidelines for function or attribute set at root of aspect file. -When to nest sets and when to set directly (podman.nix). diff --git a/README.md b/README.md new file mode 100644 index 0000000..566ac3f --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# NixOS configuration + +Host identity and topology live in `modules/hosts//default.nix`; shared account, +service, external-device, and server-topology facts live in `modules/facts.nix`. + +- Add a package used by both workstations to the relevant Home Manager capability, + or to `workstation-apps` in `modules/capabilities/desktop-defaults.nix` when it needs + no configuration. +- Add a host-specific capability to that host's import list in + `modules/hosts//default.nix`. +- Change the selected terminal or editor by replacing the corresponding + `primary-terminal-*` import in `modules/profiles/workstation-base.nix` or + `primary-editor-*` import in `modules/profiles/host-base.nix`. +- Keep native theme settings with the application. Explicit Kanagawa color mappings + may import `modules/capabilities/_kanagawa.nix`. + +Common commands: + +```console +nix fmt +nix flake check --no-build +nh os switch +sops edit modules/secrets/secrets.yaml +``` diff --git a/modules/capabilities/_kanagawa.nix b/modules/capabilities/_kanagawa.nix new file mode 100644 index 0000000..e177995 --- /dev/null +++ b/modules/capabilities/_kanagawa.nix @@ -0,0 +1,41 @@ +{ + displayName = "Kanagawa Wave"; + + palette = { + background = "#1F1F28"; + foreground = "#DCD7BA"; + secondaryBackground = "#16161D"; + subtleBorder = "#54546D"; + selectionBackground = "#2D4F67"; + selectionForeground = "#C8C093"; + url = "#72A7BC"; + cursor = "#C8C093"; + muted = "#727169"; + + accents = { + blue = "#7E9CD8"; + red = "#E82424"; + }; + + terminal = { + color0 = "#16161D"; + color1 = "#C34043"; + color2 = "#76946A"; + color3 = "#C0A36E"; + color4 = "#7E9CD8"; + color5 = "#957FB8"; + color6 = "#6A9589"; + color7 = "#C8C093"; + color8 = "#727169"; + color9 = "#E82424"; + color10 = "#98BB6C"; + color11 = "#E6C384"; + color12 = "#7FB4CA"; + color13 = "#938AA9"; + color14 = "#7AA89F"; + color15 = "#DCD7BA"; + color16 = "#FFA066"; + color17 = "#FF5D62"; + }; + }; +} diff --git a/modules/capabilities/_svelte-language-server.nix b/modules/capabilities/_svelte-language-server.nix new file mode 100644 index 0000000..5f73e0e --- /dev/null +++ b/modules/capabilities/_svelte-language-server.nix @@ -0,0 +1,25 @@ +{ pkgs }: +pkgs.svelte-language-server.overrideAttrs ( + finalAttrs: _: { + version = "0.18.3"; + + src = pkgs.fetchFromGitHub { + owner = "sveltejs"; + repo = "language-tools"; + tag = "svelte-language-server@${finalAttrs.version}"; + hash = "sha256-FTOkJPXbsG6R53yr4n0/IR2lzFCovrdV0+epOi07lBQ="; + }; + + pnpmDeps = pkgs.fetchPnpmDeps { + inherit (finalAttrs) + pname + version + src + pnpmWorkspaces + ; + pnpm = pkgs.pnpm_10; + fetcherVersion = 3; + hash = "sha256-fY3hrCkr/soJk1gp39/jec8lT2ZJI27xRBCZi006oWA="; + }; + } +) diff --git a/modules/capabilities/_theme.nix b/modules/capabilities/_theme.nix deleted file mode 100644 index 80a51c0..0000000 --- a/modules/capabilities/_theme.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ - cursor = { - name = "phinger-cursors-light"; - packageName = "phinger-cursors"; - size = 24; - }; - - kanagawa = { - displayName = "Kanagawa Wave"; - name = "kanagawa-wave"; - gtkThemeName = "Kanagawa-BL-LB"; - iconThemeName = "Kanagawa"; - owner = "Fausto-Korpsvart"; - repo = "Kanagawa-GKT-Theme"; - rev = "55ca4ba249eba21f861b9866b71ab41bb8930318"; - hash = "sha256-UdMoMx2DoovcxSp/zBZ3PRv/Qpj+prd0uPm1gmdak2E="; - version = "unstable-2025-10-23"; - - palette = { - background = "#1F1F28"; - foreground = "#DCD7BA"; - secondaryBackground = "#16161D"; - border = "#2A2A37"; - selectionBackground = "#2D4F67"; - selectionForeground = "#C8C093"; - url = "#72A7BC"; - cursor = "#C8C093"; - muted = "#727169"; - - accents = { - blue = "#7E9CD8"; - green = "#98BB6C"; - magenta = "#D27E99"; - orange = "#FFA066"; - purple = "#957FB8"; - red = "#E82424"; - yellow = "#E6C384"; - cyan = "#7AA89F"; - }; - - niri.border = { - active = "#7E9CD8"; - inactive = "#54546D"; - urgent = "#E82424"; - }; - - terminal = { - color0 = "#16161D"; - color1 = "#C34043"; - color2 = "#76946A"; - color3 = "#C0A36E"; - color4 = "#7E9CD8"; - color5 = "#957FB8"; - color6 = "#6A9589"; - color7 = "#C8C093"; - color8 = "#727169"; - color9 = "#E82424"; - color10 = "#98BB6C"; - color11 = "#E6C384"; - color12 = "#7FB4CA"; - color13 = "#938AA9"; - color14 = "#7AA89F"; - color15 = "#DCD7BA"; - color16 = "#FFA066"; - color17 = "#FF5D62"; - }; - }; - }; -} diff --git a/modules/capabilities/ai.nix b/modules/capabilities/ai.nix index 3b419e1..35a14b6 100644 --- a/modules/capabilities/ai.nix +++ b/modules/capabilities/ai.nix @@ -27,6 +27,8 @@ in flake.modules.homeManager.ai = { pkgs, ... }: { + imports = [ hmModules.podman ]; + services.podman = { volumes = { grounded-docs-config = { }; diff --git a/modules/capabilities/desktop-defaults.nix b/modules/capabilities/desktop-defaults.nix index c173588..a924c27 100644 --- a/modules/capabilities/desktop-defaults.nix +++ b/modules/capabilities/desktop-defaults.nix @@ -1,66 +1,72 @@ -{ config, ... }: -let - homeModules = config.flake.modules.homeManager; -in +{ ... }: { - flake.modules.homeManager.browser-vivaldi = - { pkgs, ... }: + flake.modules.homeManager.desktop-commands = + { lib, ... }: { - home.packages = [ pkgs.vivaldi ]; + options.desktop = { + commands = { + browser = lib.mkOption { + type = lib.types.nonEmptyListOf lib.types.nonEmptyStr; + }; + launcher = lib.mkOption { + type = lib.types.nonEmptyListOf lib.types.nonEmptyStr; + }; + terminal = lib.mkOption { + type = lib.types.nonEmptyListOf lib.types.nonEmptyStr; + }; + }; + autostart = lib.mkOption { + type = lib.types.listOf (lib.types.nonEmptyListOf lib.types.nonEmptyStr); + default = [ ]; + }; + }; }; - flake.modules.homeManager.primary-browser-vivaldi = + flake.modules.homeManager.vivaldi = { lib, pkgs, ... }: let - browser = pkgs.vivaldi; - browserCommand = lib.getExe browser; + command = lib.getExe pkgs.vivaldi; in { - imports = [ homeModules.browser-vivaldi ]; - - facts.desktop.browserCommand = browserCommand; - home.sessionVariables.BROWSER = browserCommand; - xdg.mimeApps.defaultApplicationPackages = [ browser ]; + desktop.commands.browser = [ command ]; + home = { + packages = [ pkgs.vivaldi ]; + sessionVariables.BROWSER = command; + }; + xdg.mimeApps.defaultApplicationPackages = [ pkgs.vivaldi ]; }; - flake.modules.homeManager.file-manager-nautilus = - { pkgs, ... }: + flake.modules.homeManager.nautilus = + { config, pkgs, ... }: { home.packages = [ pkgs.nautilus ]; - }; - - flake.modules.homeManager.primary-file-manager-nautilus = - { pkgs, ... }: - { - imports = [ homeModules.file-manager-nautilus ]; - + gtk.gtk3.bookmarks = [ + "sftp://${config.facts.topology.server.sshAlias} Orion VPS" + ]; xdg.mimeApps.defaultApplicationPackages = [ pkgs.nautilus ]; }; - flake.modules.homeManager.image-viewer-imv = { - programs.imv.enable = true; - }; - - flake.modules.homeManager.default-image-viewer-imv = + flake.modules.homeManager.imv = { pkgs, ... }: { - imports = [ homeModules.image-viewer-imv ]; - + programs.imv.enable = true; xdg.mimeApps.defaultApplicationPackages = [ pkgs.imv ]; }; - flake.modules.homeManager.document-viewer-sioyek = { - programs.sioyek.enable = true; - }; - - flake.modules.homeManager.default-document-viewer-sioyek = + flake.modules.homeManager.sioyek = { pkgs, ... }: { - imports = [ homeModules.document-viewer-sioyek ]; - + programs.sioyek.enable = true; xdg.mimeApps.defaultApplicationPackages = [ pkgs.sioyek ]; }; + flake.modules.homeManager.discord = { + programs.discord = { + enable = true; + settings.SKIP_HOST_UPDATE = true; + }; + }; + flake.modules.homeManager.workstation-apps = { pkgs, ... }: { @@ -110,9 +116,7 @@ in templates = "${localDir}/templates"; }; - mimeApps = { - enable = true; - }; + mimeApps.enable = true; }; }; } diff --git a/modules/capabilities/dev-tools.nix b/modules/capabilities/dev-tools.nix index eec05ae..f388998 100644 --- a/modules/capabilities/dev-tools.nix +++ b/modules/capabilities/dev-tools.nix @@ -46,8 +46,4 @@ }; }; }; - flake.modules.nixos.openvpn = { - programs.openvpn3.enable = true; - services.resolved.enable = true; - }; } diff --git a/modules/capabilities/git.nix b/modules/capabilities/git.nix index 5666c73..f395d9f 100644 --- a/modules/capabilities/git.nix +++ b/modules/capabilities/git.nix @@ -18,7 +18,8 @@ in email = account.emails.${scope}.address; key = machine.sshKeys.${scope} or null; hasSigningKey = key != null; - privateKeyPath = key.privateKeyPath or "~/.ssh/id_${scope}"; + privateKeyPath = + if hasSigningKey && key.privateKeyPath != null then key.privateKeyPath else "~/.ssh/id_${scope}"; in { allowedSigners = lib.optional hasSigningKey "${email} ${key.publicKey}"; diff --git a/modules/capabilities/helix.nix b/modules/capabilities/helix.nix index 21bfcb3..887f961 100644 --- a/modules/capabilities/helix.nix +++ b/modules/capabilities/helix.nix @@ -1,6 +1,9 @@ -{ inputs, ... }: +{ config, inputs, ... }: +let + homeModules = config.flake.modules.homeManager; +in { - flake.modules.nixos.helix = { + flake.modules.nixos.helix-cache = { nix.settings = { extra-substituters = [ "https://helix.cachix.org" ]; extra-trusted-public-keys = [ @@ -12,30 +15,11 @@ flake.modules.homeManager.helix = { pkgs, ... }: let - svelteLanguageServer = pkgs.svelte-language-server.overrideAttrs ( - finalAttrs: previousAttrs: { - version = "0.18.3"; - - src = pkgs.fetchFromGitHub { - owner = "sveltejs"; - repo = "language-tools"; - tag = "svelte-language-server@${finalAttrs.version}"; - hash = "sha256-FTOkJPXbsG6R53yr4n0/IR2lzFCovrdV0+epOi07lBQ="; - }; - - pnpmDeps = pkgs.fetchPnpmDeps { - inherit (finalAttrs) - pname - version - src - pnpmWorkspaces - ; - pnpm = pkgs.pnpm_10; - fetcherVersion = 3; - hash = "sha256-fY3hrCkr/soJk1gp39/jec8lT2ZJI27xRBCZi006oWA="; - }; - + svelteLanguageServer = (import ./_svelte-language-server.nix { inherit pkgs; }).overrideAttrs ( + _: previousAttrs: { postInstall = (previousAttrs.postInstall or "") + '' + # @vscode/emmet-helper only enables JSX expansion for JSX syntax; + # Helix's Svelte HTML regions also need it for HTML syntax. substituteInPlace \ "$out/lib/node_modules/svelte-language-server/packages/language-server/node_modules/@vscode/emmet-helper/lib/cjs/emmetHelper.js" \ --replace-fail \ @@ -48,7 +32,6 @@ { programs.helix = { enable = true; - defaultEditor = true; package = inputs.helix.packages.${pkgs.stdenv.hostPlatform.system}.default; extraPackages = with pkgs; [ vtsls @@ -179,4 +162,9 @@ }; }; }; + + flake.modules.homeManager.primary-editor-helix = { + imports = [ homeModules.helix ]; + programs.helix.defaultEditor = true; + }; } diff --git a/modules/capabilities/limine.nix b/modules/capabilities/limine.nix index 4bbd700..4d55e55 100644 --- a/modules/capabilities/limine.nix +++ b/modules/capabilities/limine.nix @@ -1,6 +1,6 @@ { config, lib, ... }: let - palette = config.facts.theme.kanagawa.palette; + palette = (import ./_kanagawa.nix).palette; hex = lib.removePrefix "#"; terminalPalette = palette.terminal; mkPalette = colors: lib.concatStringsSep ";" (map hex colors); @@ -9,11 +9,11 @@ in flake.modules.nixos.limine = { config, lib, ... }: let - displayValues = builtins.attrValues (config.facts.machine.displays or { }); - primaryDisplays = lib.filter (display: display.primary or false) displayValues; + displayValues = builtins.attrValues config.facts.machine.displays; + primaryDisplays = lib.filter (display: display.primary) displayValues; primaryDisplay = if primaryDisplays == [ ] then null else builtins.head primaryDisplays; interfaceResolution = - if primaryDisplay != null && primaryDisplay ? width && primaryDisplay ? height then + if primaryDisplay != null && primaryDisplay.width != null then "${toString primaryDisplay.width}x${toString primaryDisplay.height}" else null; @@ -24,7 +24,6 @@ in limine = { enable = true; maxGenerations = 10; - resolution = "2560x1440"; style = { backdrop = hex palette.secondaryBackground; @@ -69,6 +68,9 @@ in resolution = interfaceResolution; }; }; + } + // lib.optionalAttrs (interfaceResolution != null) { + resolution = interfaceResolution; }; }; }; diff --git a/modules/capabilities/locale-nl.nix b/modules/capabilities/locale.nix similarity index 92% rename from modules/capabilities/locale-nl.nix rename to modules/capabilities/locale.nix index 47ab15c..b3b4e26 100644 --- a/modules/capabilities/locale-nl.nix +++ b/modules/capabilities/locale.nix @@ -1,6 +1,5 @@ -{ ... }: { - flake.modules.nixos.locale-nl = { + flake.modules.nixos.locale = { time.timeZone = "Europe/Amsterdam"; i18n.defaultLocale = "en_US.UTF-8"; diff --git a/modules/capabilities/neovim/default.nix b/modules/capabilities/neovim/default.nix index 0621e9c..59f1300 100644 --- a/modules/capabilities/neovim/default.nix +++ b/modules/capabilities/neovim/default.nix @@ -1,15 +1,9 @@ { config, ... }: let account = config.facts.account; - theme = config.facts.theme.kanagawa; + homeModules = config.flake.modules.homeManager; in { - flake.modules.homeManager.default-editor-neovim = - { pkgs, ... }: - { - xdg.mimeApps.defaultApplicationPackages = [ pkgs.neovim ]; - }; - flake.modules.homeManager.neovim = { pkgs, @@ -20,30 +14,7 @@ in }: let nvimTreesitter = pkgs.vimPlugins.nvim-treesitter; - svelteLanguageServer = pkgs.svelte-language-server.overrideAttrs ( - finalAttrs: _: { - version = "0.18.3"; - - src = pkgs.fetchFromGitHub { - owner = "sveltejs"; - repo = "language-tools"; - tag = "svelte-language-server@${finalAttrs.version}"; - hash = "sha256-FTOkJPXbsG6R53yr4n0/IR2lzFCovrdV0+epOi07lBQ="; - }; - - pnpmDeps = pkgs.fetchPnpmDeps { - inherit (finalAttrs) - pname - version - src - pnpmWorkspaces - ; - pnpm = pkgs.pnpm_10; - fetcherVersion = 3; - hash = "sha256-fY3hrCkr/soJk1gp39/jec8lT2ZJI27xRBCZi006oWA="; - }; - } - ); + svelteLanguageServer = import ../_svelte-language-server.nix { inherit pkgs; }; svelteGrammar = nvimTreesitter.builtGrammars.svelte.overrideAttrs (_: { version = "0.0.0+rev=c2457b9"; src = pkgs.fetchFromGitHub { @@ -61,11 +32,6 @@ in ); in { - home.sessionVariables = { - EDITOR = "nvim"; - VISUAL = "nvim"; - }; - imports = [ (inputs.nix-wrapper-modules.lib.getInstallModule { name = "neovim"; @@ -195,7 +161,7 @@ in }; themeSetup = import ./_kanagawa-theme.nix { - themeName = theme.name; + themeName = "kanagawa-wave"; }; typstPreviewDependencies = { @@ -209,4 +175,16 @@ in binName = "nvim"; }; }; + + flake.modules.homeManager.primary-editor-neovim = + { pkgs, ... }: + { + imports = [ homeModules.neovim ]; + + home.sessionVariables = { + EDITOR = "nvim"; + VISUAL = "nvim"; + }; + xdg.mimeApps.defaultApplicationPackages = [ pkgs.neovim ]; + }; } diff --git a/modules/capabilities/networking.nix b/modules/capabilities/networking.nix index aeb8120..9a51445 100644 --- a/modules/capabilities/networking.nix +++ b/modules/capabilities/networking.nix @@ -8,13 +8,12 @@ in }; flake.modules.nixos.network-manager = { - networking = { - networkmanager.enable = true; - firewall.allowedTCPPorts = [ - 5173 - 5174 - ]; - }; + networking.networkmanager.enable = true; + }; + + flake.modules.nixos.openvpn = { + programs.openvpn3.enable = true; + services.resolved.enable = true; }; flake.modules.nixos.server-firewall = diff --git a/modules/capabilities/niri/_bindings.nix b/modules/capabilities/niri/_bindings.nix index 9a968bc..43e8303 100644 --- a/modules/capabilities/niri/_bindings.nix +++ b/modules/capabilities/niri/_bindings.nix @@ -1,29 +1,24 @@ { - browserCommand, - launcherCommand, + browser, + launcher, shortcutCommands, - terminalCommand, + terminal, }: { # Application and utility launchers "Mod+Return" = { - action.spawn = terminalCommand; + action.spawn = terminal; hotkey-overlay.title = "Terminal"; }; "Mod+B" = { - action.spawn = browserCommand; + action.spawn = browser; hotkey-overlay.title = "Browser"; }; "Mod+Space" = { repeat = false; - action.spawn = launcherCommand; + action.spawn = launcher; hotkey-overlay.title = "App Launcher"; }; - "Mod+E" = { - repeat = false; - action.spawn = shortcutCommands.neovimProjects; - hotkey-overlay.title = "Neovim Projects"; - }; "Mod+Ctrl+Return" = { repeat = false; action.spawn = shortcutCommands.nixosTerminal; diff --git a/modules/capabilities/niri/_shortcuts.nix b/modules/capabilities/niri/_shortcuts.nix index 4ae34c6..b736f5e 100644 --- a/modules/capabilities/niri/_shortcuts.nix +++ b/modules/capabilities/niri/_shortcuts.nix @@ -1,11 +1,10 @@ { config, - facts, lib, pkgs, }: let - nixosConfigDir = facts.account.nixosConfigurationPath; + nixosConfigDir = config.facts.account.nixosConfigurationPath; mkTerminalScript = { name, @@ -28,7 +27,7 @@ let text = lib.concatStringsSep "\n" [ "# shellcheck disable=SC2016" "cd ${lib.escapeShellArg workdir}" - "exec ${lib.escapeShellArg config.facts.desktop.terminalCommand} ${argString}" + "exec ${lib.escapeShellArgs config.desktop.commands.terminal} ${argString}" ]; }; in @@ -83,13 +82,6 @@ rec { ''; }; - neovimProjects = mkTerminalScript { - name = "niri-shortcut-neovim-projects"; - command = '' - nvim -c 'Telescope projects' - ''; - }; - pickColor = pkgs.writeShellApplication { name = "niri-shortcut-pick-color"; runtimeInputs = [ diff --git a/modules/capabilities/niri/default.nix b/modules/capabilities/niri/default.nix index d98a7e4..a978c72 100644 --- a/modules/capabilities/niri/default.nix +++ b/modules/capabilities/niri/default.nix @@ -4,7 +4,7 @@ ... }: let - facts = config.facts; + kanagawa = import ../_kanagawa.nix; hmModules = config.flake.modules.homeManager; in { @@ -41,11 +41,10 @@ in ... }: let - borderPalette = facts.theme.kanagawa.palette.niri.border; + palette = kanagawa.palette; shortcuts = import ./_shortcuts.nix { inherit config - facts lib pkgs ; @@ -60,6 +59,7 @@ in [ playerctl brightnessctl + wireplumber xwayland-satellite ] ++ lib.attrValues shortcuts.scripts; @@ -72,17 +72,16 @@ in _: display: { position = { - x = display.x or 0; - y = display.y or 0; + inherit (display) x y; }; } - // lib.optionalAttrs (display.primary or false) { + // lib.optionalAttrs display.primary { "focus-at-startup" = true; } - // lib.optionalAttrs (display ? scale) { + // lib.optionalAttrs (display.scale != null) { inherit (display) scale; } - // lib.optionalAttrs (display ? width && display ? height && display ? refresh) { + // lib.optionalAttrs (display.width != null) { mode = { inherit (display) height @@ -95,16 +94,16 @@ in environment.DISPLAY = ":0"; spawn-at-startup = [ - { command = [ "xwayland-satellite" ]; } - { command = [ "noctalia" ]; } - ]; + { command = [ (lib.getExe pkgs.xwayland-satellite) ]; } + ] + ++ map (command: { inherit command; }) config.desktop.autostart; prefer-no-csd = true; hotkey-overlay.skip-at-startup = true; screenshot-path = "${config.xdg.userDirs.pictures}/screenshots/%Y-%m-%dT%H:%M:%S.png"; animations.slowdown = 0.6; - cursor = { + cursor = lib.mkIf config.home.pointerCursor.enable { inherit (config.home.pointerCursor) size; theme = config.home.pointerCursor.name; hide-after-inactive-ms = 3000; @@ -120,9 +119,9 @@ in border = { enable = true; width = 3; - active.color = borderPalette.active; - inactive.color = borderPalette.inactive; - urgent.color = borderPalette.urgent; + active.color = palette.accents.blue; + inactive.color = palette.subtleBorder; + urgent.color = palette.accents.red; }; }; @@ -157,9 +156,11 @@ in }; binds = import ./_bindings.nix { - browserCommand = config.facts.desktop.browserCommand; - launcherCommand = config.facts.desktop.launcherCommand; - terminalCommand = config.facts.desktop.terminalCommand; + inherit (config.desktop.commands) + browser + launcher + terminal + ; shortcutCommands = shortcuts.commands; }; }; diff --git a/modules/capabilities/noctalia.nix b/modules/capabilities/noctalia.nix index 332f55b..21a8f1c 100644 --- a/modules/capabilities/noctalia.nix +++ b/modules/capabilities/noctalia.nix @@ -9,27 +9,12 @@ let homeDir = config.home.homeDirectory; wallpaper = "${homeDir}/media/images/wallpapers/green-leaves.png"; - loginBox = output: { - box_height = 70.0; - box_width = 400.0; - cx = 1280.0; - cy = 1317.0; - inherit output; - rotation = 0.0; - type = "login_box"; - settings = { - background_color = "surface_variant"; - background_opacity = 0.88; - background_radius = 12.0; - input_opacity = 1.0; - input_radius = 6.0; - show_login_button = true; - }; - }; in { imports = [ inputs.noctalia.homeModules.default ]; + desktop.autostart = [ [ (lib.getExe config.programs.noctalia.package) ] ]; + programs.noctalia = { enable = true; settings = { @@ -49,7 +34,7 @@ "bluetooth" "volume" ] - ++ lib.optionals config.facts.machine.portable [ + ++ lib.optionals (config.facts.machine.name == "zenith") [ "network" "battery" ] @@ -70,7 +55,7 @@ account.radicale = { name = "Personal"; provider = "custom"; - server_url = config.facts.services.radicale.url; + server_url = "${config.facts.services.radicale.origin}/"; type = "caldav"; username = config.facts.account.name; }; @@ -97,23 +82,7 @@ tint_intensity = 0.5; }; - lockscreen_widgets = { - enabled = true; - schema_version = 2; - widget_order = [ - "lockscreen-login-box@DP-2" - "lockscreen-login-box@DP-3" - ]; - grid = { - cell_size = 16; - major_interval = 4; - visible = true; - }; - widget = { - "lockscreen-login-box@DP-2" = loginBox "DP-2"; - "lockscreen-login-box@DP-3" = loginBox "DP-3"; - }; - }; + lockscreen_widgets.enabled = true; nightlight = { enabled = true; @@ -168,10 +137,6 @@ directory = "${homeDir}/media/images/wallpapers"; default.path = wallpaper; last.path = wallpaper; - monitors = { - DP-2.path = wallpaper; - DP-3.path = wallpaper; - }; }; weather.refresh_minutes = 15; diff --git a/modules/capabilities/passwords.nix b/modules/capabilities/passwords.nix index bd1a6e3..cd30533 100644 --- a/modules/capabilities/passwords.nix +++ b/modules/capabilities/passwords.nix @@ -19,8 +19,8 @@ in programs.rbw = { enable = true; settings = { - base_url = facts.services.vaultwarden.url; - email = account.primaryEmail.address; + base_url = facts.services.vaultwarden.origin; + email = account.emails.${account.primaryEmail}.address; pinentry = pinentryPackage; }; }; diff --git a/modules/capabilities/pim.nix b/modules/capabilities/pim.nix index 844f111..ae890c3 100644 --- a/modules/capabilities/pim.nix +++ b/modules/capabilities/pim.nix @@ -5,6 +5,7 @@ let facts = config.facts; account = facts.account; + homeModules = config.flake.modules.homeManager; in { flake.modules.homeManager.email = @@ -17,12 +18,11 @@ in mkOffice365Account = { address, - primary ? false, ... }: { enable = true; - inherit address primary; + inherit address; realName = account.realName; userName = address; thunderbird = { @@ -37,12 +37,11 @@ in mkMxrouteAccount = { address, - primary ? false, ... }: { enable = true; - inherit address primary; + inherit address; realName = account.realName; userName = address; thunderbird.enable = true; @@ -60,13 +59,11 @@ in }; }; mkEmailAccount = - email: - if email.type == "office365" then - mkOffice365Account email - else if email.type == "mxrouting" then - mkMxrouteAccount email - else - throw "Unsupported email type `${email.type}` for ${config.home.username}"; + name: email: + (if email.type == "office365" then mkOffice365Account email else mkMxrouteAccount email) + // { + primary = name == account.primaryEmail; + }; in { programs.thunderbird = { @@ -87,7 +84,7 @@ in }; }; - accounts.email.accounts = lib.mapAttrs (_: mkEmailAccount) account.emails; + accounts.email.accounts = lib.mapAttrs mkEmailAccount account.emails; }; flake.modules.homeManager.calendar-tasks = @@ -100,6 +97,8 @@ in calendarsPath = "${config.xdg.dataHome}/calendars"; in { + imports = [ homeModules.sops ]; + programs.pimsync.enable = true; services.pimsync.enable = true; @@ -138,7 +137,7 @@ in }; remote = { - url = facts.services.radicale.url; + url = "${facts.services.radicale.origin}/"; type = "caldav"; userName = config.home.username; passwordCommand = [ diff --git a/modules/capabilities/qbittorrent.nix b/modules/capabilities/qbittorrent.nix index 03b6029..5748704 100644 --- a/modules/capabilities/qbittorrent.nix +++ b/modules/capabilities/qbittorrent.nix @@ -1,11 +1,7 @@ -{ config, ... }: -let - account = config.facts.account; -in { - flake.modules.nixos.qbittorrent = + flake.modules.homeManager.qbittorrent = { pkgs, ... }: { - home-manager.users.${account.name}.home.packages = [ pkgs.qbittorrent ]; + home.packages = [ pkgs.qbittorrent ]; }; } diff --git a/modules/capabilities/sddm.nix b/modules/capabilities/sddm.nix index 5be784d..9f29665 100644 --- a/modules/capabilities/sddm.nix +++ b/modules/capabilities/sddm.nix @@ -16,6 +16,10 @@ extraPackages = with pkgs; [ kdePackages.qtmultimedia ]; + settings.Theme = { + CursorTheme = "phinger-cursors-light"; + CursorSize = 24; + }; }; }; } diff --git a/modules/capabilities/services/actual.nix b/modules/capabilities/services/actual.nix index 54cfd1d..b8390ab 100644 --- a/modules/capabilities/services/actual.nix +++ b/modules/capabilities/services/actual.nix @@ -1,19 +1,21 @@ { config, ... }: let service = config.facts.services.actual; + nixosModules = config.flake.modules.nixos; in { flake.modules.nixos.actual = { + imports = [ nixosModules.caddy ]; + services.actual = { enable = true; openFirewall = false; settings = { - inherit (service) port; - hostname = service.host; + hostname = "127.0.0.1"; + port = 3000; }; }; - services.caddy.virtualHosts.${service.domain}.extraConfig = - "reverse_proxy :${toString service.port}"; + services.caddy.virtualHosts.${service.domain}.extraConfig = "reverse_proxy 127.0.0.1:3000"; }; } diff --git a/modules/capabilities/services/caddy.nix b/modules/capabilities/services/caddy.nix index 7ceaabf..facef6e 100644 --- a/modules/capabilities/services/caddy.nix +++ b/modules/capabilities/services/caddy.nix @@ -6,7 +6,7 @@ in flake.modules.nixos.caddy = { services.caddy = { enable = true; - email = facts.account.primaryEmail.address; + email = facts.account.emails.${facts.account.primaryEmail}.address; openFirewall = true; }; }; diff --git a/modules/capabilities/services/gitea.nix b/modules/capabilities/services/gitea.nix index 0bd5a5a..f299cb9 100644 --- a/modules/capabilities/services/gitea.nix +++ b/modules/capabilities/services/gitea.nix @@ -1,18 +1,24 @@ { config, ... }: let service = config.facts.services.gitea; + nixosModules = config.flake.modules.nixos; in { flake.modules.nixos.gitea = { + imports = [ + nixosModules.caddy + nixosModules.openssh + ]; + services.gitea = { enable = true; settings = { server = { DOMAIN = service.domain; - ROOT_URL = service.url; - HTTP_PORT = service.port; - HTTP_ADDR = service.host; + ROOT_URL = "${service.origin}/"; + HTTP_PORT = 3001; + HTTP_ADDR = "127.0.0.1"; START_SSH_SERVER = false; SSH_PORT = 22; @@ -24,7 +30,6 @@ in services.openssh.settings.AllowUsers = [ "gitea" ]; - services.caddy.virtualHosts.${service.domain}.extraConfig = - "reverse_proxy :${toString service.port}"; + services.caddy.virtualHosts.${service.domain}.extraConfig = "reverse_proxy 127.0.0.1:3001"; }; } diff --git a/modules/capabilities/services/openssh.nix b/modules/capabilities/services/openssh.nix index e19b583..f6343eb 100644 --- a/modules/capabilities/services/openssh.nix +++ b/modules/capabilities/services/openssh.nix @@ -3,8 +3,8 @@ let account = config.facts.account; personalPublicKeys = machines: - map (machine: (machine.sshKeys or { }).personal.publicKey) ( - lib.filter (machine: (machine.sshKeys or { }) ? personal) (builtins.attrValues machines) + map (machine: machine.sshKeys.personal.publicKey) ( + lib.filter (machine: machine.sshKeys ? personal) (builtins.attrValues machines) ); in { diff --git a/modules/capabilities/services/radicale.nix b/modules/capabilities/services/radicale.nix index 573a3cf..6a46047 100644 --- a/modules/capabilities/services/radicale.nix +++ b/modules/capabilities/services/radicale.nix @@ -1,13 +1,16 @@ { config, ... }: let service = config.facts.services.radicale; + nixosModules = config.flake.modules.nixos; in { flake.modules.nixos.radicale = { + imports = [ nixosModules.caddy ]; + services.radicale = { enable = true; settings = { - server.hosts = [ "${service.host}:${toString service.port}" ]; + server.hosts = [ "127.0.0.1:5232" ]; auth = { type = "htpasswd"; @@ -20,7 +23,7 @@ in }; services.caddy.virtualHosts.${service.domain}.extraConfig = '' - reverse_proxy :${toString service.port} { + reverse_proxy 127.0.0.1:5232 { header_up X-Script-Name / header_up X-Forwarded-For {remote} header_up X-Remote-User {http.auth.user.id} diff --git a/modules/capabilities/services/vaultwarden.nix b/modules/capabilities/services/vaultwarden.nix index e6e143f..b4245e8 100644 --- a/modules/capabilities/services/vaultwarden.nix +++ b/modules/capabilities/services/vaultwarden.nix @@ -1,21 +1,24 @@ { config, ... }: let service = config.facts.services.vaultwarden; + nixosModules = config.flake.modules.nixos; in { flake.modules.nixos.vaultwarden = { + imports = [ nixosModules.caddy ]; + services.vaultwarden = { enable = true; backupDir = "/var/backup/vaultwarden"; config = { - DOMAIN = service.url; + DOMAIN = service.origin; SIGNUPS_ALLOWED = false; - ROCKET_PORT = service.port; + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 8100; ROCKET_LOG = "critical"; }; }; - services.caddy.virtualHosts.${service.domain}.extraConfig = - "reverse_proxy :${toString service.port}"; + services.caddy.virtualHosts.${service.domain}.extraConfig = "reverse_proxy 127.0.0.1:8100"; }; } diff --git a/modules/capabilities/services/vps-insights.nix b/modules/capabilities/services/vps-insights.nix index 2724b85..9440516 100644 --- a/modules/capabilities/services/vps-insights.nix +++ b/modules/capabilities/services/vps-insights.nix @@ -1,13 +1,20 @@ { ... }: { flake.modules.nixos.vps-insights = - { config, pkgs, ... }: + { + config, + lib, + pkgs, + ... + }: let localAddress = "127.0.0.1"; grafanaDataDir = config.services.grafana.dataDir; lokiDataDir = config.services.loki.dataDir; lokiUrl = "http://${localAddress}:3100"; prometheusUrl = "http://${localAddress}:9090"; + hasCaddy = config.services.caddy.enable; + hasOpenSSH = config.services.openssh.enable; in { environment = { @@ -64,21 +71,17 @@ # Detect and block common attacks against SSH and Caddy. crowdsec = { enable = true; - hub.collections = [ - "crowdsecurity/linux" - "crowdsecurity/caddy" - ]; - localConfig.acquisitions = [ - { + hub.collections = [ "crowdsecurity/linux" ] ++ lib.optional hasCaddy "crowdsecurity/caddy"; + localConfig.acquisitions = + lib.optional hasOpenSSH { source = "journalctl"; journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; labels.type = "syslog"; } - { + ++ lib.optional hasCaddy { filenames = [ "/var/log/caddy/*.log" ]; labels.type = "caddy"; - } - ]; + }; }; crowdsec-firewall-bouncer = { @@ -86,11 +89,15 @@ registerBouncer.bouncerName = "${config.networking.hostName}-firewall-bouncer"; }; - # Grafana defaults to 127.0.0.1:3000; add secrets and datasources only. + # Keep Grafana local and separate from Actual's port. grafana = { enable = true; settings = { analytics.reporting_enabled = false; + server = { + http_addr = localAddress; + http_port = 3002; + }; security = { admin_password = "$__file{${grafanaDataDir}/admin-password}"; secret_key = "$__file{${grafanaDataDir}/secret-key}"; diff --git a/modules/capabilities/shell.nix b/modules/capabilities/shell.nix index 23bff8c..71c37f5 100644 --- a/modules/capabilities/shell.nix +++ b/modules/capabilities/shell.nix @@ -7,6 +7,10 @@ pkgs, ... }: + let + gardenctl = "${config.home.homeDirectory}/.garden/gardenctl"; + uuidgen = lib.getExe' pkgs.util-linux "uuidgen"; + in { home.sessionVariables = { STARSHIP_CACHE = "${config.xdg.cacheHome}/starship"; @@ -62,16 +66,12 @@ ''; initContent = '' - source <(/home/kiri/.garden/gardenctl completion zsh) - - - [ -n "$GCTL_SESSION_ID" ] || [ -n "$TERM_SESSION_ID" ] || export GCTL_SESSION_ID=$(uuidgen) - + source <(${gardenctl} completion zsh) if [ -z "$GCTL_SESSION_ID" ] && [ -z "$TERM_SESSION_ID" ]; then - export GCTL_SESSION_ID=$(uuidgen) + export GCTL_SESSION_ID=$(${uuidgen}) fi - eval $(/home/kiri/.garden/gardenctl kubectl-env zsh) + eval $(${gardenctl} kubectl-env zsh) bindkey -v diff --git a/modules/capabilities/ssh.nix b/modules/capabilities/ssh.nix index ef6f9c9..e3c6bb1 100644 --- a/modules/capabilities/ssh.nix +++ b/modules/capabilities/ssh.nix @@ -1,19 +1,28 @@ +{ config, ... }: +let + homeModules = config.flake.modules.homeManager; +in { flake.modules.homeManager.ssh-client = { config, ... }: + let + server = config.facts.topology.server; + in { + imports = [ homeModules.sops ]; + programs.ssh = { enable = true; enableDefaultConfig = false; includes = [ - config.sops.templates."ssh-config-orion".path + config.sops.templates."ssh-config-${server.machine}".path ]; }; - sops.secrets."orion-ip" = { }; - sops.templates."ssh-config-orion".content = '' - Host orion - HostName ${config.sops.placeholder."orion-ip"} + sops.secrets."${server.machine}-ip" = { }; + sops.templates."ssh-config-${server.machine}".content = '' + Host ${server.sshAlias} + HostName ${config.sops.placeholder."${server.machine}-ip"} ForwardAgent yes ''; }; diff --git a/modules/capabilities/syncthing.nix b/modules/capabilities/syncthing.nix index 785c30d..2f6c00e 100644 --- a/modules/capabilities/syncthing.nix +++ b/modules/capabilities/syncthing.nix @@ -14,20 +14,18 @@ let inherit name; id = machine.syncthingId; } - ) (lib.filterAttrs (_: machine: (machine.syncthingId or null) != null) config.facts.machines); + ) (lib.filterAttrs (_: machine: machine.syncthingId != null) config.facts.machines); - syncPhones = { - "pixel-10" = { - name = "pixel-10"; - id = "MTJHEHA-UMZDQZ7-BTMRRLQ-Y7BFPUJ-ZTY6LZX-PDXV3IS-XVJCU7B-EPETBQZ"; - }; - }; + syncExternalDevices = lib.mapAttrs (name: device: { + inherit name; + id = device.syncthingId; + }) (lib.filterAttrs (_: device: device.syncthingId != null) config.facts.externalDevices); - syncDevices = syncMachines // syncPhones; + syncDevices = syncMachines // syncExternalDevices; in { flake.modules.homeManager.syncthing = - { ... }: + { config, ... }: { services.syncthing = { enable = true; @@ -38,12 +36,16 @@ in settings = { folders = { sync = { - path = "~/sync"; + path = "${config.home.homeDirectory}/sync"; label = "sync"; devices = builtins.attrNames syncDevices; }; bruno = { - path = "~/dev/bruno"; + path = + if config.facts.machine.name == "orion" then + "${config.home.homeDirectory}/bruno" + else + "${config.xdg.userDirs.projects}/bruno"; label = "bruno"; devices = builtins.attrNames syncDevices; }; diff --git a/modules/capabilities/terminal.nix b/modules/capabilities/terminal.nix index 8705d78..12106d1 100644 --- a/modules/capabilities/terminal.nix +++ b/modules/capabilities/terminal.nix @@ -1,6 +1,7 @@ { lib, config, ... }: let - facts = config.facts; + kanagawa = import ./_kanagawa.nix; + homeModules = config.flake.modules.homeManager; kittySingleInstance = pkgs: @@ -25,13 +26,12 @@ in ... }: let - palette = facts.theme.kanagawa.palette; + palette = kanagawa.palette; hex = lib.removePrefix "#"; in { programs.foot = { enable = true; - package = pkgs.foot; settings = { main = { font = "JetBrains Mono:style=Medium:size=11:fontfeatures=-liga:fontfeatures=-calt"; @@ -86,7 +86,7 @@ in flake.modules.homeManager.terminal-kitty = { pkgs, ... }: let - theme = facts.theme.kanagawa; + theme = kanagawa; palette = theme.palette; kitty = kittySingleInstance pkgs; in @@ -167,11 +167,11 @@ in }; flake.modules.homeManager.primary-terminal-foot = - { lib, pkgs, ... }: + { config, lib, ... }: { - imports = [ config.flake.modules.homeManager.terminal-foot ]; + imports = [ homeModules.terminal-foot ]; - facts.desktop.terminalCommand = lib.getExe pkgs.foot; + desktop.commands.terminal = [ (lib.getExe config.programs.foot.package) ]; xdg.terminal-exec = { enable = true; @@ -180,14 +180,11 @@ in }; flake.modules.homeManager.primary-terminal-kitty = - { lib, pkgs, ... }: - let - kitty = kittySingleInstance pkgs; - in + { config, lib, ... }: { - imports = [ config.flake.modules.homeManager.terminal-kitty ]; + imports = [ homeModules.terminal-kitty ]; - facts.desktop.terminalCommand = lib.getExe kitty; + desktop.commands.terminal = [ (lib.getExe config.programs.kitty.package) ]; xdg.terminal-exec = { enable = true; diff --git a/modules/capabilities/theme.nix b/modules/capabilities/theme.nix index 9d97599..2a8a76e 100644 --- a/modules/capabilities/theme.nix +++ b/modules/capabilities/theme.nix @@ -1,58 +1,36 @@ -{ - config, - ... -}: +{ config, ... }: let - facts = config.facts; hmModules = config.flake.modules.homeManager; - mkCursorTheme = - pkgs: - facts.theme.cursor - // { - package = pkgs.${facts.theme.cursor.packageName}; - }; + cursor = { + name = "phinger-cursors-light"; + packageName = "phinger-cursors"; + size = 24; + }; + mkCursor = pkgs: cursor // { package = pkgs.${cursor.packageName}; }; in { flake.modules.nixos.theme = - { - pkgs, - ... - }: + { pkgs, ... }: let - cursorTheme = mkCursorTheme pkgs; + cursorTheme = mkCursor pkgs; in { home-manager.sharedModules = [ hmModules.theme ]; - environment.systemPackages = [ cursorTheme.package ]; - - services.displayManager.sddm.settings = { - Theme = { - CursorTheme = cursorTheme.name; - CursorSize = cursorTheme.size; - }; - }; }; flake.modules.homeManager.theme = - { config, pkgs, ... }: + { pkgs, ... }: let - theme = facts.theme; - cursorTheme = mkCursorTheme pkgs; - - kanagawaThemeSrc = pkgs.fetchFromGitHub { - inherit (theme.kanagawa) - hash - owner - repo - rev - ; - }; - - kanagawaOverride = { - version = theme.kanagawa.version; - src = kanagawaThemeSrc; + cursorTheme = mkCursor pkgs; + version = "unstable-2025-10-23"; + src = pkgs.fetchFromGitHub { + owner = "Fausto-Korpsvart"; + repo = "Kanagawa-GKT-Theme"; + rev = "55ca4ba249eba21f861b9866b71ab41bb8930318"; + hash = "sha256-UdMoMx2DoovcxSp/zBZ3PRv/Qpj+prd0uPm1gmdak2E="; }; + override = { inherit src version; }; in { home.pointerCursor = { @@ -68,17 +46,14 @@ in gtk = { enable = true; - gtk3.bookmarks = [ - "sftp://orion Orion VPS" - ]; theme = { - name = theme.kanagawa.gtkThemeName; - package = pkgs.kanagawa-gtk-theme.overrideAttrs (_: kanagawaOverride); + name = "Kanagawa-BL-LB"; + package = pkgs.kanagawa-gtk-theme.overrideAttrs (_: override); }; gtk4.theme = null; iconTheme = { - name = theme.kanagawa.iconThemeName; - package = pkgs.kanagawa-icon-theme.overrideAttrs (_: kanagawaOverride); + name = "Kanagawa"; + package = pkgs.kanagawa-icon-theme.overrideAttrs (_: override); }; }; diff --git a/modules/capabilities/walker.nix b/modules/capabilities/walker.nix index 4fc967f..340203e 100644 --- a/modules/capabilities/walker.nix +++ b/modules/capabilities/walker.nix @@ -3,7 +3,9 @@ let homeModules = config.flake.modules.homeManager; in { - flake.modules.nixos.walker-cache = { + flake.modules.nixos.walker = { + home-manager.sharedModules = [ homeModules.walker ]; + nix.settings = { extra-substituters = [ "https://walker.cachix.org" @@ -16,14 +18,22 @@ in }; }; - flake.modules.homeManager.walker-base = - { - config, - ... - }: + flake.modules.homeManager.walker = + { lib, pkgs, ... }: + let + launcher = pkgs.writeShellApplication { + name = "walker-launcher"; + runtimeInputs = [ pkgs.libressl.nc ]; + text = '' + exec nc -U "$XDG_RUNTIME_DIR/walker/walker.sock" + ''; + }; + in { imports = [ inputs.walker.homeManagerModules.default ]; + desktop.commands.launcher = [ (lib.getExe launcher) ]; + programs.walker = { enable = true; runAsService = true; @@ -36,21 +46,4 @@ in ]; }; }; - - flake.modules.homeManager.primary-launcher-walker = - { - config, - lib, - pkgs, - ... - }: - { - imports = [ homeModules.walker-base ]; - - facts.desktop.launcherCommand = [ - (lib.getExe' pkgs.libressl.nc "nc") - "-U" - "/run/user/1000/walker/walker.sock" - ]; - }; } diff --git a/modules/capabilities/yookr-dev.nix b/modules/capabilities/yookr-dev.nix index e189347..4f97ed7 100644 --- a/modules/capabilities/yookr-dev.nix +++ b/modules/capabilities/yookr-dev.nix @@ -3,8 +3,13 @@ { config, ... }: { security.pki.certificateFiles = [ - ../hosts/zenith/mkcert-rootCA.pem - ../hosts/polaris/mkcert-rootCA.pem + ./yookr-dev/zenith-rootCA.pem + ./yookr-dev/polaris-rootCA.pem + ]; + + networking.firewall.allowedTCPPorts = [ + 5173 + 5174 ]; networking.extraHosts = '' diff --git a/modules/hosts/polaris/mkcert-rootCA.pem b/modules/capabilities/yookr-dev/polaris-rootCA.pem similarity index 100% rename from modules/hosts/polaris/mkcert-rootCA.pem rename to modules/capabilities/yookr-dev/polaris-rootCA.pem diff --git a/modules/hosts/zenith/mkcert-rootCA.pem b/modules/capabilities/yookr-dev/zenith-rootCA.pem similarity index 100% rename from modules/hosts/zenith/mkcert-rootCA.pem rename to modules/capabilities/yookr-dev/zenith-rootCA.pem diff --git a/modules/capabilities/hidraw-access.nix b/modules/capabilities/yunzi-b75-pro.nix similarity index 83% rename from modules/capabilities/hidraw-access.nix rename to modules/capabilities/yunzi-b75-pro.nix index e8f192b..0390ba9 100644 --- a/modules/capabilities/hidraw-access.nix +++ b/modules/capabilities/yunzi-b75-pro.nix @@ -1,5 +1,5 @@ { - flake.modules.nixos.hidraw-access = { + flake.modules.nixos.yunzi-b75-pro = { services.udev.extraRules = '' # ROYUAN YUNZII B75 PRO KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="3151", ATTRS{idProduct}=="4015", MODE="0660", GROUP="users" diff --git a/modules/facts.nix b/modules/facts.nix index c8c7489..a5e27c2 100644 --- a/modules/facts.nix +++ b/modules/facts.nix @@ -1,14 +1,193 @@ { lib, ... }: let - factsOption = lib.mkOption { - type = lib.types.submodule { - freeformType = lib.types.attrsOf lib.types.anything; + inherit (lib) mkOption types; + + emailType = types.submodule { + options = { + address = mkOption { type = types.nonEmptyStr; }; + type = mkOption { + type = types.enum [ + "mxrouting" + "office365" + ]; + }; }; - default = { }; }; + + accountType = types.submodule { + options = { + name = mkOption { type = types.nonEmptyStr; }; + realName = mkOption { type = types.nonEmptyStr; }; + homeDirectory = mkOption { type = types.nonEmptyStr; }; + nixosConfigurationPath = mkOption { type = types.nonEmptyStr; }; + emails = mkOption { type = types.attrsOf emailType; }; + primaryEmail = mkOption { type = types.nonEmptyStr; }; + }; + }; + + accountOption = mkOption { + type = accountType; + apply = + account: + assert lib.assertMsg (builtins.hasAttr account.primaryEmail account.emails) + "facts.account.primaryEmail must name an entry in facts.account.emails"; + account; + }; + + sshKeyType = types.submodule { + options = { + publicKey = mkOption { type = types.nonEmptyStr; }; + privateKeyPath = mkOption { + type = types.nullOr types.nonEmptyStr; + default = null; + }; + }; + }; + + displayType = types.submodule { + options = { + x = mkOption { + type = types.int; + default = 0; + }; + y = mkOption { + type = types.int; + default = 0; + }; + primary = mkOption { + type = types.bool; + default = false; + }; + scale = mkOption { + type = types.nullOr types.number; + default = null; + }; + width = mkOption { + type = types.nullOr types.ints.positive; + default = null; + }; + height = mkOption { + type = types.nullOr types.ints.positive; + default = null; + }; + refresh = mkOption { + type = types.nullOr types.number; + default = null; + }; + }; + }; + + displaysOption = mkOption { + type = types.attrsOf displayType; + default = { }; + apply = + displays: + assert lib.assertMsg (lib.all ( + display: + let + values = [ + display.width + display.height + display.refresh + ]; + in + lib.all (value: value == null) values || lib.all (value: value != null) values + ) (builtins.attrValues displays)) "display width, height, and refresh must be supplied together"; + displays; + }; + + machineType = + { + withName ? false, + }: + types.submodule ( + { config, ... }: + { + options = { + system = mkOption { type = types.nonEmptyStr; }; + stateVersion = mkOption { type = types.nonEmptyStr; }; + hmStateVersion = mkOption { + type = types.nonEmptyStr; + default = config.stateVersion; + }; + syncthingId = mkOption { + type = types.nullOr types.nonEmptyStr; + default = null; + }; + sshKeys = mkOption { + type = types.attrsOf sshKeyType; + default = { }; + }; + displays = displaysOption; + } + // lib.optionalAttrs withName { + name = mkOption { type = types.nonEmptyStr; }; + }; + } + ); + + endpointType = types.submodule ( + { config, ... }: + { + options = { + scheme = mkOption { + type = types.enum [ + "http" + "https" + ]; + }; + domain = mkOption { type = types.nonEmptyStr; }; + origin = mkOption { + type = types.nonEmptyStr; + readOnly = true; + default = "${config.scheme}://${config.domain}"; + }; + }; + } + ); + + externalDeviceType = types.submodule { + options.syncthingId = mkOption { + type = types.nullOr types.nonEmptyStr; + default = null; + }; + }; + + topologyType = types.submodule { + options.server = mkOption { + type = types.submodule { + options = { + machine = mkOption { type = types.nonEmptyStr; }; + sshAlias = mkOption { type = types.nonEmptyStr; }; + }; + }; + }; + }; + + factsType = + { + withMachine ? false, + }: + types.submodule { + options = { + account = accountOption; + machines = mkOption { type = types.attrsOf (machineType { }); }; + services = mkOption { type = types.attrsOf endpointType; }; + externalDevices = mkOption { + type = types.attrsOf externalDeviceType; + default = { }; + }; + topology = mkOption { type = topologyType; }; + } + // lib.optionalAttrs withMachine { + machine = mkOption { type = machineType { withName = true; }; }; + }; + }; in { - options.facts = factsOption; + options.facts = mkOption { + type = factsType { }; + }; config = { facts = { @@ -17,11 +196,11 @@ in realName = "Jelle Spreeuwenberg"; homeDirectory = "/home/${name}"; nixosConfigurationPath = "${homeDirectory}/.config/nixos"; + primaryEmail = "personal"; emails = { personal = { address = "mail@jelles.net"; - primary = true; type = "mxrouting"; }; old = { @@ -37,61 +216,59 @@ in type = "office365"; }; }; - - primaryEmail = emails.personal; }; services = { actual = { + scheme = "https"; domain = "finance.jelles.net"; - host = "127.0.0.1"; - port = 3000; - url = "https://finance.jelles.net"; }; gitea = { + scheme = "https"; domain = "git.jelles.net"; - host = "127.0.0.1"; - port = 3001; - url = "https://git.jelles.net/"; }; radicale = { + scheme = "https"; domain = "radicale.jelles.net"; - host = "127.0.0.1"; - port = 5232; - url = "https://radicale.jelles.net/"; }; vaultwarden = { + scheme = "https"; domain = "vault.jelles.net"; - host = "127.0.0.1"; - port = 8100; - url = "https://vault.jelles.net"; }; }; - theme = import ./capabilities/_theme.nix; + externalDevices.pixel-10.syncthingId = "MTJHEHA-UMZDQZ7-BTMRRLQ-Y7BFPUJ-ZTY6LZX-PDXV3IS-XVJCU7B-EPETBQZ"; + + topology.server = { + machine = "orion"; + sshAlias = "orion"; + }; }; - flake.modules.nixos.facts = { lib, ... }: { - options.facts = factsOption; + flake.modules.nixos.facts = { + options.facts = mkOption { + type = factsType { withMachine = true; }; + }; }; flake.modules.homeManager.facts = + { osConfig, ... }: { - lib, - osConfig ? { }, - ... - }: - { - options.facts = factsOption; + options.facts = mkOption { + type = factsType { withMachine = true; }; + }; - config.facts = lib.optionalAttrs (osConfig ? facts) { + config.facts = { inherit (osConfig.facts) account + externalDevices machine machines - services - theme + topology ; + services = lib.mapAttrs (_: service: { + inherit (service) scheme domain; + }) osConfig.facts.services; }; }; }; diff --git a/modules/flake-parts.nix b/modules/flake-parts.nix index f74b646..cb08dc3 100644 --- a/modules/flake-parts.nix +++ b/modules/flake-parts.nix @@ -1,6 +1,7 @@ { inputs, config, + lib, ... }: let @@ -9,17 +10,12 @@ let { pkgs, ... }: let account = config.facts.account; - hmStateVersion = machine.hmStateVersion or machine.stateVersion; - machineFacts = { - displays = { }; - portable = false; - sshKeys = { }; - syncthingId = null; - } - // machine - // { - inherit name hmStateVersion; + machineFacts = machine // { + inherit name; }; + services = lib.mapAttrs (_: service: { + inherit (service) scheme domain; + }) config.facts.services; in { imports = [ @@ -29,10 +25,11 @@ let facts = { inherit (config.facts) account + externalDevices machines - services - theme + topology ; + inherit services; machine = machineFacts; }; @@ -54,7 +51,7 @@ let home-manager.users.${account.name}.home = { username = account.name; homeDirectory = account.homeDirectory; - stateVersion = hmStateVersion; + stateVersion = machine.hmStateVersion; }; }; in @@ -66,13 +63,17 @@ in systems = [ "x86_64-linux" ]; - flake.nixosConfigurations = builtins.mapAttrs ( - name: machine: - inputs.nixpkgs.lib.nixosSystem { - specialArgs = { inherit inputs; }; - modules = [ (mkHost name machine) ]; - } - ) config.facts.machines; + flake.nixosConfigurations = + assert lib.assertMsg (builtins.hasAttr config.facts.topology.server.machine config.facts.machines) + "facts.topology.server.machine must name an entry in facts.machines"; + builtins.mapAttrs ( + name: machine: + inputs.nixpkgs.lib.nixosSystem { + inherit (machine) system; + specialArgs = { inherit inputs; }; + modules = [ (mkHost name machine) ]; + } + ) config.facts.machines; perSystem = { pkgs, ... }: diff --git a/modules/hosts/orion/default.nix b/modules/hosts/orion/default.nix index cf06ccf..078b05c 100644 --- a/modules/hosts/orion/default.nix +++ b/modules/hosts/orion/default.nix @@ -5,6 +5,7 @@ let in { facts.machines.orion = { + system = "x86_64-linux"; syncthingId = "NNRNQKZ-OWPHSVA-B6KKBHE-SDYLSTV-7SVHGPR-NEWLKPL-4MWNJG4-G5FHUAI"; stateVersion = "24.05"; diff --git a/modules/hosts/polaris/default.nix b/modules/hosts/polaris/default.nix index aae7211..47022e4 100644 --- a/modules/hosts/polaris/default.nix +++ b/modules/hosts/polaris/default.nix @@ -8,6 +8,7 @@ let in { facts.machines.polaris = { + system = "x86_64-linux"; sshKeys = { personal.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEVORk45HKkX7gaGGp90KsVyUy6t+fKhbWN/grjkf3cQ kiri@polaris"; work.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM5DMV6EQzsscgEOE0912mNglUHTEl+LPnaWYjj0y57B kiri@polaris#work"; @@ -36,9 +37,7 @@ in { imports = [ nixosModules.workstation-base - nixosModules.qbittorrent nixosModules.steam - nixosModules.yookr-dev ./_hardware.nix ] ++ (with inputs.nixos-hardware.nixosModules; [ diff --git a/modules/hosts/zenith/default.nix b/modules/hosts/zenith/default.nix index c5d78e6..2eb9ef4 100644 --- a/modules/hosts/zenith/default.nix +++ b/modules/hosts/zenith/default.nix @@ -8,7 +8,7 @@ let in { facts.machines.zenith = { - portable = true; + system = "x86_64-linux"; sshKeys = { personal.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIQy4k04gU7UpjBgyUQ57kUwxOdt79LvMCiCekXZeZhd kiri@zenith"; @@ -35,9 +35,7 @@ in { imports = [ nixosModules.workstation-base - nixosModules.qbittorrent nixosModules.laptop-power - nixosModules.yookr-dev { hardware.enableRedistributableFirmware = true; services.fwupd.enable = true; diff --git a/modules/profiles/host-base.nix b/modules/profiles/host-base.nix index 86ded10..c66af48 100644 --- a/modules/profiles/host-base.nix +++ b/modules/profiles/host-base.nix @@ -13,9 +13,9 @@ in nixosModules.facts inputs.home-manager.nixosModules.home-manager nixosModules.nix - nixosModules.locale-nl + nixosModules.locale nixosModules.sops-password - nixosModules.helix + nixosModules.helix-cache ]; home-manager = { @@ -26,7 +26,7 @@ in hmModules.facts hmModules.syncthing hmModules.shell - hmModules.helix + hmModules.primary-editor-helix ]; }; diff --git a/modules/profiles/workstation-base.nix b/modules/profiles/workstation-base.nix index e6db97d..b5c84db 100644 --- a/modules/profiles/workstation-base.nix +++ b/modules/profiles/workstation-base.nix @@ -23,9 +23,10 @@ in nixosModules.limine nixosModules.theme nixosModules.ai - nixosModules.hidraw-access + nixosModules.yunzi-b75-pro nixosModules.openvpn - nixosModules.walker-cache + nixosModules.walker + nixosModules.yookr-dev ]; services.dbus.implementation = "broker"; @@ -42,32 +43,26 @@ in imports = [ homeModules.passwords homeModules.clipboard + homeModules.desktop-commands homeModules.dev-tools homeModules.zed homeModules.xdg homeModules.workstation-apps - homeModules.primary-browser-vivaldi - homeModules.primary-file-manager-nautilus - homeModules.primary-launcher-walker - homeModules.default-image-viewer-imv - homeModules.default-document-viewer-sioyek + homeModules.vivaldi + homeModules.nautilus + homeModules.imv + homeModules.sioyek + homeModules.discord + homeModules.qbittorrent homeModules.email homeModules.mpv homeModules.nix homeModules.calendar-tasks - homeModules.podman homeModules.git homeModules.ssh-client homeModules.primary-terminal-kitty - homeModules.terminal-foot homeModules.noctalia homeModules.keyring - { - programs.discord = { - enable = true; - settings.SKIP_HOST_UPDATE = true; - }; - } ]; }; }