add _format_cert_table() helper for CLI cert listings
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1262,6 +1262,22 @@ class CursesApp:
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
def _format_cert_table(certs: list[CertInfo]) -> str:
|
||||||
|
"""Render CN / expiry / email as an aligned table, like `ls -l`."""
|
||||||
|
if not certs:
|
||||||
|
return "(no certificates)"
|
||||||
|
rows = [
|
||||||
|
(c.cn, _expiry_label(c).strip(), get_email(EASYRSA_PKI_DIR, c.cn) or "(none)")
|
||||||
|
for c in certs
|
||||||
|
]
|
||||||
|
cn_w = max(len("CN"), max(len(r[0]) for r in rows))
|
||||||
|
exp_w = max(len("EXPIRES"), max(len(r[1]) for r in rows))
|
||||||
|
lines = [f"{'CN':<{cn_w}} {'EXPIRES':<{exp_w}} EMAIL"]
|
||||||
|
for cn, exp, email in rows:
|
||||||
|
lines.append(f"{cn:<{cn_w}} {exp:<{exp_w}} {email}")
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
class CliRunner:
|
class CliRunner:
|
||||||
"""Non-interactive runner for scripting / cron use."""
|
"""Non-interactive runner for scripting / cron use."""
|
||||||
|
|
||||||
|
|||||||
@@ -150,6 +150,63 @@ def test_regen_crl_calls_gen_and_copy(monkeypatch, capsys):
|
|||||||
assert "CRL" in capsys.readouterr().out
|
assert "CRL" in capsys.readouterr().out
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# _format_cert_table
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_format_cert_table_empty_list():
|
||||||
|
import openvpncertupdate
|
||||||
|
assert openvpncertupdate._format_cert_table([]) == "(no certificates)"
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_cert_table_header_and_columns(monkeypatch):
|
||||||
|
import openvpncertupdate
|
||||||
|
certs = [
|
||||||
|
openvpncertupdate.CertInfo(cn="alice", expires=None, days_left=24),
|
||||||
|
openvpncertupdate.CertInfo(cn="bob", expires=None, days_left=-5),
|
||||||
|
]
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"openvpncertupdate.get_email",
|
||||||
|
MagicMock(side_effect=lambda pki, cn: {"alice": "alice@example.com"}.get(cn, "")),
|
||||||
|
)
|
||||||
|
table = openvpncertupdate._format_cert_table(certs)
|
||||||
|
lines = table.splitlines()
|
||||||
|
assert lines[0].split() == ["CN", "EXPIRES", "EMAIL"]
|
||||||
|
assert len(lines) == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_cert_table_shows_email_and_none_placeholder(monkeypatch):
|
||||||
|
import openvpncertupdate
|
||||||
|
certs = [
|
||||||
|
openvpncertupdate.CertInfo(cn="alice", expires=None, days_left=24),
|
||||||
|
openvpncertupdate.CertInfo(cn="bob", expires=None, days_left=-5),
|
||||||
|
]
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"openvpncertupdate.get_email",
|
||||||
|
MagicMock(side_effect=lambda pki, cn: {"alice": "alice@example.com"}.get(cn, "")),
|
||||||
|
)
|
||||||
|
table = openvpncertupdate._format_cert_table(certs)
|
||||||
|
lines = table.splitlines()
|
||||||
|
assert "alice@example.com" in lines[1]
|
||||||
|
assert "(none)" in lines[2]
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_cert_table_columns_are_aligned(monkeypatch):
|
||||||
|
import openvpncertupdate
|
||||||
|
certs = [
|
||||||
|
openvpncertupdate.CertInfo(cn="a", expires=None, days_left=24),
|
||||||
|
openvpncertupdate.CertInfo(cn="a-much-longer", expires=None, days_left=5),
|
||||||
|
]
|
||||||
|
monkeypatch.setattr("openvpncertupdate.get_email", MagicMock(return_value=""))
|
||||||
|
table = openvpncertupdate._format_cert_table(certs)
|
||||||
|
lines = table.splitlines()
|
||||||
|
# The EMAIL column must start at the same character offset on every row.
|
||||||
|
email_col = len(lines[0]) - len("EMAIL")
|
||||||
|
for line in lines[1:]:
|
||||||
|
assert line.rstrip().endswith("(none)")
|
||||||
|
assert line.index("(none)") == email_col
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# main() argument dispatch
|
# main() argument dispatch
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user