diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 4b7bb1271392..8bfd2a784f47 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -807,6 +807,31 @@ in # Don't bother with certain units in containers. systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; + # When using the classic /etc mechanism, we set certain paths in /etc to + # /etc/static so that systemd cannot change them (as they are symlinks to + # the read-only Nix Store). This is only done so that these services cannot + # change the values. All other parts of systemd should read them from their + # canonical locations. + # + # If you use the overlay mechanism to manage /etc, this is unnecessary + # because either the overlay is mutable (and users can legitimately change + # values without them being overridden) or it is immutable and systemd will + # suggest to only make runtime changes. + systemd.services."systemd-localed".environment = lib.mkIf (!config.system.etc.overlay.enable) { + SYSTEMD_ETC_LOCALE_CONF = "/etc/static/locale.conf"; + SYSTEMD_ETC_VCONSOLE_CONF = "/etc/static/vconsole.conf"; + }; + systemd.services."systemd-timedated".environment = + lib.mkIf (!config.system.etc.overlay.enable && config.time.timeZone != null) + { + SYSTEMD_ETC_LOCALTIME = "/etc/static/localtime"; + SYSTEMD_ETC_ADJTIME = "/etc/static/adjtime"; + }; + systemd.services."systemd-hostnamed".environment = lib.mkIf (!config.system.etc.overlay.enable) { + SYSTEMD_ETC_HOSTNAME = "/etc/static/hostname"; + SYSTEMD_ETC_MACHINE_INFO = "/etc/static/machine-info"; + }; + # Increase numeric PID range (set directly instead of copying a one-line file from systemd) # https://github.com/systemd/systemd/pull/12226 boot.kernel.sysctl."kernel.pid_max" = mkIf pkgs.stdenv.hostPlatform.is64bit (lib.mkDefault 4194304); diff --git a/nixos/tests/systemd.nix b/nixos/tests/systemd.nix index f0bbdef76c61..98cc88a0326f 100644 --- a/nixos/tests/systemd.nix +++ b/nixos/tests/systemd.nix @@ -109,10 +109,10 @@ machine.wait_for_unit("first-boot-complete.target") machine.succeed( - "journalctl --system -o cat --grep 'systemd ${lib.escapeRegex pkgs.systemd.version} running'" + "journalctl --system -o cat --grep 'systemd ${lib.escapeRegex nodes.machine.systemd.package.version} running'" ) - assert "systemd ${lib.versions.major pkgs.systemd.version} (${pkgs.systemd.version})" in machine.succeed( + assert "systemd ${lib.versions.major nodes.machine.systemd.package.version} (${nodes.machine.systemd.package.version})" in machine.succeed( "systemctl --version" ) diff --git a/pkgs/by-name/bt/btrfs-progs/package.nix b/pkgs/by-name/bt/btrfs-progs/package.nix index 3d9d3cdf5968..44ea7fba892d 100644 --- a/pkgs/by-name/bt/btrfs-progs/package.nix +++ b/pkgs/by-name/bt/btrfs-progs/package.nix @@ -21,11 +21,11 @@ stdenv.mkDerivation (finalAttrs: { pname = "btrfs-progs"; - version = "6.17.1"; + version = "6.19"; src = fetchurl { url = "mirror://kernel/linux/kernel/people/kdave/btrfs-progs/btrfs-progs-v${finalAttrs.version}.tar.xz"; - hash = "sha256-pL4Kbrs8R2Qn+12Xss8CewzNtrDFX/FjIzIMHoy3dlg="; + hash = "sha256-rWt5GmDrVj0zFLwY48R/awU6AyY5SItbCbnV55Id5rY="; }; nativeBuildInputs = [ diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py index baf0c57c93b2..b5d927c51a3c 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/__init__.py @@ -265,22 +265,21 @@ def parse_args( if args.no_build_nix: parser_warn("--no-build-nix is deprecated, we do not build nix anymore") - if args.diff and args.action not in ( - # case for calling build_and_activate_system - # except excluding DRY_BUILD and DRY_ACTIVATE, - # in which --diff is uniquely a no-op - Action.SWITCH.value, - Action.BOOT.value, - Action.TEST.value, - Action.BUILD.value, - Action.BUILD_IMAGE.value, - Action.BUILD_VM.value, - Action.BUILD_VM_WITH_BOOTLOADER.value, + if ( + args.action + in ( + Action.DRY_BUILD.value, # --diff breaks dry-build + Action.EDIT.value, + Action.LIST_GENERATIONS.value, + Action.REPL.value, + ) + and args.diff ): parser_warn(f"--diff is a no-op with '{args.action}'") + args.diff = False if args.action == Action.EDIT.value and (args.file or args.attr): - parser.error("--file and --attr are not supported with 'edit'") + parser.error(f"--file and --attr are not supported with '{args.action}'") if (args.target_host or args.build_host) and args.action not in ( Action.SWITCH.value, diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/models.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/models.py index f8c20878f5e1..7fb37e8f97a9 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/models.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/models.py @@ -63,20 +63,6 @@ class BuildAttr: return cls(Path(file or "default.nix"), attr) -def _get_hostname(target_host: Remote | None) -> str | None: - if target_host: - try: - return run_wrapper( - ["uname", "-n"], - capture_output=True, - remote=target_host, - ).stdout.strip() - except (AttributeError, subprocess.CalledProcessError): - return None - else: - return platform.node() - - @dataclass(frozen=True) class Flake: path: str @@ -95,9 +81,7 @@ class Flake: m = cls._re.match(flake_str) assert m is not None, f"got no matches for {flake_str}" attr = m.group("attr") - nixos_attr = ( - f'nixosConfigurations."{attr or _get_hostname(target_host) or "default"}"' - ) + nixos_attr = f'nixosConfigurations."{attr or cls._get_hostname(target_host) or "default"}"' path = m.group("path") return cls(path, nixos_attr) @@ -126,6 +110,20 @@ class Flake: except FileNotFoundError: return self.path + @staticmethod + def _get_hostname(target_host: Remote | None) -> str | None: + if target_host: + try: + return run_wrapper( + ["uname", "-n"], + capture_output=True, + remote=target_host, + ).stdout.strip() + except (AttributeError, subprocess.CalledProcessError): + return None + else: + return platform.node() + @dataclass(frozen=True) class Generation: diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py index 1e2bd91f71c5..b1da9ef555dc 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py @@ -25,7 +25,7 @@ from .models import ( Profile, Remote, ) -from .process import SSH_DEFAULT_OPTS, run_wrapper +from .process import PRESERVE_ENV, SSH_DEFAULT_OPTS, run_wrapper from .utils import Args, dict_to_flags FLAKE_FLAGS: Final = ["--extra-experimental-features", "nix-command flakes"] @@ -192,9 +192,7 @@ def copy_closure( Also supports copying a closure from a remote to another remote.""" sshopts = os.getenv("NIX_SSHOPTS", "") - extra_env = { - "NIX_SSHOPTS": " ".join(filter(lambda x: x, [sshopts, *SSH_DEFAULT_OPTS])) - } + env = {"NIX_SSHOPTS": " ".join(filter(lambda x: x, [sshopts, *SSH_DEFAULT_OPTS]))} def nix_copy_closure(host: Remote, to: bool) -> None: run_wrapper( @@ -205,7 +203,7 @@ def copy_closure( host.host, closure, ], - extra_env=extra_env, + env=env, ) def nix_copy(to_host: Remote, from_host: Remote) -> None: @@ -221,7 +219,7 @@ def copy_closure( f"ssh://{to_host.host}", closure, ], - extra_env=extra_env, + env=env, ) match (to_host, from_host): @@ -703,7 +701,11 @@ def switch_to_configuration( run_wrapper( [*cmd, path_to_config / "bin/switch-to-configuration", str(action)], - extra_env={"NIXOS_INSTALL_BOOTLOADER": "1" if install_bootloader else "0"}, + env={ + "LOCALE_ARCHIVE": PRESERVE_ENV, + "NIXOS_NO_CHECK": PRESERVE_ENV, + "NIXOS_INSTALL_BOOTLOADER": "1" if install_bootloader else "0", + }, remote=target_host, sudo=sudo, ) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/process.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/process.py index df6beac95412..75b4e2b96823 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/process.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/process.py @@ -5,10 +5,11 @@ import os import re import shlex import subprocess -from collections.abc import Sequence +from collections.abc import Mapping, Sequence from dataclasses import dataclass +from enum import Enum from ipaddress import AddressValueError, IPv6Address -from typing import Final, Self, TextIO, TypedDict, Unpack +from typing import Final, Literal, Self, TextIO, TypedDict, Unpack, override from . import tmpdir @@ -23,7 +24,30 @@ SSH_DEFAULT_OPTS: Final = [ "ControlPersist=60", ] -type Args = Sequence[str | bytes | os.PathLike[str] | os.PathLike[bytes]] + +class _Env(Enum): + PRESERVE_ENV = "PRESERVE" + + @override + def __repr__(self) -> str: + return self.value + + +PRESERVE_ENV: Final = _Env.PRESERVE_ENV + + +type Arg = str | bytes | os.PathLike[str] | os.PathLike[bytes] +type Args = Sequence[Arg] +type EnvValue = str | Literal[_Env.PRESERVE_ENV] + + +@dataclass(frozen=True) +class _RawShellArg: + value: str + + @override + def __str__(self) -> str: + return self.value @dataclass(frozen=True) @@ -106,70 +130,84 @@ def run_wrapper( args: Args, *, check: bool = True, - extra_env: dict[str, str] | None = None, + env: Mapping[str, EnvValue] | None = None, remote: Remote | None = None, sudo: bool = False, **kwargs: Unpack[RunKwargs], ) -> subprocess.CompletedProcess[str]: "Wrapper around `subprocess.run` that supports extra functionality." - env = None process_input = None - run_args = args + run_args: list[Arg] = list(args) + final_args: list[Arg] + + normalized_env = _normalize_env(env) + resolved_env = _resolve_env_local(normalized_env) if remote: - if extra_env: - extra_env_args = [f"{env}={value}" for env, value in extra_env.items()] - args = ["env", *extra_env_args, *args] + # Apply env for the *remote command* (not for ssh itself) + remote_run_args: list[Arg | _RawShellArg] = [] + remote_run_args.extend(run_args) + if normalized_env: + remote_run_args = _prefix_env_cmd_remote(run_args, normalized_env) + if sudo: + sudo_args = shlex.split(os.getenv("NIX_SUDOOPTS", "")) if remote.sudo_password: - args = ["sudo", "--prompt=", "--stdin", *args] + remote_run_args = [ + "sudo", + "--prompt=", + "--stdin", + *sudo_args, + *remote_run_args, + ] process_input = remote.sudo_password + "\n" else: - args = ["sudo", *args] - run_args = [ + remote_run_args = ["sudo", *sudo_args, *remote_run_args] + + ssh_args: list[Arg] = [ "ssh", *remote.opts, *SSH_DEFAULT_OPTS, remote.ssh_host(), "--", - # SSH will join the parameters here and pass it to the shell, so we - # need to quote it to avoid issues. - # We can't use `shlex.join`, otherwise we will hit MAX_ARG_STRLEN - # limits when the command becomes too big. - *[shlex.quote(str(a)) for a in args], + *[_quote_remote_arg(a) for a in remote_run_args], ] + final_args = ssh_args + popen_env = None # keep ssh's environment normal + else: - if extra_env: - env = os.environ | extra_env if sudo: + # subprocess.run(env=...) would affect sudo, but sudo may drop env + # for the target command. + # So we inject env via `sudo env ... cmd`. + if env is not None and resolved_env: + run_args = _prefix_env_cmd(run_args, resolved_env) + sudo_args = shlex.split(os.getenv("NIX_SUDOOPTS", "")) - # Using --preserve-env is less than ideal since it will cause - # the following warn during usage: - # > warning: $HOME ('/home/') is not owned by you, - # > falling back to the one defined in the 'passwd' file ('/root') - # However, right now it is the only way to guarantee the semantics - # expected for the commands, e.g. activation with systemd-run - # expects access to environment variables like LOCALE_ARCHIVE, - # NIXOS_NO_CHECK. - # For now, for anyone that the above warn bothers you, please - # use `sudo nixos-rebuild` instead of `--sudo` flag. - run_args = ["sudo", "--preserve-env", *sudo_args, *run_args] + final_args = ["sudo", *sudo_args, *run_args] + + # No need to pass env to subprocess.run; keep sudo's own env + # default. + popen_env = None + else: + # Non-sudo local: we can fully control the environment with + # subprocess.run(env=...) + final_args = run_args + popen_env = None if env is None else resolved_env logger.debug( - "calling run with args=%r, kwargs=%r, extra_env=%r", - run_args, + "calling run with args=%r, kwargs=%r, env=%r", + _sanitize_env_run_args(remote_run_args if remote else run_args), kwargs, - extra_env, + env, ) try: r = subprocess.run( - run_args, + final_args, check=check, - env=env, + env=popen_env, input=process_input, - # Hope nobody is using NixOS with non-UTF8 encodings, but - # "surrogateescape" should still work in those systems. text=True, errors="surrogateescape", **kwargs, @@ -195,13 +233,95 @@ def run_wrapper( raise -# SSH does not send the signals to the process when running without usage of -# pseudo-TTY (that causes a whole other can of worms), so if the process is -# long running (e.g.: a build) this will result in the underlying process -# staying alive. -# See: https://stackoverflow.com/a/44354466 -# Issue: https://github.com/NixOS/nixpkgs/issues/403269 +def _resolve_env(env: Mapping[str, EnvValue] | None) -> dict[str, str]: + normalized = _normalize_env(env) + return _resolve_env_local(normalized) + + +def _normalize_env(env: Mapping[str, EnvValue] | None) -> dict[str, EnvValue]: + """ + Normalize env mapping, but preserve some environment variables by default. + """ + return {"PATH": PRESERVE_ENV, **(env or {})} + + +def _resolve_env_local(env: dict[str, EnvValue]) -> dict[str, str]: + """ + Resolve env mapping where values can be: + - PRESERVE_ENV: copy from current os.environ (if present) + - str: explicit value + """ + result: dict[str, str] = {} + + for k, v in env.items(): + if v == PRESERVE_ENV: + cur = os.environ.get(k) + if cur is not None: + result[k] = cur + else: + result[k] = v + return result + + +def _prefix_env_cmd(cmd: Sequence[Arg], resolved_env: dict[str, str]) -> list[Arg]: + """ + Prefix a command with `env -i K=V ... -- ` to set vars for the + command. + """ + if not resolved_env: + return list(cmd) + + assigns = [f"{k}={v}" for k, v in resolved_env.items()] + return ["env", "-i", *assigns, *cmd] + + +def _prefix_env_cmd_remote( + cmd: Args, + env: dict[str, EnvValue], +) -> list[Arg | _RawShellArg]: + """ + Prefix remote commands with env assignments. Preserve markers are expanded + by the remote shell at execution time. + """ + assigns: list[str | _RawShellArg] = [] + for k, v in env.items(): + if v is PRESERVE_ENV: + assigns.append(_RawShellArg(f"{k}=${{{k}-}}")) + else: + assigns.append(f"{k}={v}") + return ["env", "-i", *assigns, *cmd] + + +def _quote_remote_arg(arg: Arg | _RawShellArg) -> str: + if isinstance(arg, _RawShellArg): + return str(arg) + return shlex.quote(str(arg)) + + +def _sanitize_env_run_args(run_args: list[Arg] | list[Arg | _RawShellArg]) -> list[Arg]: + """ + Sanitize long or sensitive environment variables from logs. + """ + sanitized: list[Arg] = [] + for value in run_args: + if isinstance(value, str) and value.startswith("PATH="): + sanitized.append("PATH=") + elif isinstance(value, str | bytes | os.PathLike): + sanitized.append(value) + else: + sanitized.append(str(value)) + return sanitized + + def _kill_long_running_ssh_process(args: Args, remote: Remote) -> None: + """ + SSH does not send the signals to the process when running without usage of + pseudo-TTY (that causes a whole other can of worms), so if the process is + long running (e.g.: a build) this will result in the underlying process + staying alive. + See: https://stackoverflow.com/a/44354466 + Issue: https://github.com/NixOS/nixpkgs/issues/403269 + """ logger.info("cleaning-up remote process, please wait...") # We need to escape both the shell and regex here (since pkill interprets diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/services.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/services.py index f5b9609e14f7..8a170a138326 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/services.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/nixos_rebuild/services.py @@ -103,8 +103,7 @@ def _get_system_attr( case Action.BUILD_IMAGE if flake: variants = nix.get_build_image_variants_flake( flake, - eval_flags=grouped_nix_args.flake_build_flags - | grouped_nix_args.flake_eval_flags, + eval_flags=grouped_nix_args.flake_eval_flags, ) _validate_image_variant(args.image_variant, variants) attr = f"config.system.build.images.{args.image_variant}" @@ -264,8 +263,7 @@ def _activate_system( image_name = nix.get_build_image_name_flake( flake, args.image_variant, - eval_flags=grouped_nix_args.flake_build_flags - | grouped_nix_args.flake_eval_flags, + eval_flags=grouped_nix_args.flake_eval_flags, ) else: image_name = nix.get_build_image_name( diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py index b0ef88b2963e..83004b18b8a8 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_main.py @@ -248,7 +248,6 @@ def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: | { "env": { "NIXOS_INSTALL_BOOTLOADER": "0", - "NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1", } } ), @@ -487,7 +486,6 @@ def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: call( [ "sudo", - "--preserve-env", "nix-env", "-p", Path("/nix/var/nix/profiles/system"), @@ -505,21 +503,15 @@ def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: call( [ "sudo", - "--preserve-env", + "env", + "-i", + "NIXOS_INSTALL_BOOTLOADER=1", *nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX, config_path / "bin/switch-to-configuration", "switch", ], check=True, - **( - DEFAULT_RUN_KWARGS - | { - "env": { - "NIXOS_INSTALL_BOOTLOADER": "1", - "NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1", - } - } - ), + **DEFAULT_RUN_KWARGS, ), ] ) @@ -625,6 +617,9 @@ def test_execute_nix_switch_build_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@build-host", "--", + "env", + "-i", + "PATH=${PATH-}", "mktemp", "-d", "-t", @@ -640,6 +635,9 @@ def test_execute_nix_switch_build_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@build-host", "--", + "env", + "-i", + "PATH=${PATH-}", "nix-store", "--realise", str(config_path), @@ -656,6 +654,9 @@ def test_execute_nix_switch_build_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@build-host", "--", + "env", + "-i", + "PATH=${PATH-}", "readlink", "-f", "/tmp/tmpdir/config", @@ -670,6 +671,9 @@ def test_execute_nix_switch_build_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@build-host", "--", + "env", + "-i", + "PATH=${PATH-}", "rm", "-rf", "/tmp/tmpdir", @@ -699,6 +703,9 @@ def test_execute_nix_switch_build_target_host( "user@target-host", "--", "sudo", + "env", + "-i", + "PATH=${PATH-}", "nix-env", "-p", "/nix/var/nix/profiles/system", @@ -714,6 +721,9 @@ def test_execute_nix_switch_build_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@target-host", "--", + "env", + "-i", + "PATH=${PATH-}", "test", "-d", "/run/systemd/system", @@ -729,6 +739,10 @@ def test_execute_nix_switch_build_target_host( "--", "sudo", "env", + "-i", + "PATH=${PATH-}", + "LOCALE_ARCHIVE=${LOCALE_ARCHIVE-}", + "NIXOS_NO_CHECK=${NIXOS_NO_CHECK-}", "NIXOS_INSTALL_BOOTLOADER=0", *nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX, str(config_path / "bin/switch-to-configuration"), @@ -806,6 +820,9 @@ def test_execute_nix_switch_flake_target_host( "user@localhost", "--", "sudo", + "env", + "-i", + "PATH=${PATH-}", "nix-env", "-p", "/nix/var/nix/profiles/system", @@ -821,6 +838,9 @@ def test_execute_nix_switch_flake_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@localhost", "--", + "env", + "-i", + "PATH=${PATH-}", "test", "-d", "/run/systemd/system", @@ -836,6 +856,10 @@ def test_execute_nix_switch_flake_target_host( "--", "sudo", "env", + "-i", + "PATH=${PATH-}", + "LOCALE_ARCHIVE=${LOCALE_ARCHIVE-}", + "NIXOS_NO_CHECK=${NIXOS_NO_CHECK-}", "NIXOS_INSTALL_BOOTLOADER=0", *nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX, str(config_path / "bin/switch-to-configuration"), @@ -912,6 +936,9 @@ def test_execute_nix_switch_flake_build_host( *nr.process.SSH_DEFAULT_OPTS, "user@localhost", "--", + "env", + "-i", + "PATH=${PATH-}", "nix", "--extra-experimental-features", "'nix-command flakes'", @@ -1121,6 +1148,9 @@ def test_execute_build_dry_run_build_and_target_remote( *nr.process.SSH_DEFAULT_OPTS, "user@build-host", "--", + "env", + "-i", + "PATH=${PATH-}", "nix", "--extra-experimental-features", "'nix-command flakes'", @@ -1304,7 +1334,6 @@ def test_execute_switch_store_path(mock_run: Mock, tmp_path: Path) -> None: | { "env": { "NIXOS_INSTALL_BOOTLOADER": "0", - "NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1", } } ), @@ -1354,6 +1383,9 @@ def test_execute_switch_store_path_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@remote-host", "--", + "env", + "-i", + "PATH=${PATH-}", "test", "-f", str(config_path / "nixos-version"), @@ -1368,6 +1400,9 @@ def test_execute_switch_store_path_target_host( "user@remote-host", "--", "sudo", + "env", + "-i", + "PATH=${PATH-}", "nix-env", "-p", "/nix/var/nix/profiles/system", @@ -1383,6 +1418,9 @@ def test_execute_switch_store_path_target_host( *nr.process.SSH_DEFAULT_OPTS, "user@remote-host", "--", + "env", + "-i", + "PATH=${PATH-}", "test", "-d", "/run/systemd/system", @@ -1398,6 +1436,10 @@ def test_execute_switch_store_path_target_host( "--", "sudo", "env", + "-i", + "PATH=${PATH-}", + "LOCALE_ARCHIVE=${LOCALE_ARCHIVE-}", + "NIXOS_NO_CHECK=${NIXOS_NO_CHECK-}", "NIXOS_INSTALL_BOOTLOADER=0", *nr.nix.SWITCH_TO_CONFIGURATION_CMD_PREFIX, str(config_path / "bin/switch-to-configuration"), diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py index 524527f8f68d..8a69fd89fad7 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py @@ -134,9 +134,7 @@ def test_build_remote( "user@host", Path("/path/to/file"), ], - extra_env={ - "NIX_SSHOPTS": " ".join(["--ssh opts", *p.SSH_DEFAULT_OPTS]) - }, + env={"NIX_SSHOPTS": " ".join(["--ssh opts", *p.SSH_DEFAULT_OPTS])}, ), call( ["mktemp", "-d", "-t", "nixos-rebuild.XXXXX"], @@ -208,9 +206,7 @@ def test_build_remote_flake( "user@host", Path("/path/to/file"), ], - extra_env={ - "NIX_SSHOPTS": " ".join(["--ssh opts", *p.SSH_DEFAULT_OPTS]) - }, + env={"NIX_SSHOPTS": " ".join(["--ssh opts", *p.SSH_DEFAULT_OPTS])}, ), call( [ @@ -241,7 +237,7 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None: n.copy_closure(closure, target_host) mock_run.assert_called_with( ["nix-copy-closure", "--to", "user@target.host", closure], - extra_env={"NIX_SSHOPTS": " ".join(p.SSH_DEFAULT_OPTS)}, + env={"NIX_SSHOPTS": " ".join(p.SSH_DEFAULT_OPTS)}, ) monkeypatch.setenv("NIX_SSHOPTS", "--ssh build-opt") @@ -249,15 +245,11 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None: n.copy_closure(closure, None, build_host, {"copy_flag": True}) mock_run.assert_called_with( ["nix-copy-closure", "--copy-flag", "--from", "user@build.host", closure], - extra_env={ - "NIX_SSHOPTS": " ".join(["--ssh build-opt", *p.SSH_DEFAULT_OPTS]) - }, + env={"NIX_SSHOPTS": " ".join(["--ssh build-opt", *p.SSH_DEFAULT_OPTS])}, ) monkeypatch.setenv("NIX_SSHOPTS", "--ssh build-target-opt") - extra_env = { - "NIX_SSHOPTS": " ".join(["--ssh build-target-opt", *p.SSH_DEFAULT_OPTS]) - } + env = {"NIX_SSHOPTS": " ".join(["--ssh build-target-opt", *p.SSH_DEFAULT_OPTS])} with patch(get_qualified_name(n.run_wrapper, n), autospec=True) as mock_run: n.copy_closure(closure, target_host, build_host, {"copy_flag": True}) mock_run.assert_called_with( @@ -273,7 +265,7 @@ def test_copy_closure(monkeypatch: MonkeyPatch) -> None: "ssh://user@target.host", closure, ], - extra_env=extra_env, + env=env, ) @@ -723,7 +715,11 @@ def test_switch_to_configuration_without_systemd_run( ) mock_run.assert_called_with( [profile_path / "bin/switch-to-configuration", "switch"], - extra_env={"NIXOS_INSTALL_BOOTLOADER": "0"}, + env={ + "LOCALE_ARCHIVE": p.PRESERVE_ENV, + "NIXOS_NO_CHECK": p.PRESERVE_ENV, + "NIXOS_INSTALL_BOOTLOADER": "0", + }, sudo=False, remote=None, ) @@ -760,7 +756,11 @@ def test_switch_to_configuration_without_systemd_run( config_path / "specialisation/special/bin/switch-to-configuration", "test", ], - extra_env={"NIXOS_INSTALL_BOOTLOADER": "1"}, + env={ + "LOCALE_ARCHIVE": p.PRESERVE_ENV, + "NIXOS_NO_CHECK": p.PRESERVE_ENV, + "NIXOS_INSTALL_BOOTLOADER": "1", + }, sudo=True, remote=target_host, ) @@ -791,7 +791,11 @@ def test_switch_to_configuration_with_systemd_run( profile_path / "bin/switch-to-configuration", "switch", ], - extra_env={"NIXOS_INSTALL_BOOTLOADER": "0"}, + env={ + "LOCALE_ARCHIVE": p.PRESERVE_ENV, + "NIXOS_NO_CHECK": p.PRESERVE_ENV, + "NIXOS_INSTALL_BOOTLOADER": "0", + }, sudo=False, remote=None, ) @@ -816,7 +820,11 @@ def test_switch_to_configuration_with_systemd_run( config_path / "specialisation/special/bin/switch-to-configuration", "test", ], - extra_env={"NIXOS_INSTALL_BOOTLOADER": "1"}, + env={ + "LOCALE_ARCHIVE": p.PRESERVE_ENV, + "NIXOS_NO_CHECK": p.PRESERVE_ENV, + "NIXOS_INSTALL_BOOTLOADER": "1", + }, sudo=True, remote=target_host, ) diff --git a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py index a47ebe31f9bb..858850f569a8 100644 --- a/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py +++ b/pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_process.py @@ -7,6 +7,7 @@ import nixos_rebuild.models as m import nixos_rebuild.process as p +@patch.dict(p.os.environ, {"PATH": "/path/to/bin"}, clear=True) @patch("subprocess.run", autospec=True) def test_run(mock_run: Any) -> None: p.run_wrapper(["test", "--with", "flags"], check=True) @@ -19,22 +20,27 @@ def test_run(mock_run: Any) -> None: input=None, ) - with patch.dict(p.os.environ, {"PATH": "/path/to/bin"}, clear=True): - p.run_wrapper( - ["test", "--with", "flags"], - check=False, - sudo=True, - extra_env={"FOO": "bar"}, - ) + p.run_wrapper( + ["test", "--with", "flags"], + check=False, + sudo=True, + env={"FOO": "bar"}, + ) mock_run.assert_called_with( - ["sudo", "--preserve-env", "test", "--with", "flags"], + [ + "sudo", + "env", + "-i", + "PATH=/path/to/bin", + "FOO=bar", + "test", + "--with", + "flags", + ], check=False, text=True, errors="surrogateescape", - env={ - "PATH": "/path/to/bin", - "FOO": "bar", - }, + env=None, input=None, ) @@ -51,6 +57,9 @@ def test_run(mock_run: Any) -> None: *p.SSH_DEFAULT_OPTS, "user@localhost", "--", + "env", + "-i", + "PATH=${PATH-}", "test", "--with", "'some flags'", @@ -66,7 +75,7 @@ def test_run(mock_run: Any) -> None: ["test", "--with", "flags"], check=True, sudo=True, - extra_env={"FOO": "bar"}, + env={"FOO": "bar"}, remote=m.Remote("user@localhost", ["--ssh", "opt"], "password"), ) mock_run.assert_called_with( @@ -81,6 +90,8 @@ def test_run(mock_run: Any) -> None: "--prompt=", "--stdin", "env", + "-i", + "PATH=${PATH-}", "FOO=bar", "test", "--with", @@ -164,14 +175,57 @@ def test_ssh_host() -> None: @patch("subprocess.run", autospec=True) def test_custom_sudo_args(mock_run: Any) -> None: - with patch.dict(p.os.environ, {"NIX_SUDOOPTS": "--custom foo --args"}): + with patch.dict( + p.os.environ, + {"NIX_SUDOOPTS": "--custom foo --args", "PATH": "/path/to/bin"}, + clear=True, + ): p.run_wrapper( ["test"], check=False, sudo=True, ) mock_run.assert_called_with( - ["sudo", "--preserve-env", "--custom", "foo", "--args", "test"], + [ + "sudo", + "--custom", + "foo", + "--args", + "test", + ], + check=False, + env=None, + input=None, + text=True, + errors="surrogateescape", + ) + + with patch.dict( + p.os.environ, + {"NIX_SUDOOPTS": "--custom foo --args", "PATH": "/path/to/bin"}, + clear=True, + ): + p.run_wrapper( + ["test"], + check=False, + sudo=True, + remote=m.Remote("user@localhost", [], None), + ) + mock_run.assert_called_with( + [ + "ssh", + *p.SSH_DEFAULT_OPTS, + "user@localhost", + "--", + "sudo", + "--custom", + "foo", + "--args", + "env", + "-i", + "PATH=${PATH-}", + "test", + ], check=False, env=None, input=None, diff --git a/pkgs/by-name/ru/ruff/package.nix b/pkgs/by-name/ru/ruff/package.nix index 70a260c75721..d9950ba56618 100644 --- a/pkgs/by-name/ru/ruff/package.nix +++ b/pkgs/by-name/ru/ruff/package.nix @@ -16,18 +16,18 @@ rustPlatform.buildRustPackage (finalAttrs: { pname = "ruff"; - version = "0.15.1"; + version = "0.15.3"; src = fetchFromGitHub { owner = "astral-sh"; repo = "ruff"; tag = finalAttrs.version; - hash = "sha256-Bj4ATRVYrKqigISNiDvgjUw4MLMwfgdID8MqaiVxz0g="; + hash = "sha256-xeZk044anJ21uQwV3VN1QOvav+soYVdArpEw/rr8Xsw="; }; cargoBuildFlags = [ "--package=ruff" ]; - cargoHash = "sha256-IF60aGv56Kh+wDYyN7XzLBywepvAxv2HMqSOz+Su2b4="; + cargoHash = "sha256-16Ao1y0pFWxGjHkGi4VCIA9msvA5Tka8wvok8o3g6rc="; nativeBuildInputs = [ installShellFiles ]; diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/.gitignore b/pkgs/by-name/sw/switch-to-configuration-ng/.gitignore similarity index 100% rename from pkgs/by-name/sw/switch-to-configuration-ng/src/.gitignore rename to pkgs/by-name/sw/switch-to-configuration-ng/.gitignore diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/Cargo.lock b/pkgs/by-name/sw/switch-to-configuration-ng/Cargo.lock similarity index 100% rename from pkgs/by-name/sw/switch-to-configuration-ng/src/Cargo.lock rename to pkgs/by-name/sw/switch-to-configuration-ng/Cargo.lock diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/Cargo.toml b/pkgs/by-name/sw/switch-to-configuration-ng/Cargo.toml similarity index 100% rename from pkgs/by-name/sw/switch-to-configuration-ng/src/Cargo.toml rename to pkgs/by-name/sw/switch-to-configuration-ng/Cargo.toml diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/README.md b/pkgs/by-name/sw/switch-to-configuration-ng/README.md index 4111f131f089..b0f6cf9f08c5 100644 --- a/pkgs/by-name/sw/switch-to-configuration-ng/README.md +++ b/pkgs/by-name/sw/switch-to-configuration-ng/README.md @@ -9,6 +9,5 @@ For more information on what happens during a switch, see [what-happens-during-a ``` cd ./pkgs/by-name/sw/switch-to-configuration-ng nix-shell ../../../.. -A switch-to-configuration-ng -cd ./src cargo build ``` diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/build.rs b/pkgs/by-name/sw/switch-to-configuration-ng/build.rs similarity index 100% rename from pkgs/by-name/sw/switch-to-configuration-ng/src/build.rs rename to pkgs/by-name/sw/switch-to-configuration-ng/build.rs diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/package.nix b/pkgs/by-name/sw/switch-to-configuration-ng/package.nix index e398f86e79a5..cffc771405f4 100644 --- a/pkgs/by-name/sw/switch-to-configuration-ng/package.nix +++ b/pkgs/by-name/sw/switch-to-configuration-ng/package.nix @@ -12,9 +12,9 @@ rustPlatform.buildRustPackage { pname = "switch-to-configuration"; version = "0.1.0"; - src = ./src; + src = builtins.filterSource (name: _: !(lib.hasSuffix ".nix" name)) ./.; - cargoLock.lockFile = ./src/Cargo.lock; + cargoLock.lockFile = ./Cargo.lock; nativeBuildInputs = [ pkg-config ]; buildInputs = [ dbus ]; diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs b/pkgs/by-name/sw/switch-to-configuration-ng/src/main.rs similarity index 100% rename from pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs rename to pkgs/by-name/sw/switch-to-configuration-ng/src/main.rs diff --git a/pkgs/by-name/wh/whois/package.nix b/pkgs/by-name/wh/whois/package.nix index c95394a97f82..4503732b8681 100644 --- a/pkgs/by-name/wh/whois/package.nix +++ b/pkgs/by-name/wh/whois/package.nix @@ -11,14 +11,14 @@ }: stdenv.mkDerivation (finalAttrs: { - version = "5.6.5"; + version = "5.6.6"; pname = "whois"; src = fetchFromGitHub { owner = "rfc1036"; repo = "whois"; rev = "v${finalAttrs.version}"; - hash = "sha256-zCaM3fMittoEzuMRELqc1ES8QPgZRXVjyHUfMsS5tJA="; + hash = "sha256-RKiXQJoyy3wd/KXphhgjikdmIHl8nmjEzibjk5FKpBQ="; }; patches = [ diff --git a/pkgs/development/python-modules/ruff/default.nix b/pkgs/development/python-modules/ruff/default.nix index d32d951c4aec..2322db869620 100644 --- a/pkgs/development/python-modules/ruff/default.nix +++ b/pkgs/development/python-modules/ruff/default.nix @@ -20,7 +20,7 @@ buildPythonPackage { # Do not rely on path lookup at runtime to find the ruff binary. # Use the propagated binary instead. '' - substituteInPlace python/ruff/__main__.py \ + substituteInPlace python/ruff/_find_ruff.py \ --replace-fail \ 'ruff_exe = "ruff" + sysconfig.get_config_var("EXE")' \ 'return "${lib.getExe ruff}"' diff --git a/pkgs/os-specific/linux/kernel/kernels-org.json b/pkgs/os-specific/linux/kernel/kernels-org.json index 0dd8cc79f635..fad7f3538163 100644 --- a/pkgs/os-specific/linux/kernel/kernels-org.json +++ b/pkgs/os-specific/linux/kernel/kernels-org.json @@ -30,13 +30,13 @@ "lts": true }, "6.18": { - "version": "6.18.13", - "hash": "sha256:0zv8qml075jpk2i58cxp61hm3yb74mpkbkjg15n87riqzmakqb7d", - "lts": false + "version": "6.18.14", + "hash": "sha256:1f3wv9vdg43cy1lnqd60zqgki6px67mdhfkfnpk1npqq5akk86cd", + "lts": true }, "6.19": { - "version": "6.19.3", - "hash": "sha256:1glf369wfr66lmv9wmijin6idlfgijfsh0gx2qly7gpwmml4jiqf", + "version": "6.19.4", + "hash": "sha256:1b68i7z91fbs1zayzzzf71g9ilfk0wi2fr8nralha60xq723p6r7", "lts": false } } diff --git a/pkgs/tools/misc/grub/default.nix b/pkgs/tools/misc/grub/default.nix index aa119dac9e8a..35acf233f794 100644 --- a/pkgs/tools/misc/grub/default.nix +++ b/pkgs/tools/misc/grub/default.nix @@ -596,7 +596,10 @@ stdenv.mkDerivation rec { echo 'echo "Compile grub2 with { kbdcompSupport = true; } to enable support for this command."' >> util/grub-kbdcomp.in ''; - depsBuildBuild = [ buildPackages.stdenv.cc ]; + depsBuildBuild = [ + buildPackages.stdenv.cc + pkg-config + ]; nativeBuildInputs = [ bison flex @@ -661,6 +664,12 @@ stdenv.mkDerivation rec { ./bootstrap --no-git --gnulib-srcdir=${gnulib} substituteInPlace ./configure --replace '/usr/share/fonts/unifont' '${unifont}/share/fonts' + '' + # build-grub-mkfont is built & run during build, need to find freetype for buildPlatform + + lib.optionalString (!lib.systems.equals stdenv.buildPlatform stdenv.hostPlatform) '' + configureFlagsArray+=( + "BUILD_PKG_CONFIG=$PKG_CONFIG_FOR_BUILD" + ) ''; postConfigure = ''