railiance-platform/tests/test_keycape_secrets_engine_openbao_custody.py
codex 71607d277c
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Record founder approval 2ab717e1 on CCR-2026-0033/0034 and the ESO admission
The custody refusal test now checks proposed copies instead of the committed
CCRs, which are approved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 132360@bnt-lap001
Assistant-Session: 769b1afd-4330-4c86-96b2-e510e26db42b
2026-10-07 00:25:37 +02:00

214 lines
10 KiB
Python

"""CCR-2026-0033 custody child: synthetic values and fakes only; no OpenBao, cluster or real file."""
import contextlib
import copy
import io
import json
import os
from pathlib import Path
import sys
import tempfile
from types import SimpleNamespace
import unittest
from unittest.mock import patch
import yaml
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'scripts'))
import keycape_secrets_engine_openbao_custody as child # noqa: E402
DECISION = '00000000-0000-4000-8000-000000000033'
SYNTHETIC = 'synthetic-test-value-' + 'x' * 43
def result(code=0, stdout=b'', stderr=b''):
return SimpleNamespace(returncode=code, stdout=stdout, stderr=stderr)
class FakeBao:
"""KV-v2 metadata/data behaviour for one path; refuses data reads outright."""
def __init__(self, current=None, fail_write=False, metadata=None):
self.current, self.fail_write, self.calls, self.payloads = current, fail_write, [], []
self.metadata = metadata or {'cas_required': False, 'max_versions': 0,
'delete_version_after': '0s', 'custom_metadata': None}
self.metadata_writes = []
def __call__(self, args, *, payload=None, token=None, allow_failure=False):
self.calls.append(list(args))
if args[:2] == ['token', 'lookup']:
return result(stdout=json.dumps({'data': {'policies': ['default', 'platform-admin']}}).encode())
if args[0] == 'read' and args[-1] == child.KV_DATA:
raise AssertionError('data path read attempted')
if args[0] == 'read' and args[-1] == child.KV_METADATA:
if self.current is None:
return result(2, stderr=b'No value found at ' + child.KV_METADATA.encode())
body = dict(self.metadata, current_version=self.current,
versions={str(self.current): {'destroyed': False, 'deletion_time': ''}})
return result(stdout=json.dumps({'data': body}).encode())
if args[0] == 'write' and child.KV_METADATA in args:
self.metadata_writes.append(payload)
self.metadata.update(copy.deepcopy(payload))
return result()
if args[0] == 'write' and child.KV_DATA in args:
self.payloads.append(payload)
if self.fail_write or payload['options']['cas'] != (self.current or 0):
raise child.LaneError('command_failed')
self.current = (self.current or 0) + 1
return result(stdout=json.dumps({'request_id': 'req-1', 'data': {'version': self.current}}).encode())
raise AssertionError('unexpected bao call: ' + ' '.join(args[:2]))
def approve(path, base, name, decision=DECISION):
ccr = yaml.safe_load(path.read_text())
ccr['status'] = 'approved'
ccr['openbao']['auth']['bound_claims_confirmed'] = True
ccr['review']['comments'] = [
{'at': '2026-10-06', 'reviewer': r, 'decision': 'approved',
'comment': 'custody child approved by decision ' + decision} for r in child.APPROVERS]
out = base / name
out.write_text(yaml.safe_dump(ccr, sort_keys=False))
return out, ccr
class CustodyChild(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
base = Path(self.tmp.name)
self.ccr, data = approve(child.CCR_PATH, base, 'CCR-2026-0033.yaml')
self.desired = data['openbao']['kv_metadata']
self.sibling, _ = approve(child.SIBLING_PATH, base, 'CCR-2026-0034.yaml')
self.bao = FakeBao()
self.patches = [patch.object(child, 'CCR_PATH', self.ccr), patch.object(child, 'SIBLING_PATH', self.sibling),
patch.object(child, 'bao', self.bao), patch.object(child, 'attended_envelope', lambda: True),
patch.object(child.secrets, 'token_urlsafe', lambda n: SYNTHETIC)]
for p in self.patches:
p.start()
self.umask = os.umask(0o022)
def tearDown(self):
os.umask(self.umask)
for p in reversed(self.patches):
p.stop()
self.tmp.cleanup()
def run_child(self, *extra, decision=DECISION):
receipt = Path(self.tmp.name) / ('receipt-%d.json' % len(list(Path(self.tmp.name).glob('receipt-*'))))
out, err = io.StringIO(), io.StringIO()
argv = ['provision', '--receipt', str(receipt), *extra]
if decision is not None:
argv += ['--approval-decision', decision]
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
code = child.main(argv)
text = receipt.read_text()
for blob in (text, out.getvalue(), err.getvalue(), json.dumps(self.bao.calls), ' '.join(argv)):
self.assertNotIn(SYNTHETIC, blob)
self.assertEqual(out.getvalue(), '')
self.assertEqual(oct(receipt.stat().st_mode & 0o777), oct(0o600))
return code, json.loads(text)
def test_refuses_without_or_with_wrong_decision(self):
with self.assertRaises(SystemExit), contextlib.redirect_stderr(io.StringIO()):
child.main(['provision', '--receipt', str(Path(self.tmp.name) / 'r.json')])
for decision, reason in (('not-a-uuid', 'approval_decision_id_required'),
(child.BOUNDARY_DECISION, 'boundary_decision_does_not_approve_custody_child'),
('11111111-1111-4111-8111-111111111111', 'custody_child_decision_not_recorded_in_ccr')):
code, receipt = self.run_child(decision=decision)
self.assertEqual((code, receipt['error']), (1, reason))
self.assertEqual(self.bao.calls, [])
def proposed_copy(self, name):
text = (ROOT / 'credential-change-requests' / name).read_text()
path = Path(self.tmp.name) / name
path.write_text(text.replace('\nstatus: approved\n', '\nstatus: proposed\n', 1))
return path
def test_proposed_ccrs_are_refused(self):
with patch.object(child, 'CCR_PATH', self.proposed_copy('CCR-2026-0033.yaml')):
code, receipt = self.run_child()
self.assertEqual((code, receipt['error']), (1, 'approved_ccr_required'))
with patch.object(child, 'SIBLING_PATH', self.proposed_copy('CCR-2026-0034.yaml')):
code, receipt = self.run_child()
self.assertEqual((code, receipt['error']), (1, 'approved_ccr_required'))
self.assertEqual(self.bao.calls, [])
def test_refuses_ambient_token_or_outside_envelope(self):
with patch.object(child, 'attended_envelope', lambda: False):
code, receipt = self.run_child()
self.assertEqual(receipt['error'], 'attended_warden_envelope_required')
self.assertEqual(self.bao.calls, [])
self.patches[3].stop()
try:
with patch.object(child.Path, 'home', lambda: Path('/x/.warden-attended-login/u')):
with patch.dict(os.environ, {}, clear=False):
os.environ.pop('BAO_TOKEN', None)
os.environ.pop('VAULT_TOKEN', None)
self.assertTrue(child.attended_envelope())
for var in ('BAO_TOKEN', 'VAULT_TOKEN'):
with patch.dict(os.environ, {var: 'synthetic-ambient'}):
self.assertFalse(child.attended_envelope())
code, receipt = self.run_child()
self.assertEqual(receipt['error'], 'attended_warden_envelope_required')
finally:
self.patches[3].start()
self.assertEqual(self.bao.calls, [])
def test_create_writes_kv_cas0_and_metadata(self):
code, receipt = self.run_child()
self.assertEqual(code, 0)
self.assertEqual(receipt['status'], 'custody_written_pending_issuer_delivery')
self.assertEqual((receipt['kv_version'], receipt['kv_cas'], receipt['kv_metadata']), (1, 0, 'applied'))
self.assertEqual(self.bao.payloads, [{'options': {'cas': 0}, 'data': {'CLIENT_SECRET': SYNTHETIC}}])
self.assertEqual(self.bao.metadata_writes, [self.desired])
self.assertTrue(self.bao.metadata['cas_required'])
self.assertEqual(self.bao.metadata['max_versions'], 2)
self.assertEqual(self.bao.metadata['custom_metadata']['ccr'], 'CCR-2026-0033')
self.assertEqual(sorted(p.name for p in Path(self.tmp.name).iterdir()),
['CCR-2026-0033.yaml', 'CCR-2026-0034.yaml', 'receipt-0.json'])
def test_existing_entry_requires_rotate_and_rotation_uses_current_cas(self):
self.bao.current = 1
self.bao.metadata.update(copy.deepcopy(self.desired))
code, receipt = self.run_child()
self.assertEqual((code, receipt['error']), (1, 'existing_custody_requires_rotate'))
self.assertEqual(self.bao.payloads, [])
code, receipt = self.run_child('--rotate')
self.assertEqual((code, receipt['kv_cas'], receipt['kv_version'], receipt['kv_metadata']), (0, 1, 2, 'unchanged'))
self.assertEqual(self.bao.metadata_writes, [])
def test_rotate_without_entry_is_refused(self):
code, receipt = self.run_child('--rotate')
self.assertEqual((code, receipt['error']), (1, 'rotation_requires_existing_custody'))
self.assertEqual(self.bao.payloads, [])
def test_failed_kv_write_records_no_version_and_no_metadata(self):
self.bao.fail_write = True
code, receipt = self.run_child()
self.assertEqual((code, receipt['kv_written'], receipt['error']), (1, False, 'command_failed'))
self.assertEqual(self.bao.metadata_writes, [])
def test_metadata_readback_mismatch_fails_but_records_written_version(self):
real = self.bao.__call__
bao = self.bao
def wrapper(args, **kw):
if args[0] == 'write' and child.KV_METADATA in args:
bao.calls.append(list(args))
return result()
return real(args, **kw)
with patch.object(child, 'bao', wrapper):
code, receipt = self.run_child()
self.assertEqual((code, receipt['kv_written'], receipt['kv_version'], receipt['error']),
(1, True, 1, 'kv_metadata_readback_mismatch'))
def test_receipt_contains_only_metadata_keys(self):
_, receipt = self.run_child()
self.assertTrue(set(receipt) <= {
'schema', 'ccr', 'status', 'phase', 'started_at', 'finished_at', 'credential_values_emitted',
'client_side_read_admitted', 'kv_written', 'approval_decision_id', 'ccr_sha256',
'kv_version', 'kv_request_id', 'kv_cas', 'kv_metadata', 'error'})
self.assertFalse(any('consumer' in key for key in receipt))
if __name__ == '__main__':
unittest.main()