net-kingdom/sso-mfa/k8s/keycape/test_bind_env_adapter.py
tegwick 6fbce73b87 NK-WP-0048-T27: bind-env adapter source candidate (references only)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 903097@bnt-lap001
Assistant-Session: aa320c8f-c3fa-46e7-8541-0b58e1e45d23
2026-10-17 07:55:04 +02:00

103 lines
4.7 KiB
Python

"""Synthetic-only tests for the T27 bind-env candidate; no cluster, no values."""
import copy
import importlib.util
from pathlib import Path
import unittest
ROOT = Path(__file__).parent
spec = importlib.util.spec_from_file_location('bind_env_adapter', ROOT / 'bind-env-adapter.py')
a = importlib.util.module_from_spec(spec)
spec.loader.exec_module(a)
spec = importlib.util.spec_from_file_location('bind_env_fixture', ROOT / 'test_keycape_client.py')
f = importlib.util.module_from_spec(spec)
spec.loader.exec_module(f)
CASE = {'spec': {'type': 'oidc-browser-relying-party@1.1', 'parameters': f.FORGEJO_PARAMS}}
def deployment(env=None):
return {'kind': 'Deployment', 'metadata': {'name': 'keycape', 'namespace': 'sso', 'resourceVersion': '1'},
'spec': {'template': {'spec': {'containers': [
{'name': 'keycape', 'env': list(env or [{'name': 'KEYCAPE_CONFIG', 'value': '/etc/keycape/config.yaml'}])}]}}}}
class Store:
def __init__(self, d):
self.d, self.writes = d, []
def read(self):
return copy.deepcopy(self.d)
def write(self, new, rv):
if rv != self.d['metadata']['resourceVersion']:
raise RuntimeError('conflict')
self.d = copy.deepcopy(new)
self.d['metadata']['resourceVersion'] = str(int(rv) + 1)
self.writes.append(self.d)
return self.d['metadata']['resourceVersion']
class BindEnvTests(unittest.TestCase):
def test_binding_is_reference_only(self):
b = a.binding_for_case(CASE)
self.assertEqual(b['name'], 'KEYCAPE_FORGEJO_CLIENT_SECRET')
self.assertEqual(b['valueFrom']['secretKeyRef'], {'name': 'keycape-forgejo-client', 'key': 'client-secret'})
self.assertNotIn('value', b)
def test_run_then_created_only_rollback(self):
s = Store(deployment())
ref, run, rollback = a.build(case=CASE, expected_resource_version='1', read=s.read, write=s.write)
self.assertEqual(ref, a.REFERENCE)
r = run()
self.assertEqual((r['outcome'], r['created'], r['values_emitted']), ('success', ('KEYCAPE_FORGEJO_CLIENT_SECRET',), False))
self.assertEqual(len(s.d['spec']['template']['spec']['containers'][0]['env']), 2)
self.assertEqual(rollback()['outcome'], 'rolled-back')
self.assertEqual(s.d['spec']['template']['spec']['containers'][0]['env'], deployment()['spec']['template']['spec']['containers'][0]['env'])
with self.assertRaises(a.Refused):
rollback()
def test_existing_identical_binding_is_no_change_and_not_rollbackable(self):
s = Store(deployment([a.binding_for_case(CASE)]))
_, run, rollback = a.build(case=CASE, expected_resource_version='1', read=s.read, write=s.write)
self.assertEqual(run()['outcome'], 'no-change')
self.assertEqual(s.writes, [])
with self.assertRaises(a.Refused):
rollback()
def test_refusals(self):
other = dict(a.binding_for_case(CASE), valueFrom={'secretKeyRef': {'name': 'x', 'key': 'client-secret'}})
literal = {'name': 'KEYCAPE_FORGEJO_CLIENT_SECRET', 'value': 'synthetic'}
for env in ([other], [literal]):
s = Store(deployment(env))
_, run, _ = a.build(case=CASE, expected_resource_version='1', read=s.read, write=s.write)
with self.assertRaises(a.Refused):
run()
self.assertEqual(s.writes, [])
s = Store(deployment())
_, run, _ = a.build(case=CASE, expected_resource_version='0', read=s.read, write=s.write)
with self.assertRaises(a.Refused):
run()
with self.assertRaises(a.Refused):
a.build(case=CASE, expected_resource_version='1', read=s.read, write=s.write, allow_unimplemented=True)
public = {'spec': {'type': 'oidc-browser-relying-party@1.1',
'parameters': dict(f.FORGEJO_PARAMS, client_type='public', mfa_required='false')}}
with self.assertRaises(a.Refused):
a.binding_for_case(public)
with self.assertRaises(Exception):
a.binding_for_case({'spec': {'type': 'other@1', 'parameters': f.FORGEJO_PARAMS}})
with self.assertRaises(a.Refused):
a.plan(dict(deployment(), metadata={'name': 'keycape', 'namespace': 'other'}), a.binding_for_case(CASE))
with self.assertRaises(a.Refused):
a.plan(deployment(), dict(a.binding_for_case(CASE), value='synthetic'))
def test_rollback_refused_after_drift(self):
s = Store(deployment())
_, run, rollback = a.build(case=CASE, expected_resource_version='1', read=s.read, write=s.write)
run()
s.d['metadata']['resourceVersion'] = '9'
with self.assertRaises(a.Refused):
rollback()
if __name__ == '__main__':
unittest.main()