feat: --send-email / --no-send-email flag for CLI mode
This commit is contained in:
@@ -984,13 +984,13 @@ class CursesApp:
|
|||||||
class CliRunner:
|
class CliRunner:
|
||||||
"""Non-interactive runner for scripting / cron use."""
|
"""Non-interactive runner for scripting / cron use."""
|
||||||
|
|
||||||
def create(self, cn: str, email_addr: str) -> None:
|
def create(self, cn: str, email_addr: str, send_email_flag: bool = True) -> None:
|
||||||
self._issue(cn, email_addr, is_renewal=False)
|
self._issue(cn, email_addr, is_renewal=False, send_email_flag=send_email_flag)
|
||||||
|
|
||||||
def reissue(self, cn: str, email_addr: str) -> None:
|
def reissue(self, cn: str, email_addr: str, send_email_flag: bool = True) -> None:
|
||||||
# Prefer the caller-supplied email; fall back to stored metadata.
|
# Prefer the caller-supplied email; fall back to stored metadata.
|
||||||
final_email = email_addr or get_email(EASYRSA_PKI_DIR, cn)
|
final_email = email_addr or get_email(EASYRSA_PKI_DIR, cn)
|
||||||
self._issue(cn, final_email, is_renewal=True)
|
self._issue(cn, final_email, is_renewal=True, send_email_flag=send_email_flag)
|
||||||
|
|
||||||
def revoke(self, cn: str) -> None:
|
def revoke(self, cn: str) -> None:
|
||||||
print(f"Revoking {cn}…", file=sys.stderr)
|
print(f"Revoking {cn}…", file=sys.stderr)
|
||||||
@@ -1013,7 +1013,8 @@ class CliRunner:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print(f"CRL updated → {CRL_DEST_PATH}")
|
print(f"CRL updated → {CRL_DEST_PATH}")
|
||||||
|
|
||||||
def _issue(self, cn: str, email_addr: str, is_renewal: bool) -> None:
|
def _issue(self, cn: str, email_addr: str, is_renewal: bool,
|
||||||
|
send_email_flag: bool = True) -> None:
|
||||||
password = generate_password()
|
password = generate_password()
|
||||||
|
|
||||||
if is_renewal:
|
if is_renewal:
|
||||||
@@ -1055,7 +1056,7 @@ class CliRunner:
|
|||||||
except CryptgeonError as exc:
|
except CryptgeonError as exc:
|
||||||
print(f"warning: Cryptgeon failed: {exc}", file=sys.stderr)
|
print(f"warning: Cryptgeon failed: {exc}", file=sys.stderr)
|
||||||
|
|
||||||
if email_addr:
|
if email_addr and send_email_flag:
|
||||||
try:
|
try:
|
||||||
send_email(email_addr, cn, one_time_url or password, ovpn_path,
|
send_email(email_addr, cn, one_time_url or password, ovpn_path,
|
||||||
MAIL_FROM, MAIL_SUBJECT, EMAIL_TEMPLATE_PATH, MAIL_BINARY)
|
MAIL_FROM, MAIL_SUBJECT, EMAIL_TEMPLATE_PATH, MAIL_BINARY)
|
||||||
@@ -1082,6 +1083,10 @@ def _build_parser() -> argparse.ArgumentParser:
|
|||||||
group.add_argument("--gen-crl", action="store_true", help="Regenerate and copy CRL")
|
group.add_argument("--gen-crl", action="store_true", help="Regenerate and copy CRL")
|
||||||
parser.add_argument("--email", metavar="EMAIL",
|
parser.add_argument("--email", metavar="EMAIL",
|
||||||
help="Email address (required for --create; optional for --reissue)")
|
help="Email address (required for --create; optional for --reissue)")
|
||||||
|
parser.add_argument("--send-email", dest="send_email", action="store_true",
|
||||||
|
default=True, help="Send email after issuing cert (default)")
|
||||||
|
parser.add_argument("--no-send-email", dest="send_email", action="store_false",
|
||||||
|
help="Skip email delivery; print URL to stdout instead")
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@@ -1097,9 +1102,9 @@ def main() -> None:
|
|||||||
if args.create:
|
if args.create:
|
||||||
if not args.email:
|
if not args.email:
|
||||||
parser.error("--email is required with --create")
|
parser.error("--email is required with --create")
|
||||||
CliRunner().create(args.create, args.email)
|
CliRunner().create(args.create, args.email, send_email_flag=args.send_email)
|
||||||
elif args.reissue:
|
elif args.reissue:
|
||||||
CliRunner().reissue(args.reissue, args.email or "")
|
CliRunner().reissue(args.reissue, args.email or "", send_email_flag=args.send_email)
|
||||||
elif args.revoke:
|
elif args.revoke:
|
||||||
CliRunner().revoke(args.revoke)
|
CliRunner().revoke(args.revoke)
|
||||||
elif args.gen_crl:
|
elif args.gen_crl:
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ def test_main_dispatches_create(monkeypatch):
|
|||||||
runner = MagicMock()
|
runner = MagicMock()
|
||||||
monkeypatch.setattr("openvpncertupdate.CliRunner", lambda: runner)
|
monkeypatch.setattr("openvpncertupdate.CliRunner", lambda: runner)
|
||||||
main()
|
main()
|
||||||
runner.create.assert_called_once_with("alice", "a@b.com")
|
runner.create.assert_called_once_with("alice", "a@b.com", send_email_flag=True)
|
||||||
|
|
||||||
|
|
||||||
def test_main_dispatches_reissue(monkeypatch):
|
def test_main_dispatches_reissue(monkeypatch):
|
||||||
@@ -173,7 +173,7 @@ def test_main_dispatches_reissue(monkeypatch):
|
|||||||
runner = MagicMock()
|
runner = MagicMock()
|
||||||
monkeypatch.setattr("openvpncertupdate.CliRunner", lambda: runner)
|
monkeypatch.setattr("openvpncertupdate.CliRunner", lambda: runner)
|
||||||
main()
|
main()
|
||||||
runner.reissue.assert_called_once_with("bob", "")
|
runner.reissue.assert_called_once_with("bob", "", send_email_flag=True)
|
||||||
|
|
||||||
|
|
||||||
def test_main_dispatches_revoke(monkeypatch):
|
def test_main_dispatches_revoke(monkeypatch):
|
||||||
@@ -198,3 +198,25 @@ def test_main_no_args_launches_tui(monkeypatch):
|
|||||||
monkeypatch.setattr("openvpncertupdate.CursesApp", lambda: app)
|
monkeypatch.setattr("openvpncertupdate.CursesApp", lambda: app)
|
||||||
main()
|
main()
|
||||||
app.run.assert_called_once_with()
|
app.run.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# --send-email / --no-send-email
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_no_send_email_skips_delivery(monkeypatch, capsys):
|
||||||
|
mocks = _patch_issue(monkeypatch)
|
||||||
|
monkeypatch.setattr("openvpncertupdate.get_email", MagicMock(return_value=""))
|
||||||
|
CliRunner().create("alice", "alice@example.com", send_email_flag=False)
|
||||||
|
mocks["send_email"].assert_not_called()
|
||||||
|
out = capsys.readouterr().out
|
||||||
|
assert "config:" in out
|
||||||
|
|
||||||
|
|
||||||
|
def test_main_no_send_email_flag(monkeypatch):
|
||||||
|
monkeypatch.setattr(sys, "argv",
|
||||||
|
["prog", "--reissue", "bob", "--no-send-email"])
|
||||||
|
runner = MagicMock()
|
||||||
|
monkeypatch.setattr("openvpncertupdate.CliRunner", lambda: runner)
|
||||||
|
main()
|
||||||
|
runner.reissue.assert_called_once_with("bob", "", send_email_flag=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user