diff --git a/modules/networking/default.nix b/modules/networking/default.nix index b53a9e4a7..7a81ca1c8 100644 --- a/modules/networking/default.nix +++ b/modules/networking/default.nix @@ -118,6 +118,7 @@ in echo "configuring networking..." >&2 ${optionalString (cfg.computerName != null) '' + # shellcheck disable=SC1112 scutil --set ComputerName ${escapeShellArg cfg.computerName} ''} ${optionalString (cfg.hostName != null) '' diff --git a/modules/services/buildkite-agents.nix b/modules/services/buildkite-agents.nix index 4888247e9..69bc1f65d 100644 --- a/modules/services/buildkite-agents.nix +++ b/modules/services/buildkite-agents.nix @@ -237,7 +237,7 @@ in tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags); in optionalString (cfg.privateSshKeyPath != null) '' - mkdir -m 0700 -p "${sshDir}" + mkdir -m 0700 "${sshDir}" install -m600 "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa" '' + '' cat > "${cfg.dataDir}/buildkite-agent.cfg" <&2 "setting up GitHub Runner '${cfg.name}'..." - ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkStateDir cfg)} - ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkStateDir cfg)} - - ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkLogDir cfg)} - ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkLogDir cfg)} - '' + optionalString (cfg.workDir == null) '' - ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkWorkDir cfg)} - ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkWorkDir cfg)} + ( + umask -S u=rwx,g=rx,o= + + ${pkgs.coreutils}/bin/mkdir -p ${escapeShellArg (mkStateDir cfg)} + ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkStateDir cfg)} + + ${pkgs.coreutils}/bin/mkdir -p ${escapeShellArg (mkLogDir cfg)} + ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkLogDir cfg)} + + ${optionalString (cfg.workDir == null) '' + ${pkgs.coreutils}/bin/mkdir -p ${escapeShellArg (mkWorkDir cfg)} + ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkWorkDir cfg)} + ''} + ) ''); }; })); diff --git a/modules/system/base.nix b/modules/system/base.nix index 44a8d912b..43c9d7ff9 100644 --- a/modules/system/base.nix +++ b/modules/system/base.nix @@ -2,22 +2,46 @@ { system.activationScripts.createRun.text = '' - if ! test -L /run; then - if ! grep -q '^run\b' /etc/synthetic.conf 2>/dev/null; then + if [[ ! -L /run ]]; then + # This file doesn't exist by default on macOS and is only supported after 10.15 + # however every system with Nix installed should have this file otherwise `/nix` + # wouldn't exist. + if [[ -e /etc/synthetic.conf ]]; then + if ! grep -q '^run\b' /etc/synthetic.conf 2>/dev/null; then echo "setting up /run via /etc/synthetic.conf..." - echo -e "run\tprivate/var/run" | sudo tee -a /etc/synthetic.conf >/dev/null - sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B &>/dev/null || true - sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t &>/dev/null || true - if ! test -L /run; then - echo "warning: apfs.util failed to symlink /run" - fi - fi - if ! test -L /run; then - echo "setting up /run..." - sudo ln -sfn private/var/run /run - fi - if ! test -L /run; then - echo "warning: failed to symlink /run" + printf 'run\tprivate/var/run\n' | sudo tee -a /etc/synthetic.conf >/dev/null + fi + + # for Catalina (10.15) + sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B &>/dev/null || true + # for Big Sur (11.0) + sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t &>/dev/null || true + + if [[ ! -L /run ]]; then + printf >&2 'error: apfs.util failed to symlink /run, aborting activation\n' + printf >&2 'To create a symlink from /run to /var/run, please run:\n' + printf >&2 '\n' + printf >&2 "$ printf 'run\tprivate/var/run\n' | sudo tee -a /etc/synthetic.conf" + printf >&2 '$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B # For Catalina\n' + printf >&2 '$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t # For Big Sur and later\n' >&2 + printf >&2 '\n' + printf >&2 'The current contents of /etc/synthetic.conf is:\n' + printf >&2 '\n' + sudo sed 's/^/ /' /etc/synthetic.conf >&2 + printf >&2 '\n' + exit 1 + fi + else + echo "setting up /run..." + sudo ln -sfn private/var/run /run + + if [[ ! -L /run ]]; then + printf >&2 'error: failed to symlink /run, aborting activation\n' + printf >&2 'To create a symlink from /run to /var/run, please run:\n' + printf >&2 '\n' + printf >&2 '$ sudo ln -sfn private/var/link /run\n' + exit 1 + fi fi fi ''; diff --git a/modules/system/checks.nix b/modules/system/checks.nix index 497cd9a97..ec6e3b5dc 100644 --- a/modules/system/checks.nix +++ b/modules/system/checks.nix @@ -22,25 +22,9 @@ let ''; runLink = '' - if ! test -e /run; then - echo "error: Directory /run does not exist, aborting activation" >&2 - echo "Create a symlink to /var/run with:" >&2 - if test -e /etc/synthetic.conf; then - echo >&2 - echo "$ printf 'run\tprivate/var/run\n' | sudo tee -a /etc/synthetic.conf" >&2 - echo "$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -B # For Catalina" >&2 - echo "$ sudo /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -t # For Big Sur and later" >&2 - echo >&2 - echo "The current contents of /etc/synthetic.conf is:" >&2 - echo >&2 - sed 's/^/ /' /etc/synthetic.conf >&2 - echo >&2 - else - echo >&2 - echo "$ sudo ln -s private/var/run /run" >&2 - echo >&2 - fi - exit 2 + if [[ ! -e /run ]]; then + printf >&2 'error: directory /run does not exist, aborting activation\n' + exit 1 fi ''; @@ -59,7 +43,7 @@ let exit 2 fi ''; - + preSequoiaBuildUsers = '' ${lib.optionalString config.nix.configureBuildUsers '' # Don’t complain when we’re about to migrate old‐style build users… @@ -104,7 +88,7 @@ let buildUsers = '' buildUser=$(dscl . -read /Groups/nixbld GroupMembership 2>&1 | awk '/^GroupMembership: / {print $2}') || true - if [ -z $buildUser ]; then + if [[ -z "$buildUser" ]]; then echo "error: Using the nix-daemon requires build users, aborting activation" >&2 echo "Create the build users or disable the daemon:" >&2 echo "$ darwin-install" >&2 @@ -120,7 +104,7 @@ let buildGroupID = '' buildGroupID=$(dscl . -read /Groups/nixbld PrimaryGroupID | awk '{print $2}') expectedBuildGroupID=${toString config.ids.gids.nixbld} - if [[ $buildGroupID != $expectedBuildGroupID ]]; then + if [[ $buildGroupID != "$expectedBuildGroupID" ]]; then printf >&2 '\e[1;31merror: Build user group has mismatching GID, aborting activation\e[0m\n' printf >&2 'The default Nix build user group ID was changed from 30000 to 350.\n' printf >&2 'You are currently managing Nix build users with nix-darwin, but your\n' @@ -130,6 +114,7 @@ let printf >&2 'Possible causes include setting up a new Nix installation with an\n' printf >&2 'existing nix-darwin configuration, setting up a new nix-darwin\n' printf >&2 'installation with an existing Nix installation, or manually increasing\n' + # shellcheck disable=SC2016 printf >&2 'your `system.stateVersion` setting.\n' printf >&2 '\n' printf >&2 'You can set the configured group ID to match the actual value:\n' @@ -282,6 +267,7 @@ let if [[ -d /etc/ssh/authorized_keys.d ]]; then printf >&2 '\e[1;31merror: /etc/ssh/authorized_keys.d exists, aborting activation\e[0m\n' printf >&2 'SECURITY NOTICE: The previous implementation of the\n' + # shellcheck disable=SC2016 printf >&2 '`users.users..openssh.authorizedKeys.*` options would not delete\n' printf >&2 'authorized keys files when the setting for a given user was removed.\n' printf >&2 '\n' @@ -350,7 +336,7 @@ in system.activationScripts.checks.text = '' ${cfg.text} - if test ''${checkActivation:-0} -eq 1; then + if [[ "''${checkActivation:-0}" -eq 1 ]]; then echo "ok" >&2 exit 0 fi diff --git a/modules/system/default.nix b/modules/system/default.nix index 285936c56..a1862faee 100644 --- a/modules/system/default.nix +++ b/modules/system/default.nix @@ -92,6 +92,8 @@ in name = "darwin-system-${cfg.darwinLabel}"; preferLocalBuild = true; + nativeBuildInputs = [ pkgs.shellcheck ]; + activationScript = cfg.activationScripts.script.text; activationUserScript = cfg.activationScripts.userScript.text; inherit (cfg) darwinLabel; @@ -133,6 +135,8 @@ in chmod u+x $out/activate-user unset activationUserScript + shellcheck $out/activate $out/activate-user + echo -n "$systemConfig" > $out/systemConfig echo -n "$darwinLabel" > $out/darwin-version diff --git a/modules/system/launchd.nix b/modules/system/launchd.nix index cdb6549f3..c578dec34 100644 --- a/modules/system/launchd.nix +++ b/modules/system/launchd.nix @@ -105,19 +105,29 @@ in ${concatMapStringsSep "\n" (attr: launchdActivation "LaunchAgents" attr.target) launchAgents} ${concatMapStringsSep "\n" (attr: launchdActivation "LaunchDaemons" attr.target) launchDaemons} - for f in $(ls /run/current-system/Library/LaunchAgents 2> /dev/null); do - if test ! -e "${cfg.build.launchd}/Library/LaunchAgents/$f"; then - echo "removing service $(basename $f .plist)" >&2 + for f in /run/current-system/Library/LaunchAgents/*; do + [[ -e "$f" ]] || break # handle when directory is empty + f=''${f#/run/current-system/Library/LaunchAgents/} + + if [[ ! -e "${cfg.build.launchd}/Library/LaunchAgents/$f" ]]; then + echo "removing service $(basename "$f" .plist)" >&2 launchctl unload "/Library/LaunchAgents/$f" || true - if test -e "/Library/LaunchAgents/$f"; then rm -f "/Library/LaunchAgents/$f"; fi + if [[ -e "/Library/LaunchAgents/$f" ]]; then + rm -f "/Library/LaunchAgents/$f" + fi fi done - for f in $(ls /run/current-system/Library/LaunchDaemons 2> /dev/null); do - if test ! -e "${cfg.build.launchd}/Library/LaunchDaemons/$f"; then - echo "removing service $(basename $f .plist)" >&2 + for f in /run/current-system/Library/LaunchDaemons/*; do + [[ -e "$f" ]] || break # handle when directory is empty + f=''${f#/run/current-system/Library/LaunchDaemons/} + + if [[ ! -e "${cfg.build.launchd}/Library/LaunchDaemons/$f" ]]; then + echo "removing service $(basename "$f" .plist)" >&2 launchctl unload "/Library/LaunchDaemons/$f" || true - if test -e "/Library/LaunchDaemons/$f"; then rm -f "/Library/LaunchDaemons/$f"; fi + if [[ -e "/Library/LaunchDaemons/$f" ]]; then + rm -f "/Library/LaunchDaemons/$f" + fi fi done ''; @@ -133,11 +143,16 @@ in ''} ${concatMapStringsSep "\n" (attr: userLaunchdActivation attr.target) userLaunchAgents} - for f in $(ls /run/current-system/user/Library/LaunchAgents 2> /dev/null); do - if test ! -e "${cfg.build.launchd}/user/Library/LaunchAgents/$f"; then - echo "removing user service $(basename $f .plist)" >&2 - launchctl unload ~/Library/LaunchAgents/$f || true - if test -e ~/Library/LaunchAgents/$f; then rm -f ~/Library/LaunchAgents/$f; fi + for f in /run/current-system/user/Library/LaunchAgents/*; do + [[ -e "$f" ]] || break # handle when directory is empty + f=''${f#/run/current-system/user/Library/LaunchAgents/} + + if [[ ! -e "${cfg.build.launchd}/user/Library/LaunchAgents/$f" ]]; then + echo "removing user service $(basename "$f" .plist)" >&2 + launchctl unload ~/Library/LaunchAgents/"$f" || true + if [[ -e ~/Library/LaunchAgents/"$f" ]]; then + rm -f ~/Library/LaunchAgents/"$f" + fi fi done ''; diff --git a/modules/system/patches.nix b/modules/system/patches.nix index 4f965014c..7b1925562 100644 --- a/modules/system/patches.nix +++ b/modules/system/patches.nix @@ -30,9 +30,9 @@ in Set of patches to apply to {file}`/`. ::: {.warning} - + This can modify everything so use with caution. - + ::: Useful for safely changing system files. Unlike the etc module this @@ -56,10 +56,13 @@ in # Applying patches to /. echo "applying patches..." >&2 - for f in $(ls /run/current-system/patches 2> /dev/null); do - if test ! -e "${config.system.build.patches}/patches/$f"; then - patch --force --reverse --backup -d / -p1 < "/run/current-system/patches/$f" || true - fi + for f in /run/current-system/patches/*; do + [[ -e "$f" ]] || break # handle when directory is empty + f=''${f#/run/current-system/patches/} + + if [[ ! -e "${config.system.build.patches}/patches/$f" ]]; then + patch --force --reverse --backup -d / -p1 < "/run/current-system/patches/$f" || true + fi done ${concatMapStringsSep "\n" (f: '' diff --git a/modules/users/default.nix b/modules/users/default.nix index 6a1cd2e6b..434b1daa1 100644 --- a/modules/users/default.nix +++ b/modules/users/default.nix @@ -99,6 +99,10 @@ in assertion = cfg.users ? root -> (cfg.users.root.home == null || cfg.users.root.home == "/var/root"); message = "`users.users.root.home` must be set to either `null` or `/var/root`."; } + { + assertion = !builtins.elem "root" deletedUsers; + message = "Remove `root` from `users.knownUsers` if you no longer want nix-darwin to manage it."; + } ]; users.gids = mkMerge gids; @@ -107,7 +111,7 @@ in # NOTE: We put this in `system.checks` as we want this to run first to avoid partial activations # however currently that runs at user level activation as that runs before system level activation # TODO: replace `$USER` with `$SUDO_USER` when system.checks runs from system level - system.checks.text = lib.mkAfter '' + system.checks.text = lib.mkIf (builtins.length (createdUsers ++ deletedUsers) > 0) (lib.mkAfter '' ensurePerms() { homeDirectory=$(dscl . -read /Users/nobody NFSHomeDirectory) homeDirectory=''${homeDirectory#NFSHomeDirectory: } @@ -115,6 +119,7 @@ in if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then if [[ -n "$SSH_CONNECTION" ]]; then printf >&2 '\e[1;31merror: users cannot be %s over SSH without Full Disk Access, aborting activation\e[0m\n' "$2" + # shellcheck disable=SC2016 printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access over SSH.\n' "$1" "$2" printf >&2 'You can either:\n' printf >&2 '\n' @@ -122,6 +127,7 @@ in printf >&2 '\n' printf >&2 'or\n' printf >&2 '\n' + # shellcheck disable=SC2016 printf >&2 ' run `darwin-rebuild` in a graphical session.\n' printf >&2 '\n' printf >&2 'The option "Allow full disk access for remote users" can be found by\n' @@ -135,9 +141,11 @@ in if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then printf >&2 '\e[1;31merror: permission denied when trying to %s user %s, aborting activation\e[0m\n' "$2" "$1" - printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n' "$1" "$2" + # shellcheck disable=SC2016 + printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n' printf >&2 'please accept the dialog that pops up.\n' printf >&2 '\n' + # shellcheck disable=SC2016 printf >&2 'If you do not wish to be prompted every time `darwin-rebuild updates your users,\n' printf >&2 'you can grant Full Disk Access to your terminal emulator in System Settings.\n' printf >&2 '\n' @@ -149,7 +157,6 @@ in fi } - ${concatMapStringsSep "\n" (v: let name = lib.escapeShellArg v.name; dsclUser = lib.escapeShellArg "/Users/${v.name}"; @@ -187,18 +194,16 @@ in if [ "$u" -gt 501 ]; then # TODO: add `darwin.primaryUser` as well if [[ ${name} == "$USER" ]]; then + # shellcheck disable=SC2016 printf >&2 '\e[1;31merror: refusing to delete the user calling `darwin-rebuild` (%s), aborting activation\e[0m\n', ${name} exit 1 - elif [[ ${name} == "root" ]]; then - printf >&2 '\e[1;31merror: refusing to delete `root`, aborting activation\e[0m\n' - exit 1 fi ensurePerms ${name} delete fi fi '') deletedUsers} - ''; + ''); system.activationScripts.groups.text = mkIf (cfg.knownGroups != []) '' echo "setting up groups..." >&2