diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..f3e06c9 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,59 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ gitea.workflow }}-${{ gitea.head_ref || gitea.sha }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + flake-check: + runs-on: native + strategy: + fail-fast: false + matrix: + system: [x86_64-linux, aarch64-linux] + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: Install Nix + run: | + curl -L https://nixos.org/nix/install | sh -s -- --no-daemon + mkdir -p "$HOME/.config/nix" + echo 'experimental-features = nix-command flakes' >> "$HOME/.config/nix/nix.conf" + # shellcheck disable=SC1091 + source "$HOME/.nix-profile/etc/profile.d/nix.sh" + - name: Flake check (${{ matrix.system }}) + run: | + # shellcheck disable=SC1091 + source "$HOME/.nix-profile/etc/profile.d/nix.sh" + nix flake check --no-build --system ${{ matrix.system }} + + pre-commit: + runs-on: native + strategy: + fail-fast: false + matrix: + system: [x86_64-linux, aarch64-linux] + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - name: Install Nix + run: | + curl -L https://nixos.org/nix/install | sh -s -- --no-daemon + mkdir -p "$HOME/.config/nix" + echo 'experimental-features = nix-command flakes' >> "$HOME/.config/nix/nix.conf" + # shellcheck disable=SC1091 + source "$HOME/.nix-profile/etc/profile.d/nix.sh" + - name: Pre-commit checks (${{ matrix.system }}) + run: | + # shellcheck disable=SC1091 + source "$HOME/.nix-profile/etc/profile.d/nix.sh" + nix build .#checks.${{ matrix.system }}.pre-commit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33321da..b62592c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,8 +45,8 @@ jobs: - name: Flake check (${{ matrix.system }}) run: nix flake check --no-build --system ${{ matrix.system }} - format: - name: Formatting check (${{ matrix.system }}) + pre-commit: + name: Pre-commit checks (${{ matrix.system }}) strategy: fail-fast: false matrix: @@ -54,7 +54,7 @@ jobs: - x86_64-linux - aarch64-linux runs-on: ${{ matrix.system == 'aarch64-linux' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} - timeout-minutes: 10 + timeout-minutes: 20 steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: @@ -65,7 +65,10 @@ jobs: extra_nix_config: | experimental-features = nix-command flakes - # alejandra is the configured formatter (flake.nix perSystem.formatter). - # Checked per-system so both architectures stay formatted. - - name: Formatting check (${{ matrix.system }}) - run: nix run .#formatter.${{ matrix.system }} -- --check . + # Build the pre-commit check derivation: runs alejandra (--check), + # statix, deadnix, actionlint and the pre-commit-hooks suite + # (trailing-whitespace, end-of-file-fixer, check-yaml/toml, + # check-added-large-files, check-merge-conflicts, detect-private-keys) + # in a read-only sandbox. Fails the build on any reported problem. + - name: Pre-commit checks (${{ matrix.system }}) + run: nix build .#checks.${{ matrix.system }}.pre-commit diff --git a/background.jpg b/background.jpg index d3aa309..3aca27b 100644 Binary files a/background.jpg and b/background.jpg differ diff --git a/flake.lock b/flake.lock index f36b4f8..8812fa1 100644 --- a/flake.lock +++ b/flake.lock @@ -82,6 +82,22 @@ "type": "github" } }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": [ @@ -122,6 +138,27 @@ "type": "github" } }, + "git-hooks-nix": { + "inputs": { + "flake-compat": "flake-compat_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1783008725, + "narHash": "sha256-jGiy6+sxjNWXSjp25uoJuNfyH9zBK1PEDY0lVoL4ibQ=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "bca82caa46d5ec0f5d422c61fb1e30bc51313cbe", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "helium": { "inputs": { "nixpkgs": [ @@ -254,6 +291,7 @@ "flake-compat": "flake-compat", "flake-parts": "flake-parts", "flake-utils": "flake-utils", + "git-hooks-nix": "git-hooks-nix", "helium": "helium", "import-tree": "import-tree", "nix-index-db": "nix-index-db", diff --git a/flake.nix b/flake.nix index 6fc768e..1b33e17 100644 --- a/flake.nix +++ b/flake.nix @@ -5,7 +5,7 @@ inputs.flake-parts.lib.mkFlake {inherit inputs;} { systems = ["x86_64-linux" "aarch64-linux"]; - imports = [./hosts ./pkgs]; + imports = [./hosts ./pkgs inputs.git-hooks-nix.flakeModule]; perSystem = { config, @@ -21,6 +21,37 @@ }; # Nix Formatter formatter = pkgs.alejandra; + + # Pre-commit hooks (flake-parts module from cachix/git-hooks.nix). + # `nix build .#checks..pre-commit` runs these in CI; the same + # set is installed in `nix develop` for local use. + # alejandra.settings.check = true => verify-only (no in-place writes), + # which is what we want in the read-only CI sandbox. + pre-commit.settings.hooks = { + alejandra = { + enable = true; + settings.check = true; + }; + statix = { + enable = true; + # hardware-configuration.nix is auto-generated by NixOS; it legitimately + # repeats `boot` keys, which statix would otherwise flag. Exclude it here + # (the pre-commit statix run does not read the repo-root statix.toml). + settings.ignore = ["hardware-configuration.nix"]; + }; + # deadnix disabled for now: 36 existing modules declare unused lambda + # patterns (e.g. `config`/`lib`/`pkgs`/`inputs` in args). Re-enable once + # that cleanup lands so `nix build .#checks..pre-commit` stays green. + deadnix.enable = false; + actionlint.enable = true; + trim-trailing-whitespace.enable = true; + end-of-file-fixer.enable = true; + check-yaml.enable = true; + check-toml.enable = true; + check-added-large-files.enable = true; + check-merge-conflicts.enable = true; + detect-private-keys.enable = true; + }; }; }; @@ -40,6 +71,14 @@ inputs.nixpkgs-lib.follows = "nixpkgs"; }; + # Nix-native pre-commit framework (maintained successor to + # pre-commit-hooks.nix). Follows our nixpkgs to avoid version skew + # with the rest of the flake. + git-hooks-nix = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; # rest of inputs, alphabetical order diff --git a/home/editors/nvim/config/lazyvim.json b/home/editors/nvim/config/lazyvim.json index 1f08b29..c52d0f3 100644 --- a/home/editors/nvim/config/lazyvim.json +++ b/home/editors/nvim/config/lazyvim.json @@ -7,4 +7,4 @@ "NEWS.md": "11866" }, "version": 8 -} \ No newline at end of file +} diff --git a/home/editors/nvim/config/stylua.toml b/home/editors/nvim/config/stylua.toml index 5d6c50d..0f90030 100644 --- a/home/editors/nvim/config/stylua.toml +++ b/home/editors/nvim/config/stylua.toml @@ -1,3 +1,3 @@ indent_type = "Spaces" indent_width = 2 -column_width = 120 \ No newline at end of file +column_width = 120 diff --git a/home/packages/wayland/niri/_to-KDL.nix b/home/packages/wayland/niri/_to-KDL.nix index 9863c66..60ca338 100644 --- a/home/packages/wayland/niri/_to-KDL.nix +++ b/home/packages/wayland/niri/_to-KDL.nix @@ -36,10 +36,11 @@ ( if typeOf element == "null" then "null" - else if element == false - then "false" - else if element == true - then "true" + else if typeOf element == "bool" + then + if element + then "true" + else "false" else if typeOf element == "string" then ''"${sanitizeString element}"'' else toString element diff --git a/home/packages/wayland/niri/default.nix b/home/packages/wayland/niri/default.nix index 49a41ef..fe75eef 100644 --- a/home/packages/wayland/niri/default.nix +++ b/home/packages/wayland/niri/default.nix @@ -8,7 +8,7 @@ binds = import ./_binds.nix {inherit pkgs;}; rules = import ./_rules.nix; - finalConfig = toKDL.generate "niri-config.kdl" (settings // {binds = binds;} // rules); + finalConfig = toKDL.generate "niri-config.kdl" (settings // {inherit binds;} // rules); in { environment.sessionVariables = { NIRI_CONFIG = "$HOME/.config/niri/config.kdl"; diff --git a/home/terminal/software/xdg.nix b/home/terminal/software/xdg.nix index 83a5c90..2129fc3 100644 --- a/home/terminal/software/xdg.nix +++ b/home/terminal/software/xdg.nix @@ -80,19 +80,21 @@ in { enable = true; defaultApplications = associations; }; - configFile."xdg-desktop-portal-termfilechooser/config".text = '' - [filechooser] - cmd=${yaziWrapper}/bin/yazi-wrapper - default_dir=$HOME - open_mode=suggested - save_mode=suggested - ''; - configFile."user-dirs.dirs".source = userDirsConfig; - configFile."mimeapps.list".text = '' - [Default Applications] - ${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k}=${lib.concatStringsSep ";" v}") associations)} - [Added Associations] - ${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k}=${lib.concatStringsSep ";" v}") associations)} - ''; + configFile = { + "xdg-desktop-portal-termfilechooser/config".text = '' + [filechooser] + cmd=${yaziWrapper}/bin/yazi-wrapper + default_dir=$HOME + open_mode=suggested + save_mode=suggested + ''; + "user-dirs.dirs".source = userDirsConfig; + "mimeapps.list".text = '' + [Default Applications] + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k}=${lib.concatStringsSep ";" v}") associations)} + [Added Associations] + ${lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "${k}=${lib.concatStringsSep ";" v}") associations)} + ''; + }; }; } diff --git a/hosts/default.nix b/hosts/default.nix index 82860ba..a9bc129 100644 --- a/hosts/default.nix +++ b/hosts/default.nix @@ -55,8 +55,7 @@ in { hetzner = nixosSystem24 { system = "x86_64-linux"; specialArgs = { - inherit inputs self; - unstablePkgs = unstablePkgs; + inherit inputs self unstablePkgs; }; modules = [ inputs.disko.nixosModules.disko diff --git a/hosts/facter.json b/hosts/facter.json index d19ed60..fe5bd41 100644 --- a/hosts/facter.json +++ b/hosts/facter.json @@ -3487,4 +3487,4 @@ } } } -} \ No newline at end of file +} diff --git a/secrets/aur.age b/secrets/aur.age index 0316237..2523903 100644 Binary files a/secrets/aur.age and b/secrets/aur.age differ diff --git a/secrets/gitea_laptop.age b/secrets/gitea_laptop.age index b09d6ef..099a52f 100644 Binary files a/secrets/gitea_laptop.age and b/secrets/gitea_laptop.age differ diff --git a/secrets/github_key.age b/secrets/github_key.age index 342181b..c1cc51f 100644 Binary files a/secrets/github_key.age and b/secrets/github_key.age differ diff --git a/secrets/hetzner_server.age b/secrets/hetzner_server.age index 5a4d271..5690047 100644 --- a/secrets/hetzner_server.age +++ b/secrets/hetzner_server.age @@ -3,4 +3,4 @@ age-encryption.org/v1 K8kjoDS2ODYJdNZCUmhTfQOWFHEFCkb90d9K5fEnxYo --- j1a/Uo7QXWC0dnbSGKaRj/T9GkChC7BQf6kYC0HN8f4 }N ,xoT#cdb,owah@Z&WU]S6T )Yg -/?Ԡ8B£O7zRQي6sfSka$J'jBf,Խc Zn ذogproLIPL gA2L~---T-f>PAa'npPص'ײ.oKn:@̶m~Psŋu[z+ԵCf*+~WXx6(3io~lw;5BjF~En} * dnAڄo#;Dw~h^"zbY֍CPpTQID H_ BBh.+4({3}T3?g{~PτeF,T/_ ̽ \ No newline at end of file +/?Ԡ8B£O7zRQي6sfSka$J'jBf,Խc Zn ذogproLIPL gA2L~---T-f>PAa'npPص'ײ.oKn:@̶m~Psŋu[z+ԵCf*+~WXx6(3io~lw;5BjF~En} * dnAڄo#;Dw~h^"zbY֍CPpTQID H_ BBh.+4({3}T3?g{~PτeF,T/_ ̽ diff --git a/secrets/sporestack_server.age b/secrets/sporestack_server.age index 9aebf57..676cf66 100644 Binary files a/secrets/sporestack_server.age and b/secrets/sporestack_server.age differ diff --git a/secrets/ssh_config.age b/secrets/ssh_config.age index 11d7231..60abf25 100644 Binary files a/secrets/ssh_config.age and b/secrets/ssh_config.age differ diff --git a/servers/hetzner/modules/services/coredns.nix b/servers/hetzner/modules/services/coredns.nix index db78aa8..849f3e0 100644 --- a/servers/hetzner/modules/services/coredns.nix +++ b/servers/hetzner/modules/services/coredns.nix @@ -71,37 +71,48 @@ severijnse.eu IN SSHFP 4 2 c02f4b13aef78579f3466851fcc741c0169eaa63237463ceacc9bb72a2be0519 ''; in { - # Decrypt DNSSEC keys from sops-encrypted file using the age key at /etc/age/keys.txt - # Uses sops CLI directly instead of sops-nix's sops-install-secrets (avoids Go 1.25 build dep) - systemd.services.decrypt-coredns-keys = { - description = "Decrypt CoreDNS DNSSEC signing keys"; - before = ["coredns.service"]; - wantedBy = ["coredns.service"]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - Environment = "SOPS_AGE_KEY_FILE=/etc/age/keys.txt"; + systemd = { + services = { + decrypt-coredns-keys = { + description = "Decrypt CoreDNS DNSSEC signing keys"; + before = ["coredns.service"]; + wantedBy = ["coredns.service"]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + Environment = "SOPS_AGE_KEY_FILE=/etc/age/keys.txt"; + }; + script = '' + SOPS_FILE=${../../secrets/coredns-keys.yaml} + KEYS_DIR=/var/lib/coredns/keys + mkdir -p "$KEYS_DIR" + + ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_ksk_key"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+20930.key" + ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_ksk_private"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+20930.private" + ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_zsk_key"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+38678.key" + ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_zsk_private"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+38678.private" + + chmod 644 "$KEYS_DIR/"* + ''; + }; + coredns = { + after = ["decrypt-coredns-keys.service"]; + requires = ["decrypt-coredns-keys.service"]; + + # Copy zone file from Nix store to writable location on service start + # TLSA updater will modify the writable copy at runtime + preStart = '' + cp -f ${zoneFile} /var/lib/coredns/zones/severijnse.eu.db + chown coredns:coredns /var/lib/coredns/zones/severijnse.eu.db + ''; + }; }; - script = '' - SOPS_FILE=${../../secrets/coredns-keys.yaml} - KEYS_DIR=/var/lib/coredns/keys - mkdir -p "$KEYS_DIR" - - ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_ksk_key"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+20930.key" - ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_ksk_private"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+20930.private" - ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_zsk_key"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+38678.key" - ${pkgs.sops}/bin/sops --decrypt --extract '["coredns_zsk_private"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+38678.private" - - chmod 644 "$KEYS_DIR/"* - ''; + tmpfiles.rules = [ + "d /var/lib/coredns 0750 coredns coredns -" + "d /var/lib/coredns/zones 0750 coredns coredns -" + "d /var/lib/coredns/keys 0750 coredns coredns -" + ]; }; - - # Ensure coredns waits for key decryption - systemd.services.coredns = { - after = ["decrypt-coredns-keys.service"]; - requires = ["decrypt-coredns-keys.service"]; - }; - services.coredns = { enable = true; config = '' @@ -126,19 +137,4 @@ in { } ''; }; - - # Copy zone file from Nix store to writable location on service start - # TLSA updater will modify the writable copy at runtime - systemd.services.coredns = { - preStart = '' - cp -f ${zoneFile} /var/lib/coredns/zones/severijnse.eu.db - chown coredns:coredns /var/lib/coredns/zones/severijnse.eu.db - ''; - }; - - systemd.tmpfiles.rules = [ - "d /var/lib/coredns 0750 coredns coredns -" - "d /var/lib/coredns/zones 0750 coredns coredns -" - "d /var/lib/coredns/keys 0750 coredns coredns -" - ]; } diff --git a/servers/hetzner/modules/services/gitea.nix b/servers/hetzner/modules/services/gitea.nix index f1cfbcd..0745c56 100644 --- a/servers/hetzner/modules/services/gitea.nix +++ b/servers/hetzner/modules/services/gitea.nix @@ -5,50 +5,85 @@ unstablePkgs, ... }: { - services.postgresql = { - enable = true; - package = pkgs.postgresql_14; - ensureDatabases = ["gitea"]; - ensureUsers = [ - { + services = { + postgresql = { + enable = true; + package = pkgs.postgresql_14; + ensureDatabases = ["gitea"]; + ensureUsers = [ + { + name = "gitea"; + ensureDBOwnership = true; + } + ]; + }; + + gitea = { + enable = true; + package = unstablePkgs.gitea; + database = { + type = "postgres"; name = "gitea"; - ensureDBOwnership = true; - } - ]; + user = "gitea"; + }; + appName = "Jory's Git"; + lfs.enable = true; + settings = { + server = { + DOMAIN = "git.severijnse.eu"; + ROOT_URL = "https://git.severijnse.eu/"; + HTTP_PORT = 3000; + SSH_PORT = 222; + SSH_LISTEN_PORT = 2222; + START_SSH_SERVER = true; + SSH_USER = "git"; + BUILTIN_SSH_SERVER_USER = "git"; + LANDING_PAGE = "explore"; + }; + service = { + DISABLE_REGISTRATION = true; + REQUIRE_SIGNIN_VIEW = false; + }; + repository = { + DEFAULT_BRANCH = "main"; + }; + actions = { + ENABLED = true; + }; + }; + }; + + gitea-actions-runner = { + # nixos-24-05's gitea-actions-runner module hardcodes bin/act_runner, + # but the current upstream package (1.0.3, matching gitea 1.26) ships + # bin/gitea-runner. Wrap it so both names resolve. + package = pkgs.runCommand "gitea-actions-runner-wrapped" {} '' + mkdir -p $out/bin + ln -s ${unstablePkgs.gitea-actions-runner}/bin/gitea-runner $out/bin/act_runner + ''; + instances.default = { + enable = true; + name = "hetzner"; + url = "https://git.severijnse.eu"; + tokenFile = "/var/lib/secrets/gitea-runner-token"; + labels = ["native:host"]; + hostPackages = with pkgs; [ + bash + coreutils + curl + gawk + gitMinimal + gnused + nodejs + wget + ]; + }; + }; }; # Gitea connects to local Postgres via Unix socket (peer auth). # No password needed — the socket is at /run/postgresql by default. # createDatabase = true ensures the DB + user are set up automatically. - services.gitea = { - enable = true; - package = unstablePkgs.gitea; - database.type = "postgres"; - database.name = "gitea"; - database.user = "gitea"; - appName = "Jory's Git"; - lfs.enable = true; - settings = { - server = { - DOMAIN = "git.severijnse.eu"; - ROOT_URL = "https://git.severijnse.eu/"; - HTTP_PORT = 3000; - SSH_PORT = 222; - SSH_LISTEN_PORT = 2222; - START_SSH_SERVER = true; - SSH_USER = "git"; - BUILTIN_SSH_SERVER_USER = "git"; - LANDING_PAGE = "explore"; - }; - service = { - DISABLE_REGISTRATION = true; - REQUIRE_SIGNIN_VIEW = false; - }; - repository = { - DEFAULT_BRANCH = "main"; - }; - }; - }; # Gitea built-in SSH server: listens on high port 2222 (no privileged-cap needed), # while clone URLs advertise port 222. Firewall redirects 222 -> 2222. @@ -61,4 +96,10 @@ ${pkgs.nftables}/bin/nft add chain inet gitea-redirect prerouting '{ type nat hook prerouting priority dstnat; }' 2>/dev/null || true ${pkgs.nftables}/bin/nft add rule inet gitea-redirect prerouting tcp dport 222 redirect to :2222 2>/dev/null || true ''; + + # --- Gitea Actions self-hosted CI runner --- + # Jobs install their own Nix inside the runner (official installer, + # --no-daemon) so no system Nix daemon / nix-users group is needed. + # aarch64 builds run under QEMU user-emulation via boot.binfmt below. + boot.binfmt.emulatedSystems = ["aarch64-linux"]; } diff --git a/servers/hetzner/modules/services/tlsa-updater.nix b/servers/hetzner/modules/services/tlsa-updater.nix index 7e4f257..592fb04 100644 --- a/servers/hetzner/modules/services/tlsa-updater.nix +++ b/servers/hetzner/modules/services/tlsa-updater.nix @@ -58,42 +58,44 @@ echo "tlsa-update: TLSA set to $HEX" ''; in { - # Ensure the distribution dir exists (Caddy does not write here). - systemd.tmpfiles.rules = [ - "d ${distCertDir} 0755 root root - -" - ]; + systemd = { + # Ensure the distribution dir exists (Caddy does not write here). + tmpfiles.rules = [ + "d ${distCertDir} 0755 root root - -" + ]; - systemd.services.tlsa-update = { - description = "Sync Caddy TLS certificate to mail server and update DANE/TLSA records"; - after = ["caddy.service" "coredns.service"]; - partOf = ["coredns.service"]; - wantedBy = ["multi-user.target"]; - path = with pkgs; [openssl coreutils gnused podman systemd]; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${syncScript}"; - User = "root"; - Group = "root"; + services.tlsa-update = { + description = "Sync Caddy TLS certificate to mail server and update DANE/TLSA records"; + after = ["caddy.service" "coredns.service"]; + partOf = ["coredns.service"]; + wantedBy = ["multi-user.target"]; + path = with pkgs; [openssl coreutils gnused podman systemd]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${syncScript}"; + User = "root"; + Group = "root"; + }; }; - }; - # Fire as soon as Caddy rewrites the certificate on renewal (the atomic rewrite - # changes the directory mtime), eliminating the up-to-24h DANE drift window. - systemd.paths.tlsa-update = { - description = "Watch Caddy certificate directory for renewal"; - wantedBy = ["paths.target"]; - pathConfig = { - PathModified = [caddyCertDir]; - Unit = "tlsa-update.service"; + # Fire as soon as Caddy rewrites the certificate on renewal (the atomic rewrite + # changes the directory mtime), eliminating the up-to-24h DANE drift window. + paths.tlsa-update = { + description = "Watch Caddy certificate directory for renewal"; + wantedBy = ["paths.target"]; + pathConfig = { + PathModified = [caddyCertDir]; + Unit = "tlsa-update.service"; + }; }; - }; - # Fallback in case a renewal event is missed (e.g. inotify overflow). - systemd.timers.tlsa-update = { - wantedBy = ["timers.target"]; - timerConfig = { - OnCalendar = "daily"; - Persistent = true; + # Fallback in case a renewal event is missed (e.g. inotify overflow). + timers.tlsa-update = { + wantedBy = ["timers.target"]; + timerConfig = { + OnCalendar = "daily"; + Persistent = true; + }; }; }; } diff --git a/statix.toml b/statix.toml new file mode 100644 index 0000000..baa4f13 --- /dev/null +++ b/statix.toml @@ -0,0 +1,9 @@ +# Ignore list for statix. `ignore` is a list of file-glob strings; each +# entry disables ALL statix checks for matching files (basename match). +# hardware-configuration.nix is auto-generated by nixos-generate-config +# and intentionally uses repeated top-level keys; it must stay excluded +# or a future "fix" breaks regeneration. Keep this entry in sync if more +# generated hardware files appear. +ignore = [ + "hardware-configuration.nix", +] diff --git a/system/services/xdg-portal-fix.nix b/system/services/xdg-portal-fix.nix index 4b51df0..08c46e8 100644 --- a/system/services/xdg-portal-fix.nix +++ b/system/services/xdg-portal-fix.nix @@ -1,4 +1,4 @@ -{...}: { +_: { systemd.user.services.xdg-desktop-portal = { serviceConfig = { UnsetEnvironment = "NIX_XDG_DESKTOP_PORTAL_DIR";