#!/usr/bin/env python3 """Rotate lab Ed25519 config key; re-sign payload; append admin-history.""" from __future__ import annotations import argparse import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "python")) from cryptography.hazmat.primitives.serialization import load_pem_private_key from secure_messaging.admin_history import AdminHistory from secure_messaging.signed_config import ( generate_signing_key, load_signed, pem_private, pem_public, save_signed, sign, ) def main() -> None: p = argparse.ArgumentParser() p.add_argument("--pem", default="/opt/pfc/etc/sm-keys/config.ed25519.pem") p.add_argument("--signed", default="/opt/pfc/etc/secure-messaging.signed.json") p.add_argument("--history", default="/opt/pfc/data/admin/admin-history") p.add_argument("--actor", default="rotate-lab") args = p.parse_args() pem = Path(args.pem) signed_path = Path(args.signed) old = load_pem_private_key(pem.read_bytes(), password=None) payload = load_signed(signed_path, old.public_key()) new = generate_signing_key() pem.rename(pem.with_suffix(pem.suffix + ".prev")) pem.write_bytes(pem_private(new)) pem.chmod(0o600) pub = pem.with_name("config.ed25519.pub.pem") pub.write_bytes(pem_public(new.public_key())) prev_text = signed_path.read_text() signed = sign(payload, new) save_signed(signed_path, signed) row = AdminHistory(Path(args.history)).append_change( actor=args.actor, prev_text=prev_text, new_text=signed.dumps() ) print("rotated key_id", signed.key_id, "history_seq", row.get("seq")) if __name__ == "__main__": main()