#!/usr/bin/env python3 """Persisted auth selection with fake dependencies and no live connection.""" import json import os from pathlib import Path import subprocess import tempfile ROOT = Path(__file__).resolve().parents[1] CLI = ROOT / "bin/vpn-lemanapro.sh" with tempfile.TemporaryDirectory(prefix="lemana-auth-") as temporary: home = Path(temporary) config = home / "config" config.mkdir() saved = config / "env" custom = 'LEMANA_VPN_USERNAME="fixture-user"\nLEMANA_VPN_BW_ITEM="Corporate & VPN"\nLEMANA_VPN_LOG_MAX_BYTES="4096"\nLEMANA_VPN_USE_TOUCHID="0"\n' saved.write_text(custom + 'LEMANA_VPN_MODE="manual-keychain"\n') fake = home / "fake" fake.mkdir() fake.joinpath("security").write_text('''#!/bin/sh while [ "$#" -gt 0 ]; do if [ "$1" = -w ]; then echo forbidden-secret-read >> "$HOME/side-effects"; exit 1; fi if [ "$1" = -a ]; then shift; account="$1"; fi shift done case "${TEST_CREDENTIALS:-all}:$account" in none:*|password:totp/*) exit 1 ;; *) exit 0 ;; esac ''') for name in ("sudo", "openconnect", "bw"): fake.joinpath(name).write_text('#!/bin/sh\necho unexpected-execution >> "$HOME/side-effects"\nexit 1\n') for path in fake.iterdir(): path.chmod(0o755) env = {key: value for key, value in os.environ.items() if not key.startswith(("LEMANA_VPN_", "OPENCONNECT_LITE_"))} env.update(HOME=temporary, PATH=str(fake) + ":" + os.environ["PATH"], LEMANA_VPN_CONFIG_DIR=str(config), OPENCONNECT_LITE_CONFIG_DIR=str(home / "sso"), LEMANA_VPN_STATUS_DIR=str(home / "state"), LEMANA_VPN_OC_VENV=str(home / "no-venv"), LEMANA_VPN_OC_BIN=str(fake / "openconnect"), LEMANA_VPN_APP_DIR=str(home / "no-app"), LEMANA_VPN_DNS_CLEANUP=str(fake / "sudo")) def run(*args, extra=None, success=True): result = subprocess.run(["bash", str(CLI), *args], env=dict(env, **(extra or {})), text=True, capture_output=True, timeout=10) if success: assert result.returncode == 0, result.stderr else: assert result.returncode != 0, result.stdout return result def status(extra=None): return json.loads(run("--status", "--json", extra=extra).stdout)["modules"] for choice, mode, source, preferred in ( ("keychain", "keychain-auto", "keychain", "keychain"), ("manual", "manual-keychain", "keychain", "keychain"), ("bitwarden", "bitwarden-auto", "bitwarden", "bitwarden"), ("manual", "manual-keychain", "keychain", "bitwarden"), ("auto", "bitwarden-auto", "bitwarden", "bitwarden"), ("keychain", "keychain-auto", "keychain", "keychain"), ): run("--set-auth=" + choice) modules = status() assert modules["mode"]["id"] == mode assert modules["auth"]["source"] == source assert modules["auth"]["auto_source"] == preferred assert modules["auth"]["mode"] == ("manual" if mode == "manual-keychain" else "auto") assert modules["auth"]["ready"] assert custom.rstrip() in saved.read_text() assert saved.stat().st_mode & 0o777 == 0o600 assert not list(config.glob(".auth-env-*")) assert not (home / "side-effects").exists() assert not (home / "state").exists() print("PASS saved selection: manual/automatic sources, remembered auto source, settings preserved, no connection or secret reads") before = saved.read_text() run("--set-auth=invalid", success=False) assert saved.read_text() == before fake.joinpath("python3").write_text('#!/bin/sh\nexit 1\n') fake.joinpath("python3").chmod(0o755) run("--set-auth=manual", success=False) assert saved.read_text() == before fake.joinpath("python3").unlink() print("PASS failed/invalid save leaves active settings unchanged") for credentials, hint in (("none", "--configure-login"), ("password", "--import-yandex-key")): modules = status({"TEST_CREDENTIALS": credentials}) assert not modules["auth"]["ready"] and hint in modules["auth"]["setup_hint"] failure = run("--json", extra={"TEST_CREDENTIALS": credentials}, success=False) assert hint in failure.stdout assert not (home / "side-effects").exists() and not (home / "state").exists() print("PASS incomplete local automatic setup blocks client launch with correct guidance") saved.write_text(custom + 'LEMANA_VPN_MODE="manual-keychain"\nLEMANA_VPN_LOCAL_OTP="1"\n') assert status()["mode"]["id"] == "keychain-auto" manual = json.loads(run("--manual", "--status", "--json").stdout)["modules"] assert manual["mode"]["id"] == "manual-keychain" and not manual["local_otp"] print("PASS approved legacy-local migration and explicit manual override") print("auth settings checks ok")