]> git.scottworley.com Git - auto-upgrade-with-pinch/blame - modules/auto-upgrade.nix
Accept multiple signing keys
[auto-upgrade-with-pinch] / modules / auto-upgrade.nix
CommitLineData
901670f5
SW
1{ config, lib, pkgs, ... }:
2with lib;
364c110c
SW
3let
4 cfg = config.system.autoUpgradeWithPinch;
5 auto-upgrade-script = pkgs.writeShellScript "auto-upgrade" ''
2b58720b 6 ${pkgs.utillinux}/bin/flock /run/auto-upgrade-with-pinch ${
364c110c
SW
7 pkgs.writeShellScript "auto-upgrade-with-lock-held" ''
8 set -e
eb0fa99c
SW
9
10 in_tmpdir() {
11 d=$(mktemp -d)
12 pushd "$d"
13 "$@"
14 popd
15 rm -r "$d"
16 }
17
18 as_user() {
19 ${
20 if cfg.userEnvironment.enable then ''
4acf153c 21 /run/wrappers/bin/sudo -u ${escapeShellArg cfg.userEnvironment.user} "$@"
eb0fa99c
SW
22 '' else ''
23 :
24 ''
25 }
26 }
27
28 # Update channels
364c110c
SW
29 (
30 cd /etc/nixos
9d0c0d71 31 ${pkgs.keyedgit cfg.keys}/bin/git pull --ff-only --verify-signatures
364c110c
SW
32 ${pkgs.pinch}/bin/pinch update channels
33 )
34
eb0fa99c
SW
35 # Build
36 in_tmpdir ${config.system.build.nixos-rebuild}/bin/nixos-rebuild build
b972908a 37 as_user nix-build --no-out-link '<nixpkgs>' -A ${
eb0fa99c
SW
38 escapeShellArg cfg.userEnvironment.package
39 }
40
41 # Install
42 ${config.system.build.nixos-rebuild}/bin/nixos-rebuild switch
43 as_user nix-env -f '<nixpkgs>' -riA ${
44 escapeShellArg cfg.userEnvironment.package
45 }
364c110c
SW
46 ''
47 }
48 '';
901670f5
SW
49in {
50 options = {
51 system.autoUpgradeWithPinch = {
52
53 enable = mkOption {
54 type = types.bool;
55 default = false;
56 description = ''
57 Whether to periodically upgrade NixOS to the latest version.
58 Presumes that /etc/nixos is a git repo with a remote and
59 contains a pinch file called "channels".
60 '';
61 };
62
63 dates = mkOption {
64 default = "04:40";
65 type = types.str;
66 description = ''
67 Specification (in the format described by
68 <citerefentry><refentrytitle>systemd.time</refentrytitle>
69 <manvolnum>7</manvolnum></citerefentry>) of the time at
70 which the update will occur.
71 '';
72 };
d8537205 73
9d0c0d71 74 keys = mkOption {
d8537205
SW
75 type = types.path;
76 description = ''
9d0c0d71
SW
77 File containing GPG keys that sign updates. Updates are only merged
78 if the commit at the tip of the remote branch is signed with one of
79 these keys.
d8537205
SW
80 '';
81 };
eb0fa99c
SW
82
83 userEnvironment = {
84 enable = mkOption {
85 type = types.bool;
86 default = false;
87 description = ''
88 Whether to update a user-environment as well. This update is done
89 with nix-env -riA. Note the -r! I.e., ALL OTHER PACKAGES INSTALLED
90 WITH nix-env WILL BE DELETED!
91
92 This presumes that you have configured an "entire user environment"
93 package as shown in
94 https://nixos.wiki/wiki/FAQ#How_can_I_manage_software_with_nix-env_like_with_configuration.nix.3F
95
96 To check if you're set up for this, run "nix-env --query". If it
97 only lists one package, you're good to go.
98 '';
99 };
100
101 user = mkOption {
102 type = types.str;
103 description = ''
104 The username of the user whose environment should be updated.
105 '';
106 };
107
108 package = mkOption {
109 type = types.str;
110 example = "nixos.userPackages";
111 description = ''
112 The name of the single package that is the user's entire environment.
113 '';
114 };
115
116 };
901670f5
SW
117 };
118 };
119
120 config = lib.mkIf cfg.enable {
364c110c
SW
121
122 security.sudo.extraRules = lib.mkAfter [{
123 groups = [ "users" ];
124 commands = [{
125 command = "${auto-upgrade-script}";
126 options = [ "NOPASSWD" "NOSETENV" ];
127 }];
128 }];
129 # NOSETENV above still allows through ~17 vars, including PATH. Block those
130 # as well:
131 security.sudo.extraConfig = ''
132 Defaults!${auto-upgrade-script} !env_check
133 Defaults!${auto-upgrade-script} !env_keep
134 '';
135
d8537205
SW
136 nixpkgs.overlays = [
137 (import ../overlays/keyedgit.nix)
138 (import ../overlays/pinch.nix)
5aaf4680
SW
139 (self: super: {
140 auto-upgrade = super.writeShellScriptBin "auto-upgrade" ''
4acf153c 141 /run/wrappers/bin/sudo ${auto-upgrade-script}
5aaf4680
SW
142 '';
143 })
d8537205 144 ];
5aaf4680
SW
145
146 environment.systemPackages = [ pkgs.auto-upgrade ];
147
901670f5
SW
148 systemd.services.nixos-upgrade = {
149 description = "NixOS Upgrade";
150 restartIfChanged = false;
151 unitConfig.X-StopOnRemoval = false;
152 serviceConfig.Type = "oneshot";
153 environment = config.nix.envVars // {
154 inherit (config.environment.sessionVariables) NIX_PATH;
155 HOME = "/root";
156 } // config.networking.proxy.envVars;
157
158 path = with pkgs; [
159 config.nix.package.out
160 coreutils
161 git
162 gitMinimal
163 gnutar
164 gzip
901670f5
SW
165 xz.bin
166 ];
167
168 script = ''
169 set -e
8569b965
SW
170
171 # Chill for awhile before applying updates. If applying an update
172 # badly breaks things, we want a window in which an operator can
173 # intervene either to fix the problem or disable automatic updates.
174 sleep 2h
175
f43ffe15
SW
176 # Wait until outside business hours
177 now=$(date +%s)
178 day_of_week=$(date +%u)
179 business_start=$(date -d 8:00 +%s)
180 business_end=$( date -d 17:00 +%s)
181 if (( day_of_week <= 5 && now > business_start && now < business_end ));then
182 delay=$((business_end - now))
183 echo "Waiting $delay seconds so we don't upgrade during business hours" >&2
184 sleep "$delay"
185 fi
186
364c110c 187 ${auto-upgrade-script}
901670f5
SW
188 '';
189
190 startAt = cfg.dates;
191 };
eb0fa99c
SW
192
193 assertions = [{
194 assertion = cfg.userEnvironment.enable -> cfg.enable;
195 message =
196 "User environment upgrades cannot yet be enabled separately from system upgrades.";
197 }];
901670f5
SW
198 };
199}