]> git.scottworley.com Git - auto-upgrade-with-pinch/blame_incremental - modules/auto-upgrade.nix
No-sudo, no-password auto-upgrade
[auto-upgrade-with-pinch] / modules / auto-upgrade.nix
... / ...
CommitLineData
1{ config, lib, pkgs, ... }:
2with lib;
3let
4 cfg = config.system.autoUpgradeWithPinch;
5 auto-upgrade-script = pkgs.writeShellScript "auto-upgrade" ''
6 flock /run/auto-upgrade-with-pinch ${
7 pkgs.writeShellScript "auto-upgrade-with-lock-held" ''
8 set -e
9 (
10 cd /etc/nixos
11 ${pkgs.keyedgit cfg.key}/bin/git pull --ff-only --verify-signatures
12 ${pkgs.pinch}/bin/pinch update channels
13 )
14
15 ${config.system.build.nixos-rebuild}/bin/nixos-rebuild switch --no-build-output
16 ''
17 }
18 '';
19in {
20 options = {
21 system.autoUpgradeWithPinch = {
22
23 enable = mkOption {
24 type = types.bool;
25 default = false;
26 description = ''
27 Whether to periodically upgrade NixOS to the latest version.
28 Presumes that /etc/nixos is a git repo with a remote and
29 contains a pinch file called "channels".
30 '';
31 };
32
33 dates = mkOption {
34 default = "04:40";
35 type = types.str;
36 description = ''
37 Specification (in the format described by
38 <citerefentry><refentrytitle>systemd.time</refentrytitle>
39 <manvolnum>7</manvolnum></citerefentry>) of the time at
40 which the update will occur.
41 '';
42 };
43
44 key = mkOption {
45 type = types.path;
46 description = ''
47 GPG key that signs updates. Updates are only merged if the commit
48 at the tip of the remote branch is signed with this key.
49 '';
50 };
51 };
52 };
53
54 config = lib.mkIf cfg.enable {
55
56 security.sudo.extraRules = lib.mkAfter [{
57 groups = [ "users" ];
58 commands = [{
59 command = "${auto-upgrade-script}";
60 options = [ "NOPASSWD" "NOSETENV" ];
61 }];
62 }];
63 # NOSETENV above still allows through ~17 vars, including PATH. Block those
64 # as well:
65 security.sudo.extraConfig = ''
66 Defaults!${auto-upgrade-script} !env_check
67 Defaults!${auto-upgrade-script} !env_keep
68 '';
69
70 nixpkgs.overlays = [
71 (import ../overlays/keyedgit.nix)
72 (import ../overlays/pinch.nix)
73 (self: super: {
74 auto-upgrade = super.writeShellScriptBin "auto-upgrade" ''
75 sudo ${auto-upgrade-script}
76 '';
77 })
78 ];
79
80 environment.systemPackages = [ pkgs.auto-upgrade ];
81
82 systemd.services.nixos-upgrade = {
83 description = "NixOS Upgrade";
84 restartIfChanged = false;
85 unitConfig.X-StopOnRemoval = false;
86 serviceConfig.Type = "oneshot";
87 environment = config.nix.envVars // {
88 inherit (config.environment.sessionVariables) NIX_PATH;
89 HOME = "/root";
90 } // config.networking.proxy.envVars;
91
92 path = with pkgs; [
93 config.nix.package.out
94 coreutils
95 git
96 gitMinimal
97 gnutar
98 gzip
99 xz.bin
100 ];
101
102 script = ''
103 set -e
104
105 # Chill for awhile before applying updates. If applying an update
106 # badly breaks things, we want a window in which an operator can
107 # intervene either to fix the problem or disable automatic updates.
108 sleep 2h
109
110 # Wait until outside business hours
111 now=$(date +%s)
112 day_of_week=$(date +%u)
113 business_start=$(date -d 8:00 +%s)
114 business_end=$( date -d 17:00 +%s)
115 if (( day_of_week <= 5 && now > business_start && now < business_end ));then
116 delay=$((business_end - now))
117 echo "Waiting $delay seconds so we don't upgrade during business hours" >&2
118 sleep "$delay"
119 fi
120
121 ${auto-upgrade-script}
122 '';
123
124 startAt = cfg.dates;
125 };
126 };
127}