feat: add 'muxplex generate-federation-key' CLI command

This commit is contained in:
Brian Krabach
2026-04-01 10:15:38 -07:00
parent 8e779b49b9
commit 1f90613030
2 changed files with 56 additions and 0 deletions
+20
View File
@@ -125,6 +125,19 @@ def _check_for_update(info: dict) -> tuple[bool, str]:
return True, "unknown install source — upgrading to be safe" return True, "unknown install source — upgrading to be safe"
def generate_federation_key() -> None:
"""Generate a random federation key and write it to FEDERATION_KEY_PATH."""
import muxplex.settings as settings_mod
path = settings_mod.FEDERATION_KEY_PATH
path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
key = _secrets.token_urlsafe(32)
path.write_text(key + "\n")
path.chmod(0o600)
print(f"Federation key written to {path}")
print(f"Key: {key}")
def reset_secret() -> None: def reset_secret() -> None:
"""Regenerate the signing secret and warn that all sessions are now invalid.""" """Regenerate the signing secret and warn that all sessions are now invalid."""
path = get_secret_path() path = get_secret_path()
@@ -675,6 +688,11 @@ def main() -> None:
"reset-secret", help="Regenerate signing secret (invalidates sessions)" "reset-secret", help="Regenerate signing secret (invalidates sessions)"
) )
sub.add_parser(
"generate-federation-key",
help="Generate a random federation key and write it to disk",
)
sub.add_parser("doctor", help="Check dependencies and system status") sub.add_parser("doctor", help="Check dependencies and system status")
upgrade_parser = sub.add_parser( upgrade_parser = sub.add_parser(
@@ -707,6 +725,8 @@ def main() -> None:
show_password() show_password()
elif args.command == "reset-secret": elif args.command == "reset-secret":
reset_secret() reset_secret()
elif args.command == "generate-federation-key":
generate_federation_key()
elif args.command == "doctor": elif args.command == "doctor":
doctor() doctor()
elif args.command in ("upgrade", "update"): elif args.command in ("upgrade", "update"):
+36
View File
@@ -1021,6 +1021,42 @@ def test_config_subcommand_registered():
assert "reset" in result.stdout assert "reset" in result.stdout
# ---------------------------------------------------------------------------
# task-3: generate-federation-key subcommand tests
# ---------------------------------------------------------------------------
def test_generate_federation_key_creates_file(tmp_path, monkeypatch, capsys):
"""generate_federation_key() creates key file with mode 0600 and prints key info."""
import muxplex.settings as settings_mod
key_file = tmp_path / ".config" / "muxplex" / "federation_key"
monkeypatch.setattr(settings_mod, "FEDERATION_KEY_PATH", key_file)
from muxplex.cli import generate_federation_key
generate_federation_key()
# File must exist
assert key_file.exists(), "Federation key file must be created"
# Content must be longer than 20 chars (stripping the trailing newline)
content = key_file.read_text().strip()
assert len(content) > 20, f"Key must be > 20 chars, got {len(content)}"
# File mode must be 0600
file_mode = stat.S_IMODE(key_file.stat().st_mode)
assert file_mode == 0o600, f"Expected 0o600, got {oct(file_mode)}"
# Output must include key info
captured = capsys.readouterr()
assert "federation" in captured.out.lower() or "key" in captured.out.lower(), (
f"Output must mention key info, got: {captured.out!r}"
)
# The actual key value must appear in output
assert content in captured.out, "Key value must appear in output"
def test_upgrade_uses_service_module_install(monkeypatch, capsys): def test_upgrade_uses_service_module_install(monkeypatch, capsys):
"""upgrade() must call muxplex.service.service_install.""" """upgrade() must call muxplex.service.service_install."""
import subprocess import subprocess