feat: add show-password CLI subcommand
Adds 'show-password' subcommand to the muxplex CLI that: - Prints 'Auth mode: PAM — no password file used' when MUXPLEX_AUTH is not 'password' and PAM is available - Prints 'Password: <pw>' when a password file exists - Prints guidance to auto-generate when no password file found Also imports load_password and pam_available at module level in cli.py to enable testable patching via muxplex.cli namespace. Tests added: - test_show_password_prints_password_from_file - test_show_password_no_file - test_show_password_pam_mode
This commit is contained in:
@@ -5,10 +5,25 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from muxplex.auth import load_password, pam_available
|
||||||
|
|
||||||
# Module-level path constants (overridable in tests via monkeypatch)
|
# Module-level path constants (overridable in tests via monkeypatch)
|
||||||
_system_service_path = Path("/etc/systemd/system/muxplex.service")
|
_system_service_path = Path("/etc/systemd/system/muxplex.service")
|
||||||
|
|
||||||
|
|
||||||
|
def show_password() -> None:
|
||||||
|
"""Print the current muxplex password or indicate PAM mode."""
|
||||||
|
auth_mode = os.environ.get("MUXPLEX_AUTH", "").lower()
|
||||||
|
if auth_mode != "password" and pam_available():
|
||||||
|
print("Auth mode: PAM — no password file used")
|
||||||
|
return
|
||||||
|
pw = load_password()
|
||||||
|
if pw:
|
||||||
|
print(f"Password: {pw}")
|
||||||
|
else:
|
||||||
|
print("No password file found. Start muxplex to auto-generate one.")
|
||||||
|
|
||||||
|
|
||||||
def serve(
|
def serve(
|
||||||
host: str = "127.0.0.1",
|
host: str = "127.0.0.1",
|
||||||
port: int = 8088,
|
port: int = 8088,
|
||||||
@@ -101,10 +116,14 @@ def main() -> None:
|
|||||||
"--system", action="store_true", help="System-wide (requires sudo)"
|
"--system", action="store_true", help="System-wide (requires sudo)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
sub.add_parser("show-password", help="Show the current muxplex password")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.command == "install-service":
|
if args.command == "install-service":
|
||||||
install_service(system=args.system)
|
install_service(system=args.system)
|
||||||
|
elif args.command == "show-password":
|
||||||
|
show_password()
|
||||||
else:
|
else:
|
||||||
serve(
|
serve(
|
||||||
host=args.host, port=args.port, auth=args.auth, session_ttl=args.session_ttl
|
host=args.host, port=args.port, auth=args.auth, session_ttl=args.session_ttl
|
||||||
|
|||||||
@@ -160,6 +160,57 @@ def test_install_service_strips_wsl_mnt_paths_from_environment(tmp_path, monkeyp
|
|||||||
assert "/usr/bin" in env_line
|
assert "/usr/bin" in env_line
|
||||||
|
|
||||||
|
|
||||||
|
def test_show_password_prints_password_from_file(tmp_path, monkeypatch, capsys):
|
||||||
|
"""show_password() prints the password when MUXPLEX_AUTH=password and file exists."""
|
||||||
|
from muxplex.cli import show_password
|
||||||
|
|
||||||
|
# Set up fake home with password file
|
||||||
|
fake_home = tmp_path / "home"
|
||||||
|
pw_dir = fake_home / ".config" / "muxplex"
|
||||||
|
pw_dir.mkdir(parents=True)
|
||||||
|
pw_file = pw_dir / "password"
|
||||||
|
pw_file.write_text("my-test-password\n")
|
||||||
|
|
||||||
|
monkeypatch.setattr(Path, "home", staticmethod(lambda: fake_home))
|
||||||
|
monkeypatch.setenv("MUXPLEX_AUTH", "password")
|
||||||
|
|
||||||
|
show_password()
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert "my-test-password" in captured.out
|
||||||
|
|
||||||
|
|
||||||
|
def test_show_password_no_file(tmp_path, monkeypatch, capsys):
|
||||||
|
"""show_password() tells user no file found when in password mode with no file."""
|
||||||
|
from muxplex.cli import show_password
|
||||||
|
|
||||||
|
# Set up fake home WITHOUT password file
|
||||||
|
fake_home = tmp_path / "home"
|
||||||
|
fake_home.mkdir(parents=True)
|
||||||
|
|
||||||
|
monkeypatch.setattr(Path, "home", staticmethod(lambda: fake_home))
|
||||||
|
monkeypatch.setenv("MUXPLEX_AUTH", "password")
|
||||||
|
|
||||||
|
show_password()
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
output_lower = captured.out.lower()
|
||||||
|
assert "no password" in output_lower or "not found" in output_lower
|
||||||
|
|
||||||
|
|
||||||
|
def test_show_password_pam_mode(monkeypatch, capsys):
|
||||||
|
"""show_password() reports PAM mode when pam_available() is True and not password mode."""
|
||||||
|
from muxplex.cli import show_password
|
||||||
|
|
||||||
|
monkeypatch.delenv("MUXPLEX_AUTH", raising=False)
|
||||||
|
|
||||||
|
with patch("muxplex.cli.pam_available", return_value=True):
|
||||||
|
show_password()
|
||||||
|
|
||||||
|
captured = capsys.readouterr()
|
||||||
|
assert "pam" in captured.out.lower()
|
||||||
|
|
||||||
|
|
||||||
def test_dunder_main_calls_main():
|
def test_dunder_main_calls_main():
|
||||||
"""python -m muxplex must call cli.main()."""
|
"""python -m muxplex must call cli.main()."""
|
||||||
import importlib.util
|
import importlib.util
|
||||||
|
|||||||
Reference in New Issue
Block a user