From 3ca4d4fb86301297fcd059f8dd1006c2c9a39225 Mon Sep 17 00:00:00 2001 From: yukkop Date: Sun, 26 Apr 2026 22:22:15 +0000 Subject: [PATCH] feat: `sentinella`: update --- .sops.yaml | 14 +++++ nixos/module/hectic/service/sentinèlla.nix | 16 +++++- nixos/system/hectic-lab/sentinèlla.nix | 12 ++--- script/update-sops-keys | 63 ++++++++++++++++++++++ sus/sentinella-default.yaml | 5 ++ 5 files changed, 99 insertions(+), 11 deletions(-) create mode 100755 script/update-sops-keys create mode 100644 sus/sentinella-default.yaml diff --git a/.sops.yaml b/.sops.yaml index 2817144..2c95680 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -47,6 +47,20 @@ creation_rules: - *hectic-lab-server - *umbriel-bfs + - path_regex: sus/sentinella-default.yaml$ + key_groups: + - age: + - *yukkop + - *yukkop-alt + - *nrv + - *bfs-server + - *bfs-pol-server + - *bfs-new-server + - *neuro-server + - *games-server + - *hectic-lab-server + - *umbriel-bfs + - path_regex: docs/.*\.md$ key_groups: - age: diff --git a/nixos/module/hectic/service/sentinèlla.nix b/nixos/module/hectic/service/sentinèlla.nix index 6ffa835..bdc28a0 100644 --- a/nixos/module/hectic/service/sentinèlla.nix +++ b/nixos/module/hectic/service/sentinèlla.nix @@ -100,10 +100,18 @@ in { }; environmentFile = lib.mkOption { type = with lib.types; nullOr path; - default = null; + default = config.sops.secrets."sentinèlla/watcher/environment".path; + defaultText = lib.literalExpression + "config.sops.secrets.\"sentinèlla/watcher/environment\".path"; example = "config.sops.secrets.\"sentinella-watcher-env\".path"; description = '' - Optional environment file for secrets. Supported variables: + Environment file for secrets. Defaults to the auto-declared SOPS + secret sentinèlla/watcher/environment (resolved from + sus/sentinella-default.yaml in the flake). Override the sopsFile + via sops.secrets."sentinèlla/watcher/environment".sopsFile if you + need a host-specific file instead. + + Supported variables: TG_TOKEN= TG_CHAT_ID= PEERS_TOKEN= # Basic Auth token sent to all peers @@ -148,6 +156,10 @@ in { }) (lib.mkIf cfg.watcher.enable { + sops.secrets."sentinèlla/watcher/environment" = lib.mkDefault { + sopsFile = "${flake}/sus/sentinella-default.yaml"; + }; + systemd.services."sentinella-watcher" = { description = "sentinèlla watcher — p2p peer monitor"; after = [ "network.target" ]; diff --git a/nixos/system/hectic-lab/sentinèlla.nix b/nixos/system/hectic-lab/sentinèlla.nix index 17a4c71..7054564 100644 --- a/nixos/system/hectic-lab/sentinèlla.nix +++ b/nixos/system/hectic-lab/sentinèlla.nix @@ -5,7 +5,7 @@ domain, sslOpts, ... -}: { config, ... }: let +}: { ... }: let port = 5869; in { hectic.services."sentinèlla" = { @@ -18,17 +18,11 @@ in { peersDns = "peers.${domain}"; peersPort = port; pollingIntervalSec = 60; - # TG_TOKEN= and TG_CHAT_ID= are set via this environment file - # Add the following to sus/hectic-lab.yaml under sentinèlla/watcher/: - # environment: | - # TG_TOKEN= - # TG_CHAT_ID= - environmentFile = config.sops.secrets."sentinèlla/watcher/environment".path; + # TG_TOKEN= and TG_CHAT_ID= are read from sus/sentinella-default.yaml + # (auto-declared by the module as sops.secrets."sentinèlla/watcher/environment") }; }; - sops.secrets."sentinèlla/watcher/environment" = {}; - services.nginx = { virtualHosts."probe.${domain}" = sslOpts // { forceSSL = true; diff --git a/script/update-sops-keys b/script/update-sops-keys new file mode 100755 index 0000000..0114bbb --- /dev/null +++ b/script/update-sops-keys @@ -0,0 +1,63 @@ +#!/usr/bin/env sh +# Update SOPS keys for every encrypted file in the project. +# Discovers files by matching path_regex rules from .sops.yaml — +# no directories are hardcoded. +# +# Usage: script/update-sops-keys [--dry-run] +set -eu + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +DRY_RUN=0 + +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=1 ;; + *) printf 'unknown argument: %s\n' "$arg" >&2; exit 9 ;; + esac +done + +SOPS_CONFIG="$REPO_ROOT/.sops.yaml" + +if [ ! -f "$SOPS_CONFIG" ]; then + printf 'error: .sops.yaml not found at %s\n' "$SOPS_CONFIG" >&2 + exit 1 +fi + +# Extract every path_regex value from .sops.yaml. +# Lines look like: - path_regex: some/pattern$ +regexes="$(grep '^\s*-\s*path_regex:' "$SOPS_CONFIG" | sed 's/.*path_regex:[[:space:]]*//')" + +if [ -z "$regexes" ]; then + printf 'no path_regex rules found in .sops.yaml\n' >&2 + exit 0 +fi + +# Collect all repo files (committed + untracked, excluding .gitignore). +# Write matches to a temp file to avoid subshell variable scoping issues. +tmp="$(mktemp)" +trap 'rm -f "$tmp"' EXIT + +git -C "$REPO_ROOT" ls-files --cached --others --exclude-standard | while read -r rel; do + for regex in $regexes; do + if printf '%s\n' "$rel" | grep -qE "$regex"; then + printf '%s\n' "$rel" >> "$tmp" + break + fi + done +done + +if [ ! -s "$tmp" ]; then + printf 'no matching sops files found\n' + exit 0 +fi + +while read -r rel; do + abs="$REPO_ROOT/$rel" + [ -f "$abs" ] || continue + if [ "$DRY_RUN" -eq 1 ]; then + printf '[dry-run] would updatekeys: %s\n' "$rel" + else + printf 'updating keys: %s\n' "$rel" + sops updatekeys --yes "$abs" + fi +done < "$tmp" diff --git a/sus/sentinella-default.yaml b/sus/sentinella-default.yaml new file mode 100644 index 0000000..bb9e309 --- /dev/null +++ b/sus/sentinella-default.yaml @@ -0,0 +1,5 @@ +sentinèlla: + watcher: + environment: | + TG_TOKEN= + TG_CHAT_ID=