180 lines
5.6 KiB
Nix
180 lines
5.6 KiB
Nix
{
|
|
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 = "example.test";
|
|
redirectHostNames = [ "www.example.test" ];
|
|
};
|
|
backend = {
|
|
hostName = "api.example.test";
|
|
environmentFile = "/run/secrets/rabbi-gerzi.env";
|
|
};
|
|
};
|
|
}
|
|
];
|
|
}).config;
|
|
|
|
evaluatedHostName = evaluatedConfig.services.rabbi-gerzi.backend.hostName;
|
|
|
|
evaluatedFrontendHostName = evaluatedConfig.services.rabbi-gerzi.frontend.hostName;
|
|
|
|
frontendRedirectVirtualHost = evaluatedConfig.services.nginx.virtualHosts."www.example.test";
|
|
|
|
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 = frontendRedirectVirtualHost.globalRedirect == evaluatedFrontendHostName;
|
|
message = "frontend redirect does not target the canonical host";
|
|
}
|
|
{
|
|
passed = frontendRedirectVirtualHost.forceSSL;
|
|
message = "frontend redirect does not force HTTPS";
|
|
}
|
|
{
|
|
passed = frontendRedirectVirtualHost.enableACME;
|
|
message = "frontend redirect does not enable ACME";
|
|
}
|
|
{
|
|
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
|
|
''
|