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 838b8913abb3..fb68b219c1f9 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 @@ -5,6 +5,7 @@ import os import sys from pathlib import Path from subprocess import CalledProcessError, run +from textwrap import dedent from typing import Final, assert_never from . import nix, tmpdir @@ -329,6 +330,30 @@ def reexec( os.execve(current, argv, os.environ | {"_NIXOS_REBUILD_REEXEC": "1"}) +def validate_nixos_config(path_to_config: Path) -> None: + if not (path_to_config / "nixos-version").exists() and not os.environ.get( + "NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM" + ): + msg = dedent( + # the lowercase for the first letter below is proposital + f""" + your NixOS configuration path seems to be missing essential files. + To avoid corrupting your current NixOS installation, the activation will abort. + + This could be caused by Nix bug: https://github.com/NixOS/nix/issues/13367. + This is the evaluated NixOS configuration path: {path_to_config}. + Change the directory to somewhere else (e.g., `cd $HOME`) before trying again. + + If you think this is a mistake, you can set the environment variable + NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM to 1 + and re-run the command to continue. + Please open an issue if this is the case. + """ + ).strip() + logger.error(msg) + sys.exit(1) + + def execute(argv: list[str]) -> None: args, args_groups = parse_args(argv) @@ -488,6 +513,7 @@ def execute(argv: list[str]) -> None: copy_flags=copy_flags, ) if action in (Action.SWITCH, Action.BOOT): + validate_nixos_config(path_to_config) nix.set_profile( profile, path_to_config, 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 a66d70498c5f..345c8bd32f79 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 @@ -213,7 +213,11 @@ def test_reexec_flake( ) -@patch.dict(os.environ, {}, clear=True) +@patch.dict( + os.environ, + {"NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1"}, + clear=True, +) @patch("subprocess.run", autospec=True) def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: nixpkgs_path = tmp_path / "nixpkgs" @@ -291,7 +295,15 @@ def test_execute_nix_boot(mock_run: Mock, tmp_path: Path) -> None: "boot", ], check=True, - **(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "0"}}), + **( + DEFAULT_RUN_KWARGS + | { + "env": { + "NIXOS_INSTALL_BOOTLOADER": "0", + "NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1", + } + } + ), ), ] ) @@ -421,7 +433,11 @@ def test_execute_nix_build_image_flake(mock_run: Mock, tmp_path: Path) -> None: ) -@patch.dict(os.environ, {}, clear=True) +@patch.dict( + os.environ, + {"NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1"}, + clear=True, +) @patch("subprocess.run", autospec=True) def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: config_path = tmp_path / "test" @@ -498,13 +514,25 @@ def test_execute_nix_switch_flake(mock_run: Mock, tmp_path: Path) -> None: "switch", ], check=True, - **(DEFAULT_RUN_KWARGS | {"env": {"NIXOS_INSTALL_BOOTLOADER": "1"}}), + **( + DEFAULT_RUN_KWARGS + | { + "env": { + "NIXOS_INSTALL_BOOTLOADER": "1", + "NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1", + } + } + ), ), ] ) -@patch.dict(os.environ, {}, clear=True) +@patch.dict( + os.environ, + {"NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1"}, + clear=True, +) @patch("subprocess.run", autospec=True) @patch("uuid.uuid4", autospec=True) @patch(get_qualified_name(nr.cleanup_ssh), autospec=True) @@ -714,7 +742,11 @@ def test_execute_nix_switch_build_target_host( ) -@patch.dict(os.environ, {}, clear=True) +@patch.dict( + os.environ, + {"NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1"}, + clear=True, +) @patch("subprocess.run", autospec=True) @patch(get_qualified_name(nr.cleanup_ssh), autospec=True) def test_execute_nix_switch_flake_target_host( @@ -817,7 +849,11 @@ def test_execute_nix_switch_flake_target_host( ) -@patch.dict(os.environ, {}, clear=True) +@patch.dict( + os.environ, + {"NIXOS_REBUILD_I_UNDERSTAND_THE_CONSEQUENCES_PLEASE_BREAK_MY_SYSTEM": "1"}, + clear=True, +) @patch("subprocess.run", autospec=True) @patch(get_qualified_name(nr.cleanup_ssh), autospec=True) def test_execute_nix_switch_flake_build_host(