diff --git a/pkgs/clan-cli/clan_cli/bwrap/__init__.py b/pkgs/clan-cli/clan_cli/bwrap/__init__.py new file mode 100644 index 000000000..48311fe4c --- /dev/null +++ b/pkgs/clan-cli/clan_cli/bwrap/__init__.py @@ -0,0 +1,42 @@ +from clan_cli.cmd import run +from clan_cli.nix import nix_shell + +_works: bool | None = None + + +def bubblewrap_works() -> bool: + global _works + if _works is None: + _works = _bubblewrap_works() + return _works + + +def _bubblewrap_works() -> bool: + # fmt: off + cmd = nix_shell( + [ + "nixpkgs#bash", + "nixpkgs#bubblewrap", + ], + [ + "bwrap", + "--unshare-all", + "--tmpfs", "/", + "--ro-bind", "/nix/store", "/nix/store", + "--dev", "/dev", + "--chdir", "/", + "--bind", "/proc", "/proc", + "--uid", "1000", + "--gid", "1000", + "--", + # do nothing, just test if bash executes + "bash", "-c", ":" + ], + ) + # fmt: on + try: + run(cmd) + except Exception: + return False + else: + return True diff --git a/pkgs/clan-cli/clan_cli/bwrap/tests/test_bwrap.py b/pkgs/clan-cli/clan_cli/bwrap/tests/test_bwrap.py new file mode 100644 index 000000000..1886712a4 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/bwrap/tests/test_bwrap.py @@ -0,0 +1,16 @@ +import sys + +import pytest +from clan_cli.bwrap import bubblewrap_works + + +@pytest.mark.skipif(sys.platform != "linux", reason="bubblewrap only works on linux") +def test_bubblewrap_works_on_linux() -> None: + assert bubblewrap_works() is True + + +@pytest.mark.skipif( + sys.platform == "linux", reason="bubblewrap does not work on non-linux" +) +def test_bubblewrap_detection_non_linux() -> None: + assert bubblewrap_works() is False diff --git a/pkgs/clan-cli/clan_cli/facts/generate.py b/pkgs/clan-cli/clan_cli/facts/generate.py index d82855623..c5da1e3a6 100644 --- a/pkgs/clan-cli/clan_cli/facts/generate.py +++ b/pkgs/clan-cli/clan_cli/facts/generate.py @@ -103,7 +103,9 @@ def generate_service_facts( service, machine.facts_data[service]["generator"]["prompt"] ) env["prompt_value"] = prompt_value - if sys.platform == "linux": + from clan_cli import bwrap + + if sys.platform == "linux" and bwrap.bubblewrap_works(): cmd = bubblewrap_cmd(generator, facts_dir, secrets_dir) else: cmd = ["bash", "-c", generator] diff --git a/pkgs/clan-cli/clan_cli/vars/generate.py b/pkgs/clan-cli/clan_cli/vars/generate.py index 800012449..170ab82ea 100644 --- a/pkgs/clan-cli/clan_cli/vars/generate.py +++ b/pkgs/clan-cli/clan_cli/vars/generate.py @@ -201,8 +201,9 @@ def execute_generator( prompt_file = tmpdir_prompts / prompt.name value = get_prompt_value(prompt.name) prompt_file.write_text(value) + from clan_cli import bwrap - if sys.platform == "linux": + if sys.platform == "linux" and bwrap.bubblewrap_works(): cmd = bubblewrap_cmd(str(generator.final_script), tmpdir) else: cmd = ["bash", "-c", str(generator.final_script)] diff --git a/pkgs/clan-cli/pyproject.toml b/pkgs/clan-cli/pyproject.toml index df77c8166..05032c811 100644 --- a/pkgs/clan-cli/pyproject.toml +++ b/pkgs/clan-cli/pyproject.toml @@ -28,12 +28,12 @@ clan_cli = [ ] [tool.pytest.ini_options] -testpaths = "tests" +testpaths = ["tests", "clan_cli"] faulthandler_timeout = 60 log_level = "DEBUG" log_format = "%(message)s" addopts = "--cov . --cov-report term --cov-report html:.reports/html --no-cov-on-fail --durations 5 --color=yes --new-first -W error -n auto" # Add --pdb for debugging -norecursedirs = "tests/helpers" +norecursedirs = ["clan_cli/tests/helpers", "clan_cli/nixpkgs"] markers = ["impure", "with_core"] filterwarnings = "default::ResourceWarning"