diff --git a/flake-parts/lib.nix b/flake-parts/lib.nix index c330513..64c7a4d 100644 --- a/flake-parts/lib.nix +++ b/flake-parts/lib.nix @@ -11,8 +11,11 @@ genAttrs = f: names: lib.genAttrs names f; + mkInvalidConfigMessage = subject: reason: "Invalid configuration for ${subject}: ${reason}."; + mkUnprotectedMessage = - name: "${name} should only be exposed on private networks; access control isn't yet configured"; + name: + self.lib.mkInvalidConfigMessage name "the service must use a private domain until access control is configured"; relativePath = path: path |> toString |> lib.removePrefix "${self}/"; diff --git a/modules/home/services/ntfy-client.nix b/modules/home/services/ntfy-client.nix index e7e08e5..60639cc 100644 --- a/modules/home/services/ntfy-client.nix +++ b/modules/home/services/ntfy-client.nix @@ -58,7 +58,7 @@ in systemd.user.services.ntfy-client = { Install.WantedBy = [ "graphical-session.target" ]; Unit = { - Description = "ntfy client subscriber"; + Description = "ntfy client subscription"; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" ]; X-Restart-Triggers = [ config.xdg.configFile."ntfy/client.yml".source ]; diff --git a/modules/home/sops.nix b/modules/home/sops.nix index ff3cf3b..d33ed0a 100644 --- a/modules/home/sops.nix +++ b/modules/home/sops.nix @@ -26,7 +26,7 @@ in default = "${self}/users/${config.home.username}/@${osConfig.networking.hostName}/secrets.json"; }; secretsData = lib.mkOption { - type = lib.types.anything; + type = lib.types.attrs; default = cfg.secretsFile |> lib.readFile |> lib.strings.fromJSON; }; }; @@ -43,7 +43,7 @@ in |> lib.attrNames |> lib.map (secretPath: { assertion = cfg.secretsData |> lib.hasAttrByPath (secretPath |> lib.splitString "/"); - message = "Sops secret `${secretPath}` is used in a module but not defined in secrets.json"; + message = self.lib.mkInvalidConfigMessage "SOPS secret `${secretPath}`" "it is used in a module but not defined in `secrets.json`"; }) ) ++ ( @@ -51,7 +51,7 @@ in |> lib.mapAttrsToListRecursive (path: _: path |> lib.concatStringsSep "/") |> lib.map (secretPath: { assertion = config.sops.secrets |> lib.hasAttr secretPath; - message = "Sops secret `${secretPath}` is defined in secrets.json but not used in any module"; + message = self.lib.mkInvalidConfigMessage "SOPS secret `${secretPath}`" "it is defined in `secrets.json` but not used in any module"; }) ); }; diff --git a/modules/nixos/networking/default.nix b/modules/nixos/networking/default.nix index e6bb605..653e790 100644 --- a/modules/nixos/networking/default.nix +++ b/modules/nixos/networking/default.nix @@ -16,7 +16,7 @@ in }; nodes = lib.mkOption { - type = lib.types.anything; + type = lib.types.listOf lib.types.attrs; default = allHosts |> lib.attrValues @@ -31,7 +31,7 @@ in readOnly = true; }; peers = lib.mkOption { - type = lib.types.anything; + type = lib.types.listOf lib.types.attrs; default = cfg.nodes |> lib.filter (node: node.hostName != cfg.hostName); readOnly = true; }; diff --git a/modules/nixos/networking/overlay.nix b/modules/nixos/networking/overlay.nix index 42b7afa..007e012 100644 --- a/modules/nixos/networking/overlay.nix +++ b/modules/nixos/networking/overlay.nix @@ -59,7 +59,7 @@ in }; dnsServers = lib.mkOption { - type = lib.types.anything; + type = lib.types.listOf lib.types.nonEmptyStr; default = allHosts |> lib.attrValues diff --git a/modules/nixos/services/alloy.nix b/modules/nixos/services/alloy.nix index 9445f85..9412cb1 100644 --- a/modules/nixos/services/alloy.nix +++ b/modules/nixos/services/alloy.nix @@ -1,5 +1,6 @@ { config, + self, lib, allHosts, ... @@ -38,7 +39,7 @@ in |> lib.filter (name: name != "system") |> lib.map (name: { assertion = cfg.collect.metrics.${name} -> config.services.${name}.enable; - message = "Alloy cannot collect `${name}` metrics without the `${name}` service"; + message = self.lib.mkInvalidConfigMessage "Alloy metric collection for `${name}`" "the `${name}` service is not enabled"; }); services.alloy = { diff --git a/modules/nixos/services/caddy.nix b/modules/nixos/services/caddy.nix index 10f1bdc..3a2062a 100644 --- a/modules/nixos/services/caddy.nix +++ b/modules/nixos/services/caddy.nix @@ -91,11 +91,11 @@ in |> lib.concatMap (vHost: [ { assertion = (vHost.port == null) || (vHost.files == null); - message = "Caddy virtual host `${vHost.domain}` cannot set both `port` and `files`"; + message = self.lib.mkInvalidConfigMessage "Caddy virtual host `${vHost.domain}`" "`port` and `files` cannot be set at the same time"; } { assertion = (vHost.port != null) || (vHost.files != null) || (vHost.extraConfig != null); - message = "Caddy virtual host `${vHost.domain}` must set at least one of `port`, `files` or `extraConfig`"; + message = self.lib.mkInvalidConfigMessage "Caddy virtual host `${vHost.domain}`" "one of `port`, `files` or `extraConfig` must be set"; } ]); diff --git a/modules/nixos/services/nebula/default.nix b/modules/nixos/services/nebula/default.nix index d361d3d..7b96f61 100644 --- a/modules/nixos/services/nebula/default.nix +++ b/modules/nixos/services/nebula/default.nix @@ -62,7 +62,7 @@ in config = lib.mkIf cfg.enable { assertions = lib.singleton { assertion = netCfg.overlay.isLighthouse -> cfg.advertise.address != null; - message = "`${netCfg.hostName}` is a Nebula lighthouse, but `underlay.isPublic` or `overlay.advertise.address` are not set. Lighthouses must be publicly reachable."; + message = self.lib.mkInvalidConfigMessage "Nebula lighthouse `${netCfg.hostName}`" "`underlay.isPublic` must be enabled or `services.nebula.advertise.address` must be set so the host is publicly reachable"; }; sops.secrets."nebula/host-key" = lib.mkIf (cfg.privateKeyFile == null) { diff --git a/modules/nixos/services/prometheus.nix b/modules/nixos/services/prometheus.nix index f7cb64d..c973447 100644 --- a/modules/nixos/services/prometheus.nix +++ b/modules/nixos/services/prometheus.nix @@ -96,10 +96,10 @@ in expr = ''absent_over_time(up{instance="${hostName}", job="node"}[2m])''; labels.severity = "critical"; annotations = { - summary = "${hostName} is DOWN"; - summary_resolved = "${hostName} is up again"; - description = "No metrics received for over 2 minutes."; - description_resolved = "Metrics are being received again."; + summary = "Host ${hostName} is down"; + summary_resolved = "Host ${hostName} is up again"; + description = "Prometheus has not received node metrics from ${hostName} for 2 minutes."; + description_resolved = "Prometheus is receiving node metrics from ${hostName} again."; }; }) ) @@ -109,20 +109,20 @@ in expr = ''up{job=~"prometheus|alertmanager"} == 0''; for = "2m"; annotations = { - summary = "{{ $labels.job | title }} on {{ $labels.instance }} is DOWN"; - summary_resolved = "{{ $labels.job | title }} on {{ $labels.instance }} is up again"; - description = "Unresponsive for over 2 minutes."; - description_resolved = "Responding normally."; + summary = "Service {{ $labels.job | title }} on {{ $labels.instance }} is down"; + summary_resolved = "Service {{ $labels.job | title }} on {{ $labels.instance }} is up again"; + description = "Prometheus has not received scrape data for 2 minutes."; + description_resolved = "Prometheus is receiving scrape data again."; }; } { alert = "CominDeploymentFailed"; expr = ''comin_deployment_info{status!="done"}''; annotations = { - summary = "{{ $labels.instance }} deployment failed"; - summary_resolved = "{{ $labels.instance }} deployment recovered"; - description = "Deployment is not reaching \"done\" status."; - description_resolved = "Deployment completed successfully."; + summary = "Deployment on {{ $labels.instance }} failed"; + summary_resolved = "Deployment on {{ $labels.instance }} succeeded again"; + description = "Comin reports a deployment status other than \"done\"."; + description_resolved = "Comin reports the deployment status as \"done\" again."; }; } { @@ -130,10 +130,10 @@ in expr = "count(count by (commit_id) (comin_deployment_info)) > 1"; for = "10m"; annotations = { - summary = "Hosts are running different commits"; - summary_resolved = "All hosts are running the same commit again"; - description = "Possibly a failed deployment or incompatible configurations."; - description_resolved = "All hosts are in sync."; + summary = "Deployment commits are out of sync"; + summary_resolved = "Deployment commits are in sync again"; + description = "Comin reports different deployed commits across hosts."; + description_resolved = "Comin reports the same deployed commit across all hosts again."; }; } ]; diff --git a/modules/nixos/services/restic/backups.nix b/modules/nixos/services/restic/backups.nix index d0ff1c9..51001d3 100644 --- a/modules/nixos/services/restic/backups.nix +++ b/modules/nixos/services/restic/backups.nix @@ -31,7 +31,7 @@ in default = [ ]; }; extraConfig = lib.mkOption { - type = lib.types.attrsOf lib.types.anything; + type = lib.types.attrs; default = { }; }; }; diff --git a/modules/nixos/services/restic/healthchecks.nix b/modules/nixos/services/restic/healthchecks.nix index 5f60bc6..8cd1711 100644 --- a/modules/nixos/services/restic/healthchecks.nix +++ b/modules/nixos/services/restic/healthchecks.nix @@ -26,7 +26,7 @@ in systemd.services = { "healthcheck-ping@" = { - description = "Pings healthcheck (%i)"; + description = "Ping Healthchecks for %i"; serviceConfig.Type = "oneshot"; scriptArgs = "%i"; script = '' diff --git a/modules/nixos/sops.nix b/modules/nixos/sops.nix index 1dd2c27..4753628 100644 --- a/modules/nixos/sops.nix +++ b/modules/nixos/sops.nix @@ -22,7 +22,7 @@ in default = "${self}/hosts/${config.networking.hostName}/secrets.json"; }; secretsData = lib.mkOption { - type = lib.types.anything; + type = lib.types.attrs; default = cfg.secretsFile |> lib.readFile |> lib.strings.fromJSON; }; }; @@ -41,7 +41,7 @@ in |> lib.attrNames |> lib.map (secretPath: { assertion = cfg.secretsData |> lib.hasAttrByPath (secretPath |> lib.splitString "/"); - message = "Sops secret `${secretPath}` is used in a module but not defined in secrets.json"; + message = self.lib.mkInvalidConfigMessage "SOPS secret `${secretPath}`" "it is used in a module but not defined in `secrets.json`"; }) ) ++ ( @@ -49,7 +49,7 @@ in |> lib.mapAttrsToListRecursive (path: _: path |> lib.concatStringsSep "/") |> lib.map (secretPath: { assertion = config.sops.secrets |> lib.hasAttr secretPath; - message = "Sops secret `${secretPath}` is defined in secrets.json but not used in any module"; + message = self.lib.mkInvalidConfigMessage "SOPS secret `${secretPath}`" "it is defined in `secrets.json` but not used in any module"; }) ); };