railiance-platform/scripts/keycape-approval-custody-preflight.py
tegwick a94d06dbcf
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
docs(custody): record attended KeyCape first-provision authority proof
Assistant: codex
Assistant-Model: gpt-5.6-luna
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
2026-09-08 22:40:04 +02:00

64 lines
2.8 KiB
Python

"""Read-only, silent owner preflight inside Warden's attended login envelope.
Queries only token capabilities for the exact two reviewed CCR targets. Reads
no secret data, applies no metadata, and does not record an approval. Warden
owns the temporary token helper and self-revokes after this command returns.
"""
import argparse
import json
import os
import subprocess
from datetime import datetime, timezone
from pathlib import Path
PATHS = [
'sys/policies/acl/workload-kv-read-keycape-secrets-engine-approval',
'sys/policies/acl/workload-kv-read-keycape-approval-engine-operator',
'auth/kubernetes/role/external-secrets-keycape-secrets-engine-approval',
'auth/kubernetes/role/external-secrets-keycape-approval-engine-operator',
'platform/data/workloads/secrets-engine/approval-client',
'platform/data/workloads/approval-engine/operator-client',
]
ALLOWED = {'create', 'read', 'update', 'patch', 'delete', 'list', 'sudo', 'deny', 'root'}
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--receipt", type=Path, required=True)
args = parser.parse_args()
receipt = {'observed_at': datetime.now(timezone.utc).isoformat(),
'requests': ['CCR-2026-0017', 'CCR-2026-0018'],
'operation': 'capabilities-self only', 'credential_data_read': False,
'metadata_applied': False, 'custody_activated': False,
'upstream_issuer_proven': False}
caps = {}
for path in PATHS:
# This installed CLI accepts one PATH. Supplying several positional
# arguments selects a different TOKEN/PATH form or refuses the call.
result = subprocess.run(['bao', 'token', 'capabilities', '-format=json', path],
capture_output=True, text=True, timeout=20)
if result.returncode:
receipt['status'] = 'capability-query-failed'
break
payload = json.loads(result.stdout)
values = payload if isinstance(payload, list) else payload.get('capabilities')
if not isinstance(values, list) or any(v not in ALLOWED for v in values):
raise ValueError('unexpected capability response shape')
caps[path] = sorted(set(values))
else:
receipt['status'] = 'observed'
receipt['capabilities'] = caps
receipt['required_metadata_capabilities_present'] = all(
{'create', 'update'}.issubset(values) for values in caps.values())
receipt['paths_verified'] = len(caps)
fd = os.open(args.receipt, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
with os.fdopen(fd, 'w') as stream:
json.dump(receipt, stream, indent=2)
stream.write('\n')
if __name__ == '__main__':
try:
main()
except Exception:
raise SystemExit(1) from None