#!/usr/bin/env python3 """Create the two empty backup-primary KV slots. One CAS=0 write per path stores both field names with the placeholder PENDING. The founder replaces that version in the OpenBao UI. No provider key is read or written. """ from __future__ import annotations import json import os import subprocess from pathlib import Path STAGE = Path("/home/worsch/.local/state/railiance/receipts/backup-pair-slots.stage") RECEIPT = Path("/home/worsch/.local/state/railiance/receipts/backup-pair-slots.json") PATHS = ( "platform/workloads/coulomb-social/backup-primary", "platform/workloads/email-connect/backup-primary", ) def stage(text): STAGE.parent.mkdir(mode=0o700, exist_ok=True) STAGE.write_text(text + "\n") STAGE.chmod(0o600) def run(args, token=None): env = os.environ.copy() if token is None: env.pop("BAO_TOKEN", None) env.pop("VAULT_TOKEN", None) else: env["BAO_TOKEN"] = token env["VAULT_TOKEN"] = token return subprocess.run(args, capture_output=True, env=env) def main(): created = run( [ "bao", "token", "create", "-policy=backup-pair-writer", "-ttl=5m", "-use-limit=3", "-orphan", "-format=json", ] ) if created.returncode: stage(f"token_create_failed {created.returncode}") raise SystemExit(51) token = json.loads(created.stdout)["auth"]["client_token"] body = Path(os.environ["HOME"]) / "backup-pair-slot.json" body.write_text(json.dumps({ "AWS_ACCESS_KEY_ID": "PENDING", "AWS_SECRET_ACCESS_KEY": "PENDING", })) body.chmod(0o600) puts = [] try: for path in PATHS: meta = run(["bao", "kv", "metadata", "get", "-format=json", path]) if meta.returncode == 0: stage(f"already_present {path}") raise SystemExit(52) put = run(["bao", "kv", "put", "-cas=0", path, f"@{body}"], token=token) puts.append({"path": path, "put_returncode": put.returncode}) if put.returncode: stage(f"put_failed {path} {put.returncode}") raise SystemExit(53) finally: body.unlink(missing_ok=True) run(["bao", "token", "revoke", "-self"], token=token) slots = [] for path in PATHS: meta = run(["bao", "kv", "metadata", "get", "-format=json", path]) if meta.returncode: slots.append({"path": path, "metadata_returncode": meta.returncode}) continue data = json.loads(meta.stdout)["data"] slots.append({ "path": path, "current_version": data.get("current_version"), "version_count": len(data.get("versions") or {}), }) RECEIPT.parent.mkdir(mode=0o700, exist_ok=True) RECEIPT.write_text(json.dumps({"slots": slots, "puts": puts}, indent=2) + "\n") RECEIPT.chmod(0o600) stage("ok") if __name__ == "__main__": try: main() except SystemExit: raise except Exception as exc: stage("failed " + type(exc).__name__) raise SystemExit(54) from None