{ lib, nixpkgs, module, pkgs, system, }: let uploadLimits = import ../upload-limits.nix; evaluatedConfig = (nixpkgs.lib.nixosSystem { inherit system; modules = [ module { system.stateVersion = "26.05"; services.rabbi-gerzi = { enable = true; secretFiles = { borgPassphrase = "/run/secrets/borg-passphrase"; borgPrivateKey = "/run/secrets/borg-private-key"; }; frontend.hostName = "www.example.test"; backend = { hostName = "api.example.test"; environmentFile = "/run/secrets/rabbi-gerzi.env"; }; }; } ]; }).config; evaluatedHostName = evaluatedConfig.services.rabbi-gerzi.backend.hostName; backendVirtualHost = evaluatedConfig.services.nginx.virtualHosts.${evaluatedHostName}; phpOptions = evaluatedConfig.services.phpfpm.pools.rabbi-gerzi.phpOptions; backupConfig = evaluatedConfig.services.borgbackup.jobs.rabbi-gerzi; backupService = evaluatedConfig.systemd.services.borgbackup-job-rabbi-gerzi; phpFpmService = evaluatedConfig.systemd.services.phpfpm-rabbi-gerzi; stateDir = evaluatedConfig.services.rabbi-gerzi.stateDir; expectedUploadMaxFilesize = "upload_max_filesize = ${uploadLimits.phpUploadLimit}"; expectedPostMaxSize = "post_max_size = ${uploadLimits.phpUploadLimit}"; expectedNginxClientMaxBodySize = "client_max_body_size ${uploadLimits.nginxClientMaxBodySize};"; assertions = [ { passed = lib.hasInfix expectedUploadMaxFilesize phpOptions; message = "php-fpm upload_max_filesize is not 6M"; } { passed = lib.hasInfix expectedPostMaxSize phpOptions; message = "php-fpm post_max_size is not 6M"; } { passed = lib.hasInfix expectedNginxClientMaxBodySize backendVirtualHost.extraConfig; message = "nginx client_max_body_size is not 6m"; } { passed = backupConfig.repo == "ssh://mgjjruz9@mgjjruz9.repo.borgbase.com/./repo"; message = "Borg repository is not the Rabbi Gerzi repository"; } { passed = builtins.elem stateDir backupConfig.paths; message = "Borg backup does not include the application state"; } { passed = builtins.elem "/var/backup/rabbi-gerzi/rabbi-gerzi.dump" backupConfig.paths; message = "Borg backup does not include the database dump"; } { passed = backupConfig.startAt == "*-*-* 05:15:00"; message = "Borg backup does not run at 05:15"; } { passed = backupConfig.persistentTimer; message = "Borg timer is not persistent"; } { passed = backupConfig.prune.keep.daily == 7 && backupConfig.prune.keep.weekly == 4 && backupConfig.prune.keep.monthly == 6; message = "Borg retention policy is incorrect"; } { passed = backupConfig.encryption.mode == "repokey-blake2"; message = "Borg encryption mode is incorrect"; } { passed = lib.hasInfix "/run/secrets/borg-passphrase" (backupConfig.encryption.passCommand); message = "Borg passphrase secret is not wired"; } { passed = lib.hasInfix "/run/secrets/borg-private-key" (backupConfig.environment.BORG_RSH); message = "Borg SSH private key is not wired"; } { passed = backupConfig.compression == "auto,zstd"; message = "Borg compression is incorrect"; } { passed = backupConfig.doInit; message = "Borg repository initialization is disabled"; } { passed = builtins.elem "/var/backup/rabbi-gerzi" backupConfig.readWritePaths; message = "Borg job cannot write the database dump"; } { passed = lib.hasInfix "phpfpm-rabbi-gerzi.service" (backupConfig.preHook); message = "Borg pre-hook does not stop PHP-FPM"; } { passed = lib.hasInfix "--format=custom" backupConfig.preHook; message = "Borg pre-hook does not create a custom database dump"; } { passed = lib.hasInfix "phpfpm-rabbi-gerzi.service" (backupConfig.postHook); message = "Borg post-hook does not restore PHP-FPM"; } { passed = phpFpmService.serviceConfig.KillSignal == "SIGQUIT"; message = "PHP-FPM does not drain requests before stopping"; } { passed = builtins.elem "sops-install-secrets.service" (backupService.after); message = "Borg job is not ordered after secrets"; } { passed = builtins.elem "postgresql.service" backupService.after; message = "Borg job is not ordered after PostgreSQL"; } ]; failedAssertions = lib.filter (assertion: !assertion.passed) assertions; in pkgs.runCommand "rabbi-gerzi-module-eval" { failures = lib.concatMapStringsSep "\n" (assertion: assertion.message) failedAssertions; value = evaluatedHostName; preferLocalBuild = true; } '' if [ -n "$failures" ]; then printf '%s\n' "$failures" >&2 exit 1 fi echo "$value" > $out ''