feat: add TLS status section to doctor() command output

- Inserts TLS check between Serve config and Auth status sections
- Shows enabled status with cert expiry date when valid certs configured
- Shows warning with days-expired count when cert is expired
- Shows configured-but-not-readable warning when cert file unreadable
- Shows disabled warning mentioning clipboard/HTTPS requirement when no TLS
- Adds 3 new tests: tls_disabled, tls_enabled, tls_clipboard_warning
- All 86 CLI tests pass

Co-authored-by: Amplifier <amplifier@amplified.dev>
This commit is contained in:
Brian Krabach
2026-04-03 22:07:56 -07:00
parent 41a3adbf53
commit fad9c10bbb
2 changed files with 104 additions and 0 deletions
+31
View File
@@ -342,6 +342,37 @@ def doctor() -> None:
f" (auth={cfg['auth']}, ttl={cfg['session_ttl']}s)" f" (auth={cfg['auth']}, ttl={cfg['session_ttl']}s)"
) )
# TLS status
tls_cert = cfg.get("tls_cert", "")
tls_key = cfg.get("tls_key", "")
if tls_cert and tls_key:
from datetime import datetime, timezone # noqa: PLC0415
from muxplex.tls import get_cert_info # noqa: PLC0415
cert_info = get_cert_info(tls_cert)
if cert_info is not None:
expires = cert_info["expires"]
# Ensure timezone-aware for comparison
if expires.tzinfo is None:
expires = expires.replace(tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
if expires < now:
days_ago = (now - expires).days
print(
f" {warn_mark} TLS: WARNING \u2014 cert expired {days_ago} days ago."
" Run muxplex setup-tls to renew"
)
else:
expiry_str = expires.strftime("%Y-%m-%d")
print(f" {ok_mark} TLS: enabled (cert expires {expiry_str})")
else:
print(f" {warn_mark} TLS: configured but cert not readable ({tls_cert})")
else:
print(
f" {warn_mark} TLS: disabled (clipboard requires HTTPS on non-localhost)"
)
# Auth status # Auth status
pw_path = get_password_path() pw_path = get_password_path()
if pam_available(): if pam_available():
+73
View File
@@ -1561,3 +1561,76 @@ def test_serve_subcommand_accepts_tls_flags():
tls_cert="/path/cert.pem", tls_cert="/path/cert.pem",
tls_key="/path/key.pem", tls_key="/path/key.pem",
) )
# ---------------------------------------------------------------------------
# task-6-doctor-tls: TLS status section in doctor()
# ---------------------------------------------------------------------------
def test_doctor_shows_tls_disabled(tmp_path, monkeypatch, capsys):
"""doctor() shows TLS disabled when no TLS configured."""
import muxplex.settings as settings_mod
settings_file = tmp_path / "settings.json"
# No tls_cert/tls_key — just use empty settings
settings_file.write_text("{}")
monkeypatch.setattr(settings_mod, "SETTINGS_PATH", settings_file)
from muxplex.cli import doctor
doctor()
out = capsys.readouterr().out
out_lower = out.lower()
assert "tls" in out_lower, f"Expected 'tls' in doctor output, got: {out!r}"
assert "disabled" in out_lower, (
f"Expected 'disabled' in doctor output, got: {out!r}"
)
def test_doctor_shows_tls_enabled(tmp_path, monkeypatch, capsys):
"""doctor() shows TLS enabled when valid certs are configured."""
import json
import muxplex.settings as settings_mod
from muxplex.tls import generate_self_signed
# Generate real self-signed certs in tmp_path
cert_path = tmp_path / "muxplex.crt"
key_path = tmp_path / "muxplex.key"
generate_self_signed(cert_path, key_path)
settings_file = tmp_path / "settings.json"
settings_file.write_text(
json.dumps({"tls_cert": str(cert_path), "tls_key": str(key_path)})
)
monkeypatch.setattr(settings_mod, "SETTINGS_PATH", settings_file)
from muxplex.cli import doctor
doctor()
out = capsys.readouterr().out
out_lower = out.lower()
assert "tls" in out_lower, f"Expected 'tls' in doctor output, got: {out!r}"
assert "enabled" in out_lower, f"Expected 'enabled' in doctor output, got: {out!r}"
def test_doctor_shows_tls_clipboard_warning(tmp_path, monkeypatch, capsys):
"""doctor() mentions clipboard or https when TLS is disabled."""
import muxplex.settings as settings_mod
settings_file = tmp_path / "settings.json"
settings_file.write_text("{}")
monkeypatch.setattr(settings_mod, "SETTINGS_PATH", settings_file)
from muxplex.cli import doctor
doctor()
out = capsys.readouterr().out
out_lower = out.lower()
assert "clipboard" in out_lower or "https" in out_lower, (
f"Expected 'clipboard' or 'https' in doctor TLS-disabled output, got: {out!r}"
)