diff --git a/hosts/nb/configuration.nix b/hosts/nb/configuration.nix index 4f42a9c..e1b6db5 100644 --- a/hosts/nb/configuration.nix +++ b/hosts/nb/configuration.nix @@ -30,6 +30,7 @@ in { ./modules/ollama.nix ./modules/qdrant.nix ./modules/battery-brightness.nix + ./modules/suspend-fixes.nix ./cachix.nix ./users @@ -71,6 +72,14 @@ in { theme = "steeef"; # Set theme plugins = [ "git" ]; # Add plugins }; + interactiveShellInit = '' + # Bind Shift+Return to insert newline (foot terminal sends \e[27;2;13~) + insert-newline() { + LBUFFER="''${LBUFFER}"$'\n' + } + zle -N insert-newline + bindkey '^[[27;2;13~' insert-newline + ''; }; users.defaultUserShell = pkgs.zsh; @@ -79,7 +88,7 @@ in { services.irqbalance.enable = false; swapDevices = [ { - device = "/nix/persist/swapfile"; + device = "/swap/swapfile"; size = 96 * 1024; # Size is in megabytes (96GB for full hibernation with 92GB RAM) } ]; @@ -92,8 +101,8 @@ in { # Battery optimization - increase dirty writeback time to batch writes "vm.dirty_writeback_centisecs" = 3000; # 30 seconds (default: 500 = 5s) "vm.dirty_expire_centisecs" = 3000; # 30 seconds (default: 3000) - # Enable laptop mode for aggressive disk power management - "vm.laptop_mode" = 5; + # Enable laptop mode for disk power management (2 = balanced, less aggressive than 5) + "vm.laptop_mode" = 2; }; # nixos cross building qemu diff --git a/hosts/nb/hardware-configuration.nix b/hosts/nb/hardware-configuration.nix index a1538fb..e9fc49d 100644 --- a/hosts/nb/hardware-configuration.nix +++ b/hosts/nb/hardware-configuration.nix @@ -28,7 +28,6 @@ "snd_hda_intel.power_save=1" "transparent_hugepage=madvise" "pcie_aspm=force" - "nvme.noacpi=1" ]; fileSystems."/" = { @@ -92,6 +91,16 @@ ]; }; + fileSystems."/swap" = { + device = "/dev/mapper/root"; + fsType = "btrfs"; + neededForBoot = true; + options = [ + "subvol=@swap" + "noatime" + ]; + }; + swapDevices = [ ]; # Enables DHCP on each ethernet and wireless interface. In case of scripted networking diff --git a/hosts/nb/modules/desktop/default.nix b/hosts/nb/modules/desktop/default.nix index e7e7005..d1e2372 100644 --- a/hosts/nb/modules/desktop/default.nix +++ b/hosts/nb/modules/desktop/default.nix @@ -159,6 +159,7 @@ in { USB_EXCLUDE_PHONE = 0; USB_EXCLUDE_PRINTER = 1; USB_EXCLUDE_WWAN = 0; + USB_EXCLUDE_INPUT = 1; # Exclude keyboard/touchpad to prevent suspend issues # Audio power saving SOUND_POWER_SAVE_ON_AC = 0; diff --git a/hosts/nb/modules/development/nvim/config/sops.lua b/hosts/nb/modules/development/nvim/config/sops.lua new file mode 100644 index 0000000..662f09a --- /dev/null +++ b/hosts/nb/modules/development/nvim/config/sops.lua @@ -0,0 +1,152 @@ +-- SOPS integration for automatic encryption/decryption of secrets files +-- This module sets up autocmds to handle .secrets.yaml files transparently + +local sops_group = vim.api.nvim_create_augroup("SopsEncryption", { clear = true }) + +-- Pattern matching for secrets files +local secrets_patterns = { + "*/secrets.yaml", + "*secrets*.yaml", +} + +-- Helper function to check if file matches secrets pattern +local function is_secrets_file(filepath) + for _, pattern in ipairs(secrets_patterns) do + if vim.fn.match(filepath, vim.fn.glob2regpat(pattern)) ~= -1 then + return true + end + end + return false +end + +-- Set filetype before reading to enable syntax highlighting +vim.api.nvim_create_autocmd("BufReadPre", { + group = sops_group, + pattern = secrets_patterns, + callback = function(args) + -- Set filetype to yaml before the file is read so syntax highlighting works + vim.bo.filetype = "yaml" + end, +}) + +-- Decrypt file after reading +vim.api.nvim_create_autocmd("BufReadPost", { + group = sops_group, + pattern = secrets_patterns, + callback = function(args) + local filepath = vim.fn.expand("%:p") + + -- Only decrypt if file exists and has content + if vim.fn.filereadable(filepath) == 1 and vim.fn.getfsize(filepath) > 0 then + -- Save cursor position + local cursor_pos = vim.api.nvim_win_get_cursor(0) + + -- Decrypt file content + local result = vim.fn.system("sops --decrypt " .. vim.fn.shellescape(filepath)) + + if vim.v.shell_error == 0 then + -- Replace buffer content with decrypted content + vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(result, "\n")) + + -- Mark buffer as not modified (since we just loaded it) + vim.bo.modified = false + + -- Restore cursor position + pcall(vim.api.nvim_win_set_cursor, 0, cursor_pos) + + -- Disable swap, backup, and undo files for security + vim.bo.swapfile = false + vim.bo.backup = false + vim.bo.writebackup = false + vim.bo.undofile = false + + -- Ensure filetype is set to yaml for syntax highlighting + vim.bo.filetype = "yaml" + + vim.notify("SOPS: File decrypted successfully", vim.log.levels.INFO) + else + vim.notify("SOPS: Failed to decrypt file: " .. result, vim.log.levels.ERROR) + end + end + end, +}) + +-- Encrypt file before writing +vim.api.nvim_create_autocmd("BufWritePre", { + group = sops_group, + pattern = secrets_patterns, + callback = function(args) + local filepath = vim.fn.expand("%:p") + + if is_secrets_file(filepath) then + -- Get current buffer content + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) + local content = table.concat(lines, "\n") + + -- Encrypt content using SOPS + local encrypted = vim.fn.system("sops --encrypt /dev/stdin", content) + + if vim.v.shell_error == 0 then + -- Write encrypted content directly to file + local file = io.open(filepath, "w") + if file then + file:write(encrypted) + file:close() + + -- Mark buffer as saved (prevent Vim from writing again) + vim.bo.modified = false + + vim.notify("SOPS: File encrypted and saved successfully", vim.log.levels.INFO) + else + vim.notify("SOPS: Failed to write encrypted file", vim.log.levels.ERROR) + end + else + vim.notify("SOPS: Failed to encrypt file: " .. encrypted, vim.log.levels.ERROR) + -- Prevent write on encryption failure + return true + end + + -- Prevent default write behavior since we handled it + return true + end + end, +}) + +-- Re-decrypt after writing to show plaintext in buffer +vim.api.nvim_create_autocmd("BufWritePost", { + group = sops_group, + pattern = secrets_patterns, + callback = function(args) + local filepath = vim.fn.expand("%:p") + + if is_secrets_file(filepath) and vim.fn.filereadable(filepath) == 1 then + -- Decrypt and reload buffer content + local result = vim.fn.system("sops --decrypt " .. vim.fn.shellescape(filepath)) + + if vim.v.shell_error == 0 then + -- Save cursor position + local cursor_pos = vim.api.nvim_win_get_cursor(0) + + -- Replace buffer with decrypted content + vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(result, "\n")) + + -- Mark as not modified + vim.bo.modified = false + + -- Restore cursor position + pcall(vim.api.nvim_win_set_cursor, 0, cursor_pos) + end + end + end, +}) + +-- Warn when leaving a secrets buffer with unsaved changes +vim.api.nvim_create_autocmd("BufLeave", { + group = sops_group, + pattern = secrets_patterns, + callback = function(args) + if vim.bo.modified then + vim.notify("Warning: Unsaved changes in secrets file!", vim.log.levels.WARN) + end + end, +}) diff --git a/hosts/nb/modules/development/nvim/default.nix b/hosts/nb/modules/development/nvim/default.nix index 233414f..17f7d5c 100644 --- a/hosts/nb/modules/development/nvim/default.nix +++ b/hosts/nb/modules/development/nvim/default.nix @@ -102,6 +102,7 @@ in "utils" "bufferline" "which-key" + "sops" ]); in '' lua << EOF diff --git a/hosts/nb/modules/suspend-fixes.nix b/hosts/nb/modules/suspend-fixes.nix new file mode 100644 index 0000000..c6bb147 --- /dev/null +++ b/hosts/nb/modules/suspend-fixes.nix @@ -0,0 +1,24 @@ +{ config, pkgs, lib, ... }: + +{ + # Add i2c_hid_acpi kernel module for proper input device support + boot.kernelModules = [ "i2c_hid_acpi" ]; + + # Commands to run after resume from suspend/hibernate + # This is the NixOS-native way to ensure proper execution timing + powerManagement.resumeCommands = '' + # Reload i2c_hid_acpi module to fix keyboard/touchpad after suspend + ${pkgs.kmod}/bin/rmmod i2c_hid_acpi || true + ${pkgs.kmod}/bin/modprobe i2c_hid_acpi + + # Sync filesystem to ensure all pending writes are committed + ${pkgs.util-linux}/bin/sync + + # Remount all btrfs subvolumes read-write if they became read-only + # This fixes the issue where LUKS + btrfs can remount read-only after suspend + ${pkgs.util-linux}/bin/mount -o remount,rw /nix || true + ${pkgs.util-linux}/bin/mount -o remount,rw /nix/store || true + ${pkgs.util-linux}/bin/mount -o remount,rw /nix/persist || true + ${pkgs.util-linux}/bin/mount -o remount,rw /swap || true + ''; +} diff --git a/hosts/nb/users/configs/project_history b/hosts/nb/users/configs/project_history index b74f02b..64a3845 100644 --- a/hosts/nb/users/configs/project_history +++ b/hosts/nb/users/configs/project_history @@ -46,7 +46,7 @@ /home/dominik/projects/epicenter.works/epicenter.works-website /home/dominik/projects/epicenter.works/epicenter-nixos /home/dominik/projects/epicenter.works/spenden.akvorrat.at -/home/dominik/projects/epicenter.works/eidas.monitor +/home/dominik/projects/epicenter.works/whoidentifies.me/wim-api /home/dominik/projects/cloonar/lena-schilling-website /home/dominik/projects/cloonar/dialog-relations-website diff --git a/hosts/nb/users/dominik.nix b/hosts/nb/users/dominik.nix index 979a4e4..6387807 100644 --- a/hosts/nb/users/dominik.nix +++ b/hosts/nb/users/dominik.nix @@ -165,6 +165,7 @@ in programs.zsh = { shellInit = '' export OPENAI_API_KEY=$(cat ${config.sops.secrets.openai_api_key.path}) + export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/key.age" ''; }; @@ -175,6 +176,7 @@ in home.enableNixpkgsReleaseCheck = false; home.sessionVariables = { MOZ_ENABLE_WAYLAND = "1"; + SOPS_AGE_KEY_FILE = "$HOME/.config/sops/age/key.age"; }; nixpkgs.config.allowUnfree = true; @@ -625,7 +627,7 @@ in git clone git@github.com:AKVorrat/epicenter.works-website.git ${persistHome}/projects/epicenter.works/epicenter.works-website 2>/dev/null git clone git@github.com:AKVorrat/spenden.akvorrat.at.git ${persistHome}/projects/epicenter.works/spenden.akvorrat.at 2>/dev/null git clone git@github.com:AKVorrat/dearmep-website.git ${persistHome}/projects/epicenter.works/dearmep-website 2>/dev/null - git clone gitea@git.cloonar.com:Cloonar/eidas.monitor.git ${persistHome}/projects/epicenter.works/eidas.monitor 2>/dev/null + git clone git@github.com:whoidentifies-me/api.git ${persistHome}/projects/epicenter.works/whoidentifies.me/wim-api 2>/dev/null set -eu '';