{ config, lib, pkgs, ... }: let flake = "github:lassulus/superconfig"; # system.autoUpgrade switches to whatever the flake currently evaluates to, # forwards or backwards. A machine deployed from an unpushed local checkout # therefore gets reverted to the older remote HEAD on the next timer run. # Refuse to move backwards in time: only upgrade to a revision committed # after the running system was deployed. The deploy time is when its profile # generation was created (/run/current-system's mtime if no generation points # at it); the source's own lastModified is no use, since `clan machines # update` builds from a path: flake, which has none. guard = pkgs.writeShellApplication { name = "autoupgrade-forward-only"; runtimeInputs = [ config.nix.package pkgs.coreutils pkgs.jq ]; text = '' system=$(readlink -f /run/current-system) deployed=0 for link in /nix/var/nix/profiles/system-*-link; do if [ "$(readlink -f "$link")" = "$system" ]; then created=$(stat -c %Y "$link") if [ "$created" -gt "$deployed" ]; then deployed=$created; fi fi done if [ "$deployed" -eq 0 ]; then deployed=$(stat -c %Y /run/current-system); fi if ! meta=$(nix flake metadata --refresh --json ${lib.escapeShellArg flake}); then echo "autoupgrade: cannot reach ${flake}; letting nixos-upgrade report the error" exit 0 fi remote=$(jq -r '.lastModified // 0' <<<"$meta") if [ "$remote" -gt "$deployed" ]; then exit 0 fi echo "autoupgrade: ${flake} is at $remote, running system was deployed at $deployed; skipping" exit 1 ''; }; in { system.autoUpgrade = { enable = true; inherit flake; randomizedDelaySec = "6h"; }; systemd.services.nixos-upgrade.serviceConfig.ExecCondition = lib.getExe guard; }