#!/usr/bin/env python3 """Silent contained removal of the retired public callbacks from platform-admin. Removes exactly the two bao.coulomb.social callbacks retired by RPF-WP-0025-T03 from auth/netkingdom/role/platform-admin. Every other role setting is kept, using the reviewed read/payload/write helpers of the loopback-callback script. Refuses unless the tunnel callback is present and stays present. Writes nothing if the retired callbacks are already gone. One non-secret receipt; no output. """ from datetime import datetime, timezone import importlib.util import json import os from pathlib import Path import sys HERE = Path(__file__).resolve().parent _spec = importlib.util.spec_from_file_location('loopback', HERE / 'openbao_operator_loopback_callback.py') loopback = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(loopback) ROLE = loopback.ROLE KEEP = loopback.CALLBACK # http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback RETIRED = ( 'https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback', 'https://bao.coulomb.social/ui/vault/auth/keycape/oidc/callback', ) Refused = loopback.Refused MOUNTS = ('netkingdom', 'keycape') CONFIG_FIELDS = ('oidc_discovery_url', 'oidc_client_id', 'default_role', 'bound_issuer', 'oidc_response_mode', 'oidc_response_types', 'jwt_supported_algs', 'provider_config', 'namespace_in_state') def read_mount_configs(): """Non-secret OIDC mount settings; OpenBao never returns oidc_client_secret.""" import subprocess configs = {} for mount in MOUNTS: try: result = subprocess.run(['bao', 'read', '-format=json', 'auth/%s/config' % mount], capture_output=True, check=True, timeout=30) data = json.loads(result.stdout)['data'] configs[mount] = {key: data[key] for key in CONFIG_FIELDS if key in data} except Exception: configs[mount] = {'error': 'read_failed'} return configs def prune(read=loopback.read_role, write=loopback.write_role): original = read() uris = original['allowed_redirect_uris'] if KEEP not in uris: raise Refused('tunnel_callback_missing') remaining = [uri for uri in uris if uri not in RETIRED] if remaining == uris: return False, uris desired = dict(loopback.payload(original), allowed_redirect_uris=remaining) if loopback.preserved(read()) != loopback.preserved(original): raise Refused('role_changed_before_write') write(desired) after = read() if sorted(after.get('allowed_redirect_uris', [])) != sorted(remaining): raise Refused('readback_callbacks_mismatch') if loopback.preserved(after) != loopback.preserved(original): raise Refused('readback_settings_changed') return True, after['allowed_redirect_uris'] def write_receipt(path, status, **extra): fd = os.open(Path(path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) body = { 'schema': 'railiance-platform.openbao-callback-prune.v1', 'observed_at': datetime.now(timezone.utc).isoformat(), 'role': ROLE, 'retired': list(RETIRED), 'status': status, 'credential_values_emitted': False, **extra, } with os.fdopen(fd, 'w', encoding='utf-8') as handle: json.dump(body, handle, indent=2, sort_keys=True) handle.write('\n') def main(argv): if len(argv) != 2 or argv[0] != '--receipt': return 2 receipt = argv[1] try: loopback.require_attended() changed, uris = prune() write_receipt(receipt, 'pruned' if changed else 'already_pruned', changed=changed, allowed_redirect_uris=uris, mount_configs=read_mount_configs()) return 0 except Exception as error: try: write_receipt(receipt, loopback.classify(error), changed=False) except Exception: pass return 1 if __name__ == '__main__': raise SystemExit(main(sys.argv[1:]))