From 422647e7898b8df67cd11f8fb060aec23dec84aa Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 14 Oct 2026 22:20:15 +0200 Subject: feat(cli): meshbay-cli, a command-line client for members Signs in to the hub, lists the account's groups and their folders, and downloads and uploads files directly with each group's node, end-to-end encrypted. With no argument it opens a two-pane interactive mode (Textual). Session and device keys are kept encrypted under the system's key storage, or a 0600 key file where there is none; node keys are pinned at first contact; a new machine links as a device. Packaged on its own on Linux (deb and rpm, on meshbay-common's venv, with a man page generated from the parser) and frozen next to meshbay-node in the full Windows installer, not the light one, with a self-test the build runs. client/keys.py ports keyderive.js and is LGPL like it. Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-cli/tests/conftest.py | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 packages/meshbay-cli/tests/conftest.py (limited to 'packages/meshbay-cli/tests/conftest.py') diff --git a/packages/meshbay-cli/tests/conftest.py b/packages/meshbay-cli/tests/conftest.py new file mode 100644 index 0000000..8ef9189 --- /dev/null +++ b/packages/meshbay-cli/tests/conftest.py @@ -0,0 +1,49 @@ +""" +Every test runs with its own home, and never touches the developer's own. + +Redirecting HOME alone isolates nothing on Windows — `Path.home()` reads +USERPROFILE there, and the CLI's directories come from LOCALAPPDATA — so all of +them are pointed at a throwaway directory. The OS key storage is replaced by +keyring's refusing backend: a test must never write into the developer's real +credential store, and the store's file fallback is what a headless machine uses +anyway. A test that needs a working key storage installs its own backend. +""" + +import logging + +import pytest + + +@pytest.fixture(autouse=True) +def isolated_home(tmp_path, monkeypatch): + home = tmp_path / "home" + home.mkdir() + for var in ("HOME", "USERPROFILE"): + monkeypatch.setenv(var, str(home)) + for var, sub in (("APPDATA", "AppData/Roaming"), ("LOCALAPPDATA", "AppData/Local"), + ("XDG_CONFIG_HOME", ".config"), ("XDG_DATA_HOME", ".local/share")): + monkeypatch.setenv(var, str(home / sub)) + for var in ("MESHBAY_CLI_HOME", "MESHBAY_HUB", "MESHBAY_USER", "MESHBAY_PASSWORD"): + monkeypatch.delenv(var, raising=False) + monkeypatch.setenv("PYTHON_KEYRING_BACKEND", "keyring.backends.fail.Keyring") + return home + + +@pytest.fixture(autouse=True) +def restored_logging(): + """`main()` configures logging, as an entry point does; a test that calls it + in-process must not leave that configuration to the next package's tests.""" + root = logging.getLogger() + names = ("meshbay_cli", "aiortc", "aioice", "httpx", "httpcore") + saved = (list(root.handlers), root.level, root.disabled, + {n: logging.getLogger(n).level for n in names}) + yield + handlers, level, disabled, levels = saved + for h in root.handlers: + if h not in handlers: + h.close() + root.handlers[:] = handlers + root.setLevel(level) + root.disabled = disabled + for n, lv in levels.items(): + logging.getLogger(n).setLevel(lv) -- cgit v1.2.3