{ config, pkgs, lib, ... }: with lib; let cfg = config.services.naxos.gitops; # Safe switch script with canary validation and automatic rollback naxosRebuildWrapper = pkgs.writeShellScriptBin "naxos-rebuild-safe" '' set -euo pipefail CONFIG_DIR="''${CONFIG_DIR:-/etc/naxos/repo}" LOG_FILE="/var/log/naxos-rebuild.log" echo "[$(date -Iseconds)] Starting NaxOS declarative rebuild..." | tee -a "$LOG_FILE" cd "$CONFIG_DIR" # Pre-flight check with nix flake check / nixos-rebuild dry-build echo "Running dry build validation..." if ! nixos-rebuild build --flake .#naxos 2>&1 | tee -a "$LOG_FILE"; then echo "Dry-build failed! Configuration aborted without changing running system." | tee -a "$LOG_FILE" exit 1 fi # Record current generation PREV_GEN=$(readlink -f /nix/var/nix/profiles/system) echo "Applying system switch..." if nixos-rebuild switch --flake .#naxos 2>&1 | tee -a "$LOG_FILE"; then echo "System switch succeeded." | tee -a "$LOG_FILE" # Canary health check: verify management daemon and storage pools are responsive if systemctl is-active --quiet naxos-api.service; then echo "Canary verification passed: NaxOS daemon active." | tee -a "$LOG_FILE" exit 0 else echo "WARNING: NaxOS daemon failed canary test! Initiating safe automatic rollback..." | tee -a "$LOG_FILE" "$PREV_GEN/bin/switch-to-configuration" switch exit 2 fi else echo "Switch command failed! Rolling back to $PREV_GEN..." | tee -a "$LOG_FILE" "$PREV_GEN/bin/switch-to-configuration" switch exit 3 fi ''; # Automated remote push/pull service naxosGitSync = pkgs.writeShellScriptBin "naxos-git-sync" '' set -euo pipefail REPO_DIR="/etc/naxos/repo" if [ ! -d "$REPO_DIR/.git" ]; then echo "Git repository not initialized in $REPO_DIR." exit 0 fi cd "$REPO_DIR" if [ -n "''${NAXOS_REMOTE_URL:-}" ]; then echo "Synchronizing with remote GitOps repository..." git fetch origin main || true git push origin main || true fi ''; in { options.services.naxos.gitops = { enable = mkEnableOption "NaxOS GitOps Configuration Synchronization Engine"; remoteUrl = mkOption { type = types.nullOr types.str; default = null; example = "ssh://git@git.lholz.de:2222/naxos/naxos-config.git"; description = "Remote Git repository URL for automated backup, auditing, and disaster recovery."; }; branch = mkOption { type = types.str; default = "main"; description = "GitOps target branch."; }; tokenFile = mkOption { type = types.nullOr types.str; default = null; description = "Path to Gitea/Git access token or SSH private key."; }; autoPushOnCommit = mkOption { type = types.bool; default = true; description = "Automatically push to remote repository whenever web dashboard commits a change."; }; }; config = mkIf cfg.enable { environment.systemPackages = with pkgs; [ git naxosRebuildWrapper naxosGitSync ]; # Create config repo directory structure systemd.tmpfiles.rules = [ "d /etc/naxos 0755 root root -" "d /etc/naxos/repo 0750 root root -" "d /var/log 0755 root root -" ]; }; }