From 7d851dcb7e29e7930c59111433d4f1835701f25b Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Wed, 10 Jun 2026 21:37:30 -0400 Subject: [PATCH] feat: doctor reports bubblewrap availability Adds a non-fatal bubblewrap check to the doctor command that reports whether the bwrap binary is available. This is necessary for sandboxed sessions and the check is displayed alongside other system requirement checks. Co-Authored-By: Claude Opus 4.8 --- src/hqt/cli.py | 7 ++++++- tests/test_cli.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/test_cli.py diff --git a/src/hqt/cli.py b/src/hqt/cli.py index 7069f7f..e43cef5 100644 --- a/src/hqt/cli.py +++ b/src/hqt/cli.py @@ -1,5 +1,6 @@ import logging import os +import shutil import subprocess import sys import traceback @@ -105,7 +106,6 @@ def launch(inside_tmux: bool = False): @main.command() def doctor(): """Check system requirements.""" - import shutil from hqt.harnesses.registry import discover_harnesses tmux = shutil.which("tmux") @@ -119,6 +119,11 @@ def doctor(): click.echo(f"{name}: ✓") if not harnesses: click.echo("No harnesses found on PATH") + bwrap = shutil.which("bwrap") + if bwrap: + click.echo(f"bubblewrap: ✓ {bwrap}") + else: + click.echo("bubblewrap: ✗ not found — sandboxed sessions unavailable") @main.command(name="list") diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..3be3570 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,30 @@ +from unittest.mock import patch + +from click.testing import CliRunner + +from hqt import cli as cli_module +from hqt.cli import main + + +def _which(found: set[str]): + return lambda name: f"/usr/bin/{name}" if name in found else None + + +def test_doctor_reports_bwrap_present(): + """Test that doctor reports bubblewrap when present.""" + # Patch the single shutil.which used by both cli and registry + with patch.object( + cli_module.shutil, "which", side_effect=_which({"tmux", "bwrap"}) + ): + result = CliRunner().invoke(main, ["doctor"]) + assert result.exit_code == 0 + assert "bubblewrap: ✓" in result.output + + +def test_doctor_reports_bwrap_missing(): + """Test that doctor reports bubblewrap as missing when not present.""" + # Patch the single shutil.which used by both cli and registry + with patch.object(cli_module.shutil, "which", side_effect=_which({"tmux"})): + result = CliRunner().invoke(main, ["doctor"]) + assert result.exit_code == 0 + assert "bubblewrap: ✗" in result.output