From 31c679f212c1fd05b91c85e2aee4259a67a1b837 Mon Sep 17 00:00:00 2001 From: codex Date: Thu, 8 Oct 2026 23:13:17 +0200 Subject: [PATCH] Prepare empty OpenBao slots for the two backup publisher pairs. Version 1 names both AWS fields and holds a placeholder. The founder enters the real keys as the next version. Assistant: grok Assistant-Session: 01a11cdb-f9fe-7011-947c-936e72007e54 --- scripts/prepare-backup-pair-slots.py | 102 ++++++++++++++++++ ...WP-0053-coulomb-paired-backup-admission.md | 6 +- 2 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 scripts/prepare-backup-pair-slots.py diff --git a/scripts/prepare-backup-pair-slots.py b/scripts/prepare-backup-pair-slots.py new file mode 100644 index 0000000..628bc10 --- /dev/null +++ b/scripts/prepare-backup-pair-slots.py @@ -0,0 +1,102 @@ +#!/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 diff --git a/workplans/RPF-WP-0053-coulomb-paired-backup-admission.md b/workplans/RPF-WP-0053-coulomb-paired-backup-admission.md index b389ae2..0296c23 100644 --- a/workplans/RPF-WP-0053-coulomb-paired-backup-admission.md +++ b/workplans/RPF-WP-0053-coulomb-paired-backup-admission.md @@ -230,8 +230,10 @@ remain open; no credentials delivered, productive capture/upload or timer enable intended writer policy is `backup-pair-writer` and The founder admitted this writer on 2026-10-08, using the words "bucket-pair-writer". The policy name remains `backup-pair-writer` (`openbao/policies/backup-pair-writer.hcl`). The installed policy matches -that file, and `WRITER_ADMITTED` is true. Both backup-primary KV paths are -absent. The bootstrap key cannot list IAM applications (403). The live bucket +that file, and `WRITER_ADMITTED` is true. Both backup-primary KV paths were absent. Version 1 now exists on each +path, with both field names set to a non-credential placeholder. The founder +will write the real pairs as a new UI version. The bootstrap key cannot list +IAM applications (403). The live bucket policy still names only application ee80333e-5bab-4a04-85a9-5bdb46b7b3c1 on `platform-pg/*`. No publisher key was created. T05 stays wait for the two console-created applications and their CAS=0 pairs. An admitted writer, covered