{ self }: { config, lib, pkgs, ... }: let cfg = config.services.homelab-deploy.listener; # Build command line arguments from configuration args = lib.concatStringsSep " " ([ "--hostname ${lib.escapeShellArg cfg.hostname}" "--tier ${cfg.tier}" "--nats-url ${lib.escapeShellArg cfg.natsUrl}" "--nkey-file ${lib.escapeShellArg cfg.nkeyFile}" "--flake-url ${lib.escapeShellArg cfg.flakeUrl}" "--timeout ${toString cfg.timeout}" "--discover-subject ${lib.escapeShellArg cfg.discoverSubject}" ] ++ lib.optional (cfg.role != null) "--role ${lib.escapeShellArg cfg.role}" ++ map (s: "--deploy-subject ${lib.escapeShellArg s}") cfg.deploySubjects); in { options.services.homelab-deploy.listener = { enable = lib.mkEnableOption "homelab-deploy listener service"; package = lib.mkOption { type = lib.types.package; default = self.packages.${pkgs.system}.homelab-deploy; description = "The homelab-deploy package to use"; }; hostname = lib.mkOption { type = lib.types.str; default = config.networking.hostName; description = "Hostname for this listener (used in subject templates)"; }; tier = lib.mkOption { type = lib.types.enum [ "test" "prod" ]; description = "Deployment tier for this host"; }; role = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = "Role for role-based deployment targeting"; }; natsUrl = lib.mkOption { type = lib.types.str; description = "NATS server URL"; example = "nats://nats.example.com:4222"; }; nkeyFile = lib.mkOption { type = lib.types.path; description = "Path to NKey seed file for NATS authentication"; example = "/run/secrets/homelab-deploy-nkey"; }; flakeUrl = lib.mkOption { type = lib.types.str; description = "Git flake URL for nixos-rebuild"; example = "git+https://git.example.com/user/nixos-configs.git"; }; timeout = lib.mkOption { type = lib.types.int; default = 600; description = "Deployment timeout in seconds"; }; deploySubjects = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "deploy.." "deploy..all" "deploy..role." ]; description = '' List of NATS subjects to subscribe to for deployment requests. Template variables: , , ''; }; discoverSubject = lib.mkOption { type = lib.types.str; default = "deploy.discover"; description = "NATS subject for host discovery requests"; }; environment = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = { }; description = "Additional environment variables for the service"; example = { GIT_SSH_COMMAND = "ssh -i /run/secrets/deploy-key"; }; }; }; config = lib.mkIf cfg.enable { systemd.services.homelab-deploy-listener = { description = "homelab-deploy listener"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; environment = cfg.environment; serviceConfig = { Type = "simple"; ExecStart = "${cfg.package}/bin/homelab-deploy listener ${args}"; Restart = "always"; RestartSec = 10; # Hardening (compatible with nixos-rebuild requirements) # Note: Some options are relaxed because nixos-rebuild requires: # - Write access to /nix/store for building # - Ability to activate system configurations # - Network access for fetching from git/cache # - Namespace support for nix sandbox builds NoNewPrivileges = false; ProtectSystem = "false"; ProtectHome = "read-only"; PrivateTmp = true; PrivateDevices = true; ProtectKernelTunables = true; ProtectKernelModules = true; ProtectControlGroups = true; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; RestrictNamespaces = false; RestrictSUIDSGID = true; LockPersonality = true; MemoryDenyWriteExecute = false; SystemCallArchitectures = "native"; }; }; }; }