From b4bb9c85250fe78dee0aadbc727a3e4dec803bd8 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Thu, 26 Mar 2026 12:24:37 +0100 Subject: [PATCH] nixos-rebuild-ng: redirect switch-to-configuration stdout to stderr nixos-rebuild-ng intentionally prints only the resulting store path to stdout so callers can script against it (see the print_result comment in services.py). However, switch-to-configuration's stdout was inherited unredirected, so any output from it or its children leaked into ours. See #503032 which accidentaly broke this contract. --- .../ni/nixos-rebuild-ng/src/nixos_rebuild/nix.py | 6 ++++++ .../by-name/ni/nixos-rebuild-ng/src/tests/test_main.py | 10 ++++++++++ pkgs/by-name/ni/nixos-rebuild-ng/src/tests/test_nix.py | 4 ++++ 3 files changed, 20 insertions(+) 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 95ebb3c9c0c2..0e89656ec7aa 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 @@ -717,6 +717,12 @@ def switch_to_configuration( }, remote=target_host, sudo=sudo, + # switch-to-configuration is not expected to produce meaningful + # stdout, but if it (or any of its children) does, it would leak + # into our stdout and break the "only the store path on stdout" + # contract documented in services.py (see print_result). Redirect + # its stdout to our stderr defensively. + stdout=sys.stderr, ) 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 456a41f46eac..3ebba4edc5b6 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 @@ -249,6 +249,7 @@ def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: "boot", ], check=True, + stdout=ANY, **( DEFAULT_RUN_KWARGS | { @@ -547,6 +548,7 @@ def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: "switch", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -795,6 +797,7 @@ def test_execute_nix_switch_build_target_host( "switch", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -920,6 +923,7 @@ def test_execute_nix_switch_flake_target_host( "switch", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -1047,6 +1051,7 @@ def test_execute_nix_switch_flake_build_host( "switch", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -1132,6 +1137,7 @@ def test_execute_switch_rollback(mock_run: Mock, tmp_path: Path) -> None: "switch", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -1307,6 +1313,7 @@ def test_execute_test_flake(mock_run: Mock, tmp_path: Path) -> None: call( [config_path / "bin/switch-to-configuration", "test"], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -1372,6 +1379,7 @@ def test_execute_test_rollback( "test", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] @@ -1433,6 +1441,7 @@ def test_execute_switch_store_path(mock_run: Mock, tmp_path: Path) -> None: "switch", ], check=True, + stdout=ANY, **( DEFAULT_RUN_KWARGS | { @@ -1551,6 +1560,7 @@ def test_execute_switch_store_path_target_host( "switch", ], check=True, + stdout=ANY, **DEFAULT_RUN_KWARGS, ), ] 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 28948d1eaaff..f8c6d75c5290 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 @@ -770,6 +770,7 @@ def test_switch_to_configuration_without_systemd_run( }, sudo=False, remote=None, + stdout=sys.stderr, ) with pytest.raises(m.NixOSRebuildError) as e: @@ -811,6 +812,7 @@ def test_switch_to_configuration_without_systemd_run( }, sudo=True, remote=target_host, + stdout=sys.stderr, ) @@ -846,6 +848,7 @@ def test_switch_to_configuration_with_systemd_run( }, sudo=False, remote=None, + stdout=sys.stderr, ) target_host = m.Remote("user@localhost", [], None, "ssh") @@ -875,6 +878,7 @@ def test_switch_to_configuration_with_systemd_run( }, sudo=True, remote=target_host, + stdout=sys.stderr, )