]> git.scottworley.com Git - auto-upgrade-with-pinch/blobdiff - modules/auto-upgrade.nix
Narrow sudoers to runAs=root
[auto-upgrade-with-pinch] / modules / auto-upgrade.nix
index e41716b4387af0c8b91dbef3ff753d8701613435..7d2404cefb21183d7701854288d1c3b6fba35291 100644 (file)
@@ -4,7 +4,12 @@
 # under the terms of the GNU General Public License as published by the
 # Free Software Foundation, version 3.
 
 # under the terms of the GNU General Public License as published by the
 # Free Software Foundation, version 3.
 
-{ config, lib, pkgs, ... }:
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
 with lib;
 let
   local-pkgs = import ../. { inherit pkgs; };
 with lib;
 let
   local-pkgs = import ../. { inherit pkgs; };
@@ -65,39 +70,41 @@ let
   '';
 
   auto-upgrade-script = pkgs.writeShellScript "auto-upgrade" ''
   '';
 
   auto-upgrade-script = pkgs.writeShellScript "auto-upgrade" ''
-    ${pkgs.util-linux}/bin/flock /run/auto-upgrade-with-pinch ${
-      pkgs.writeShellScript "auto-upgrade-with-lock-held" ''
-        set -eo pipefail
-
-        dry_run=false
-        pinch_args=()
-        if [[ "$1" == --dry-run ]];then
-          dry_run=true
-          pinch_args=( --dry-run )
-        fi
-
-        hydrate() {
-          if "$dry_run";then
-            echo "Would run: $*"
-          else
-            "$@"
-          fi
-        }
-
-        die() {
-          echo "$*" >&2
-          exit 1
-        }
-
-        in_tmpdir() {
-          d=$(${pkgs.coreutils}/bin/mktemp -d)
-          pushd "$d"
+    ${pkgs.coreutils}/bin/nice -n 17 \
+    ${pkgs.util-linux}/bin/ionice -c 3 \
+    ${pkgs.util-linux}/bin/flock /run/auto-upgrade-with-pinch ${pkgs.writeShellScript "auto-upgrade-with-lock-held" ''
+      set -eo pipefail
+
+      dry_run=false
+      pinch_args=()
+      if [[ "$1" == --dry-run ]];then
+        dry_run=true
+        pinch_args=( --dry-run )
+      fi
+
+      hydrate() {
+        if "$dry_run";then
+          echo "Would run: $*"
+        else
           "$@"
           "$@"
-          popd
-          ${pkgs.coreutils}/bin/rm -r "$d"
-        }
-
-        ${optionalString (cfg.upgradeConfigOwnershipPolicy != "any") (''
+        fi
+      }
+
+      die() {
+        echo "$*" >&2
+        exit 1
+      }
+
+      in_tmpdir() {
+        d=$(${pkgs.coreutils}/bin/mktemp -d)
+        pushd "$d"
+        "$@"
+        popd
+        ${pkgs.coreutils}/bin/rm -r "$d"
+      }
+
+      ${optionalString (cfg.upgradeConfigOwnershipPolicy != "any") (
+        ''
           verify_ownership() {
             if [[ "$1" != /* ]];then
               die "Unexpected relative path: $1"
           verify_ownership() {
             if [[ "$1" != /* ]];then
               die "Unexpected relative path: $1"
@@ -143,63 +150,69 @@ let
                     fi
                   fi
                 '';
                     fi
                   fi
                 '';
-              }."${cfg.upgradeConfigOwnershipPolicy}"
+              }
+              ."${cfg.upgradeConfigOwnershipPolicy}"
             }
           }
         ''
             }
           }
         ''
-          + concatMapStringsSep "\n" (f: "verify_ownership ${escapeShellArg f}")
-          cfg.upgradeConfig)}
-
-        config=$(${pkgs.nix}/bin/nix-instantiate --eval --strict --json -A config \
-          --arg upgradeConfig ${
-            escapeShellArg ("["
-              + lib.concatMapStringsSep " " lib.strings.escapeNixString
-              cfg.upgradeConfig + "]")
-          } ${../upgrade-config.nix})
-
-        config_query() {
-          ${pkgs.jq}/bin/jq -r "$@" <<< "$config"
-        }
-
-        repo_query() {
-          config_query --arg path "$1" ".repos[\$ARGS.named.path]$2"
-        }
-
-        userenv_query() {
-          config_query --arg user "$1" ".userEnvironments[\$ARGS.named.user]$2"
-        }
-
-        # Pull updates
-        while read path;do
-          hydrate /run/wrappers/bin/sudo -u "$(repo_query "$path" .user)" \
-            ${pull-repo-script} "$path" "$(repo_query "$path" "")"
-        done < <( config_query '.repos | keys []' )
-
-        # Update channels
-        config_query '.pinchFiles[]' | ${pkgs.findutils}/bin/xargs --no-run-if-empty --delimiter=\\n ${pkgs.pinch}/bin/pinch update "''${pinch_args[@]}"
-
-        # Build
-        in_tmpdir hydrate ${config.system.build.nixos-rebuild}/bin/nixos-rebuild build
-        while read user;do
-          hydrate /run/wrappers/bin/sudo -u "$user" \
-            ${pkgs.nix}/bin/nix-build --no-out-link '<nixpkgs>' -A "$(userenv_query "$user" .package)"
-        done < <( config_query '.userEnvironments | keys []' )
-
-        # Install
-        hydrate ${config.system.build.nixos-rebuild}/bin/nixos-rebuild switch
-        while read user;do
-          remove_arg=-r
-          if [[ "$(userenv_query "$user" .otherPackagesAction)" == keep ]];then
-            remove_arg=
-          fi
-          hydrate /run/wrappers/bin/sudo -u "$user" \
-            ${pkgs.nix}/bin/nix-env -f '<nixpkgs>' $remove_arg -iA "$(userenv_query "$user" .package)"
-        done < <( config_query '.userEnvironments | keys []' )
-      ''
-    }
+        + concatMapStringsSep "\n" (f: "verify_ownership ${escapeShellArg f}") cfg.upgradeConfig
+      )}
+
+      config=$(${pkgs.nix}/bin/nix-instantiate --eval --strict --json -A config \
+        --arg upgradeConfig ${
+          escapeShellArg (
+            "[" + lib.concatMapStringsSep " " lib.strings.escapeNixString cfg.upgradeConfig + "]"
+          )
+        } ${../upgrade-config.nix})
+
+      config_query() {
+        ${pkgs.jq}/bin/jq -r "$@" <<< "$config"
+      }
+
+      repo_query() {
+        config_query --arg path "$1" ".repos[\$ARGS.named.path]$2"
+      }
+
+      userenv_query() {
+        config_query --arg user "$1" ".userEnvironments[\$ARGS.named.user]$2"
+      }
+
+      # Pull updates
+      while read path;do
+        hydrate /run/wrappers/bin/sudo -u "$(repo_query "$path" .user)" \
+          ${pull-repo-script} "$path" "$(repo_query "$path" "")"
+      done < <( config_query '.repos | keys []' )
+
+      # Update channels
+      config_query '.pinchFiles[]' | ${pkgs.findutils}/bin/xargs --no-run-if-empty --delimiter=\\n ${pkgs.pinch}/bin/pinch update "''${pinch_args[@]}"
+
+      # Build
+      in_tmpdir hydrate ${config.system.build.nixos-rebuild}/bin/nixos-rebuild build
+      while read user;do
+        pushd /
+        hydrate /run/wrappers/bin/sudo -u "$user" \
+          ${pkgs.nix}/bin/nix-build --no-out-link '<nixpkgs>' -A "$(userenv_query "$user" .package)"
+        popd
+      done < <( config_query '.userEnvironments | keys []' )
+      sync
+
+      # Install
+      hydrate ${config.system.build.nixos-rebuild}/bin/nixos-rebuild switch
+      sync
+      while read user;do
+        remove_arg=-r
+        if [[ "$(userenv_query "$user" .otherPackagesAction)" == keep ]];then
+          remove_arg=
+        fi
+        hydrate /run/wrappers/bin/sudo -u "$user" \
+          ${pkgs.nix}/bin/nix-env -f '<nixpkgs>' $remove_arg -iA "$(userenv_query "$user" .package)"
+        sync
+      done < <( config_query '.userEnvironments | keys []' )
+    ''}
   '';
 
   '';
 
-in {
+in
+{
   options = {
     system.autoUpgradeWithPinch = {
 
   options = {
     system.autoUpgradeWithPinch = {
 
@@ -245,7 +258,11 @@ in {
       };
 
       upgradeConfigOwnershipPolicy = mkOption {
       };
 
       upgradeConfigOwnershipPolicy = mkOption {
-        type = types.enum [ "root" "wheel" "any" ];
+        type = types.enum [
+          "root"
+          "wheel"
+          "any"
+        ];
         default = "root";
         description = ''
           Verify ownership of upgrade config files before using them for
         default = "root";
         description = ''
           Verify ownership of upgrade config files before using them for
@@ -261,13 +278,21 @@ in {
 
   config = lib.mkIf cfg.enable {
 
 
   config = lib.mkIf cfg.enable {
 
-    security.sudo.extraRules = lib.mkAfter [{
-      groups = [ "users" ];
-      commands = [{
-        command = "${auto-upgrade-script}";
-        options = [ "NOPASSWD" "NOSETENV" ];
-      }];
-    }];
+    security.sudo.extraRules = lib.mkAfter [
+      {
+        groups = [ "users" ];
+        runAs = "root";
+        commands = [
+          {
+            command = "${auto-upgrade-script}";
+            options = [
+              "NOPASSWD"
+              "NOSETENV"
+            ];
+          }
+        ];
+      }
+    ];
     # NOSETENV above still allows through ~17 vars, including PATH.  Block those
     # as well:
     security.sudo.extraConfig = ''
     # NOSETENV above still allows through ~17 vars, including PATH.  Block those
     # as well:
     security.sudo.extraConfig = ''
@@ -292,10 +317,13 @@ in {
       restartIfChanged = false;
       unitConfig.X-StopOnRemoval = false;
       serviceConfig.Type = "oneshot";
       restartIfChanged = false;
       unitConfig.X-StopOnRemoval = false;
       serviceConfig.Type = "oneshot";
-      environment = config.nix.envVars // {
-        inherit (config.environment.sessionVariables) NIX_PATH;
-        HOME = "/root";
-      } // config.networking.proxy.envVars;
+      environment =
+        config.nix.envVars
+        // {
+          inherit (config.environment.sessionVariables) NIX_PATH;
+          HOME = "/root";
+        }
+        // config.networking.proxy.envVars;
 
       path = with pkgs; [
         config.nix.package.out
 
       path = with pkgs; [
         config.nix.package.out