net-kingdom/sso-mfa/k8s/keycape/test_openbao_negative_session.py
tegwick bf6a44db6d
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Bound JWT private input and gate native effects on public health
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 17:30:10 +02:00

605 lines
30 KiB
Python

import base64
import copy
import importlib.util
import json
from pathlib import Path
import time
import io
import os
import urllib.error
import signal
import threading
import unittest
from unittest.mock import patch
spec = importlib.util.spec_from_file_location('session', Path(__file__).with_name('openbao-negative-session.py'))
s = importlib.util.module_from_spec(spec)
spec.loader.exec_module(s)
def baseline():
reference = dict(s.registrations()[-1], clientId='secrets-engine-openbao',
secretRef='env:PRODUCTION', tokenLifetime='15m')
return '# preserve this comment\nclients:\n' + s.yaml.safe_dump([reference], sort_keys=False) + 'other: unchanged\n'
def envelope():
return {'proposal_id': s.PROPOSAL, 'target': s.TARGET, 'disposition': 'approved',
'founder_decision_id': 'fixture-decision',
'source_hashes': {str(Path(s.__file__).resolve()): s.digest(Path(s.__file__).read_bytes())},
'owner_acknowledgments': {o: 'fixture-owner-review' for o in
['net-kingdom', 'key-cape', 'railiance-platform']},
'valid_until_epoch': time.time() + 900, 'maximum_session_seconds': 900,
'bao_addr': 'http://openbao.openbao.svc:8200',
'bao_health_identity_sha256': s.digest(b'fixture-health-cluster'),
'role_observation': {'mount': 'keycape-services', 'role': 'secrets-engine-openbao',
'issuer': 'https://kc.coulomb.social', 'algorithm': 'RS256',
'bindings_exact': True, 'policy_exact': True, 'raw_expiration_leeway': 0,
'effective_expiration_leeway': 150, 'observed_at_epoch': time.time()}}
class Tests(unittest.TestCase):
def setUp(self):
s.REQUEST_DEADLINE = None
s.BUSINESS_MONOTONIC_DEADLINE = None
s.CLEANUP_MONOTONIC_DEADLINE = None
s.CLEANING = False
def test_preserve_original_bytes(self):
raw = baseline()
result = s.candidate_config(raw)
start = result.index('clientId: openbao-probe-aud')
self.assertIn('# preserve this comment', result[:start])
parsed = s.yaml.safe_load(result)
self.assertEqual(parsed['clients'][:-6], s.yaml.safe_load(raw)['clients'])
self.assertEqual(parsed['other'], 'unchanged')
def test_isolation_and_sixth_matching_expiry(self):
clients = s.registrations()
self.assertNotIn('audience', clients[0])
for c in clients[1:]:
self.assertEqual(c['audience'], 'secrets-engine-openbao')
for key in ['roles', 'tenant', 'serviceSubject', 'allowedScopes']:
self.assertEqual(clients[-1][key], s.yaml.safe_load(baseline())['clients'][0][key])
def test_preexisting_probe_refused(self):
raw = baseline().replace('other: unchanged', '- clientId: openbao-probe-aud\nother: unchanged')
with self.assertRaises(s.Refused):
s.candidate_config(raw)
def test_duplicate_yaml_refused(self):
with self.assertRaises(s.Refused):
s.candidate_config(baseline() + 'other: shadow\n')
def test_production_drift_refused(self):
with self.assertRaises(s.Refused):
s.candidate_config(baseline().replace('tenant:platform', 'tenant:other'))
def test_env_collision_refused(self):
spec = {'replicas': 1, 'strategy': {'type': 'Recreate'}, 'template': {'spec': {'containers': [
{'name': 'keycape', 'env': [{'name': s.ENVS[0], 'value': 'fixture'}]}]}}}
with self.assertRaises(s.Refused):
s.candidate_spec(spec)
def test_recovery_roundtrip_preserves_every_baseline_byte(self):
raw = baseline()
self.assertEqual(s.recovered_config(s.candidate_config(raw)), raw)
self.assertEqual(s.recovered_config(raw), raw)
def test_recovery_claim_drift_and_partial_registration_refused(self):
raw = s.candidate_config(baseline())
with self.assertRaises(s.Refused):
s.recovered_config(raw.replace('service:openbao-probe', 'service:changed'))
with self.assertRaises(s.Refused):
s.recovered_config(raw.replace('clientId: openbao-probe-aud', 'clientId: different-probe'))
def test_recovery_env_roundtrip(self):
spec = {'replicas': 1, 'strategy': {'type': 'Recreate'}, 'template': {'spec': {'containers': [
{'name': 'keycape', 'env': [{'name': 'ORIGINAL', 'value': 'fixture'}]}]}}}
self.assertEqual(s.recovered_spec(s.candidate_spec(spec)), spec)
def test_approval_is_not_optional(self):
e = envelope()
del e['founder_decision_id']
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_source_change_refused(self):
e = envelope()
e['source_hashes'][str(Path(s.__file__).resolve())] = '0' * 64
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_owner_missing_refused(self):
e = envelope()
del e['owner_acknowledgments']['net-kingdom']
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_leeway_default_and_disabled(self):
e = envelope()
self.assertEqual(s.verify_sources(e), 150)
e['role_observation'].update(raw_expiration_leeway=-1, effective_expiration_leeway=0)
self.assertEqual(s.verify_sources(e), 0)
def test_stale_role_refused(self):
e = envelope()
e['role_observation']['observed_at_epoch'] -= 301
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_wrong_effective_leeway_refused(self):
e = envelope()
e['role_observation']['effective_expiration_leeway'] = 0
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_bao_credentials_in_origin_refused(self):
e = envelope()
e['bao_addr'] = 'https://user:password@example.invalid'
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_future_role_observation_refused(self):
e = envelope()
e['role_observation']['observed_at_epoch'] = time.time() + 60
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_arbitrary_https_origin_refused(self):
e = envelope()
e['bao_addr'] = 'https://attacker.invalid'
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_hostile_proxy_is_disabled(self):
build = s.urllib.request.build_opener
with patch.dict(os.environ, {'HTTPS_PROXY':'http://hostile-proxy.invalid:8000',
'HTTP_PROXY':'http://hostile-proxy.invalid:8000'}), \
patch.object(s.urllib.request, 'build_opener', wraps=build) as observed:
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
handlers = observed.call_args.args
self.assertIsInstance(handlers[0], s.urllib.request.ProxyHandler)
self.assertEqual(handlers[0].proxies, {})
self.assertIsInstance(handlers[1], s.NoRedirect)
self.assertIsNone(handlers[1].redirect_request(None, None, 302, '', {}, 'https://hostile.invalid'))
def test_redirect_never_follows_or_counts_as_refusal(self):
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
response = urllib.error.HTTPError('https://kc.coulomb.social/token', 302,
'redirect', {}, io.BytesIO(b'{}'))
with patch.object(transport.opener, 'open', side_effect=response) as observed:
status, raw = transport.post('https://kc.coulomb.social/token', form={})
self.assertEqual(status, 302)
self.assertEqual(observed.call_count, 1)
def test_oversized_http_body_is_closed_and_refused(self):
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
response = type('Response', (), {'getcode':lambda self: 200,
'read':lambda self, size: b'x' * size, 'close':lambda self: setattr(self, 'closed', True)})()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, 'http_response_oversized'):
transport.post('https://kc.coulomb.social/token', form={})
self.assertTrue(response.closed)
def test_expired_window_prevents_protected_kubernetes_and_http(self):
s.REQUEST_DEADLINE = time.time() - 1
with patch.object(s.subprocess, 'run') as backend:
with self.assertRaisesRegex(s.Refused, 'approved_window_expired'):
s.k(['create', '-f', '/dev/stdin'], {})
backend.assert_not_called()
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
with patch.object(transport.opener, 'open') as backend:
with self.assertRaisesRegex(s.Refused, 'approved_window_expired'):
transport.post('https://kc.coulomb.social/token', form={})
backend.assert_not_called()
def test_cleanup_revoke_allowed_after_window_expiry(self):
s.REQUEST_DEADLINE = time.time() - 1
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
response = type('Response', (), {'getcode':lambda self: 204,
'read':lambda self, size: b'', 'close':lambda self: None})()
with patch.object(transport.opener, 'open', return_value=response):
self.assertEqual(transport.post('http://openbao.openbao.svc:8200/v1/auth/token/revoke-self'), (204, b''))
def test_http_read_has_finite_size(self):
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
sizes = []
response = type('Response', (), {'getcode':lambda self: 200,
'read':lambda self, size: sizes.append(size) or b'{}', 'close':lambda self: None})()
with patch.object(transport.opener, 'open', return_value=response):
transport.post('https://kc.coulomb.social/token')
self.assertEqual(sizes, [s.MAX_RESPONSE + 1])
def test_nonfinite_and_boolean_timestamps_refused(self):
for value in [float('inf'), float('-inf'), float('nan'), True, False, 'Infinity', 10 ** 1000]:
for field in ['valid_until_epoch', 'observed_at_epoch']:
with self.subTest(field=field, value_type=type(value).__name__):
e = envelope()
if field == 'valid_until_epoch':
e[field] = value
else:
e['role_observation'][field] = value
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_finite_far_future_and_noninteger_window_refused(self):
e = envelope()
e['valid_until_epoch'] = time.time() + 86400
with self.assertRaises(s.Refused):
s.verify_sources(e)
for value in [True, 900.0, float('inf'), float('nan'), '900']:
e = envelope()
e['maximum_session_seconds'] = value
with self.assertRaises(s.Refused):
s.verify_sources(e)
def test_recovery_also_requires_finite_typed_window(self):
e = envelope()
e['disposition'] = 'recovery-approved'
e['valid_until_epoch'] = float('inf')
with self.assertRaises(s.Refused):
s.verify_sources(e, recovery=True)
def test_nonfinite_json_constants_refused(self):
for constant in ['Infinity', '-Infinity', 'NaN']:
with self.assertRaises(s.Refused):
s.read_json('{"valid_until_epoch":' + constant + '}')
self.assertFalse(s.finite_number(s.read_json('{"valid_until_epoch":1e999}')['valid_until_epoch']))
def test_hard_timer_covers_slow_trickle_body_and_closes_response(self):
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
class Trickle:
def getcode(self):
return 200
def read(self, size):
for _ in range(100):
time.sleep(0.01)
return b'{}'
def close(self):
self.closed = True
response = Trickle()
previous = signal.getsignal(signal.SIGALRM)
started = time.monotonic()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, 'request_total_timeout'):
transport.post('https://kc.coulomb.social/token', timeout=0.04)
self.assertLess(time.monotonic() - started, 0.25)
self.assertTrue(response.closed)
self.assertIs(signal.getsignal(signal.SIGALRM), previous)
self.assertEqual(signal.getitimer(signal.ITIMER_REAL), (0.0, 0.0))
def test_hard_timer_spans_headers_and_clips_to_business_window(self):
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
s.REQUEST_DEADLINE = time.time() + 60
s.BUSINESS_MONOTONIC_DEADLINE = time.monotonic() + 0.04
def slow_headers(*args, **kwargs):
time.sleep(1)
raise AssertionError('inactivity timeout would have permitted this')
started = time.monotonic()
with patch.object(transport.opener, 'open', side_effect=slow_headers):
with self.assertRaisesRegex(s.Refused, 'request_total_timeout'):
transport.post('https://kc.coulomb.social/token')
self.assertLess(time.monotonic() - started, 0.25)
def test_late_full_acceptance_is_revoked_then_refused(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
token = 'not-a-real-late-token'
class Late:
def getcode(self):
return 200
def read(self, size):
s.REQUEST_DEADLINE = time.time() - 1
return json.dumps({'auth': {'client_token': token}}).encode()
def close(self):
pass
revoke = type('Response', (), {'getcode':lambda self: 204,
'read':lambda self, size: b'', 'close':lambda self: None})()
with patch.object(transport.opener, 'open', side_effect=[Late(), revoke]) as calls:
with self.assertRaisesRegex(s.Refused, 'approved_window_expired'):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login')
self.assertEqual(calls.call_count, 2)
self.assertEqual(calls.call_args_list[1].args[0].full_url,
'http://openbao.openbao.svc:8200/v1/auth/token/revoke-self')
self.assertTrue(receipt['late_acceptance_revoke_attempted'])
self.assertTrue(receipt['late_acceptance_revoke_succeeded'])
self.assertNotIn(token, json.dumps(receipt))
def test_late_acceptance_failed_revoke_remains_unconfirmed(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
class Late:
def getcode(self):
return 200
def read(self, size):
s.REQUEST_DEADLINE = time.time() - 1
return b'{"auth":{"client_token":"fake-token"}}'
def close(self):
pass
failed = type('Response', (), {'getcode':lambda self: 403,
'read':lambda self, size: b'{}', 'close':lambda self: None})()
with patch.object(transport.opener, 'open', side_effect=[Late(), failed]):
with self.assertRaises(s.Refused):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login')
self.assertTrue(receipt['late_acceptance_revoke_attempted'])
self.assertFalse(receipt['late_acceptance_revoke_succeeded'])
def test_partial_accepted_response_timeout_retains_unknown_outcome(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
response = type('Response', (), {'getcode':lambda self: 200,
'read':lambda self, size: time.sleep(1), 'close':lambda self: None})()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, 'request_total_timeout'):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login', timeout=0.04)
self.assertTrue(receipt['openbao_login_outcome_unknown'])
def test_cleanup_has_finite_aggregate_deadline_and_restoration(self):
s.REQUEST_DEADLINE = time.time() - 1
s.begin_cleanup()
first = s.CLEANUP_MONOTONIC_DEADLINE
s.begin_cleanup()
self.assertEqual(s.CLEANUP_MONOTONIC_DEADLINE, first)
s.CLEANUP_MONOTONIC_DEADLINE = time.monotonic() - 1
s.CLEANING = True
with self.assertRaisesRegex(s.Refused, 'cleanup_budget_expired'):
s.check_deadline()
transport = s.SessionTransport('http://openbao.openbao.svc:8200')
with patch.object(transport.opener, 'open') as backend:
with self.assertRaises(s.Refused):
transport.post('http://openbao.openbao.svc:8200/v1/auth/token/revoke-self')
backend.assert_not_called()
def test_expired_cleanup_cannot_issue_native_secret_delete(self):
s.CLEANING = True
s.CLEANUP_MONOTONIC_DEADLINE = time.monotonic() - 1
obj = {'metadata': {'uid':'temporary', 'resourceVersion':'7'}}
with patch.object(s.subprocess, 'run') as native:
with self.assertRaisesRegex(s.Refused, 'cleanup_budget_expired'):
s.delete_temporary(obj)
native.assert_not_called()
def test_secret_delete_total_timeout_clipped_to_cleanup_budget(self):
s.CLEANING = True
s.CLEANUP_MONOTONIC_DEADLINE = time.monotonic() + 0.04
obj = {'metadata': {'uid':'temporary', 'resourceVersion':'7'}}
captured = {}
def slow_delete(args, **kwargs):
captured.update(kwargs)
time.sleep(1)
return type('Result', (), {'returncode':0, 'stdout':'{}'})()
started = time.monotonic()
with patch.object(s.subprocess, 'run', side_effect=slow_delete):
with self.assertRaisesRegex(s.Refused, 'request_total_timeout'):
s.delete_temporary(obj)
self.assertLess(time.monotonic() - started, 0.25)
self.assertLessEqual(captured['timeout'], 0.04)
self.assertEqual(json.loads(captured['input'])['preconditions'], {'uid':'temporary', 'resourceVersion':'7'})
def test_early_read_failure_slow_close_is_bounded_once(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
class Response:
closes = 0
def getcode(self):
return 200
def read(self, size):
raise s.Refused('synthetic_read_failure')
def close(self):
self.closes += 1
time.sleep(0.07)
response = Response()
previous = signal.getsignal(signal.SIGALRM)
started = time.monotonic()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, 'http_response_abort_unconfirmed'):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login', timeout=0.01)
self.assertLess(time.monotonic() - started, 0.05)
self.assertEqual(response.closes, 1)
self.assertTrue(receipt['openbao_login_outcome_unknown'])
self.assertTrue(receipt['http_abort_close_attempted'])
self.assertFalse(receipt['http_abort_close_succeeded'])
self.assertTrue(receipt['http_response_abort_unconfirmed'])
self.assertIs(signal.getsignal(signal.SIGALRM), previous)
self.assertEqual(signal.getitimer(signal.ITIMER_REAL), (0.0, 0.0))
def test_total_read_timeout_then_slow_close_uses_only_abort_cap(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
class Response:
closes = 0
def getcode(self):
return 200
def read(self, size):
time.sleep(0.1)
def close(self):
self.closes += 1
time.sleep(0.1)
response = Response()
started = time.monotonic()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, 'http_response_abort_unconfirmed'):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login', timeout=0.01)
self.assertLess(time.monotonic() - started, 0.06)
self.assertEqual(response.closes, 1)
self.assertTrue(receipt['openbao_login_outcome_unknown'])
self.assertFalse(receipt['http_abort_close_succeeded'])
def test_oversized_body_slow_abort_remains_unproved_and_bounded(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
response = type('Response', (), {'getcode':lambda self: 200,
'read':lambda self, size: b'x' * size,
'close':lambda self: time.sleep(0.1)})()
started = time.monotonic()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, 'http_response_abort_unconfirmed'):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login', timeout=0.01)
self.assertLess(time.monotonic() - started, 0.05)
self.assertTrue(receipt['openbao_login_outcome_unknown'])
self.assertFalse(receipt['http_abort_close_succeeded'])
def test_raising_normal_close_then_slow_abort_is_private_bounded_unknown(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
class Response:
closes = 0
def getcode(self):
return 200
def read(self, size):
return b'{}'
def close(self):
self.closes += 1
if self.closes == 1:
raise RuntimeError('private protected error must not escape')
time.sleep(0.1)
response = Response()
previous = signal.getsignal(signal.SIGALRM)
started = time.monotonic()
with patch.object(transport.opener, 'open', return_value=response):
with self.assertRaisesRegex(s.Refused, '^http_response_abort_unconfirmed$'):
transport.post('http://openbao.openbao.svc:8200/v1/auth/keycape-services/login', timeout=0.01)
self.assertLess(time.monotonic() - started, 0.05)
self.assertEqual(response.closes, 2)
self.assertTrue(receipt['openbao_login_outcome_unknown'])
self.assertFalse(receipt['http_abort_close_succeeded'])
self.assertIs(signal.getsignal(signal.SIGALRM), previous)
self.assertEqual(signal.getitimer(signal.ITIMER_REAL), (0.0, 0.0))
def test_expired_cleanup_never_attempts_exceptional_close_or_resets(self):
receipt = {}
transport = s.SessionTransport('http://openbao.openbao.svc:8200', receipt=receipt)
deadline = time.monotonic() - 1
s.CLEANUP_MONOTONIC_DEADLINE = deadline
response = type('Response', (), {'close':lambda self: self.fail('must not close')})()
with patch.object(response, 'close') as closes:
with self.assertRaisesRegex(s.Refused, 'http_response_abort_unconfirmed'):
transport.abort_response(response, time.monotonic() - 1)
closes.assert_not_called()
self.assertEqual(s.CLEANUP_MONOTONIC_DEADLINE, deadline)
self.assertFalse(receipt['http_abort_close_attempted'])
self.assertTrue(receipt['http_response_abort_unconfirmed'])
def test_thread_or_existing_timer_refused_without_overwrite(self):
results = []
def in_thread():
try:
with s.total_timeout(0.1):
results.append('unreachable')
except s.Refused:
results.append('refused')
thread = threading.Thread(target=in_thread)
thread.start()
thread.join()
self.assertEqual(results, ['refused'])
signal.setitimer(signal.ITIMER_REAL, 1)
try:
with self.assertRaisesRegex(s.Refused, 'existing_alarm_timer_refused'):
with s.total_timeout(0.1):
pass
self.assertGreater(signal.getitimer(signal.ITIMER_REAL)[0], 0.5)
finally:
signal.setitimer(signal.ITIMER_REAL, 0)
def test_cleanup_refuses_concurrent_registry_change(self):
self.lifecycle(drift=True)
def test_deleted_client_contract_is_specific(self):
self.assertTrue(s.removed_client_denied(401, b'{"error":"invalid_profile_usage","feature":"client_id"}'))
for status, body in [(503, b'{}'), (401, b'{"error":"invalid_profile_usage","feature":"Authorization"}'),
(401, b'{"error":"invalid_client"}'), (401, b'not-json')]:
self.assertFalse(s.removed_client_denied(status, body))
def test_cleanup_even_when_probe_fails(self):
self.lifecycle(probe_pass=False)
def test_complete_lifecycle(self):
self.lifecycle()
def lifecycle(self, drift=False, probe_pass=True):
raw = baseline()
dep_spec = {'replicas': 1, 'strategy': {'type': 'Recreate'}, 'template': {'spec': {'containers': [
{'name': 'keycape', 'image': 'fixture@sha256:abc', 'env': []}]}}}
objects = {'keycape-config': {'metadata': {'name': 'keycape-config', 'uid': 'cfg', 'resourceVersion': '1'},
'data': {'config.yaml': base64.b64encode(raw.encode()).decode(),
'key.pem': 'FAKE_KEY_NOT_READ'}},
'keycape': {'metadata': {'name': 'keycape', 'uid': 'dep', 'resourceVersion': '1'},
'spec': dep_spec}}
original = copy.deepcopy(objects)
e = envelope()
e.update(runner_path='fake-runner', config_metadata=s.meta(objects['keycape-config']),
deployment_metadata=s.meta(objects['keycape']), deployment_spec_sha256=s.canonical(dep_spec),
registry_sha256=s.digest(raw.encode()))
e['source_hashes']['fake-runner'] = 'fixture'
receipt = {'cleanup_verified': False}
class Probe:
def exchange(self, *args):
return 'fixture-token'
def http_post(self, *args, **kwargs):
return 401, b'{"error":"invalid_profile_usage","feature":"client_id"}'
def run(self, *args, **kwargs):
if drift:
objects['keycape-config']['data']['unrelated'] = 'concurrent-owner-change'
return {'all_refused': probe_pass}
def kube(args, payload=None):
if args[0] == 'get':
return {'metadata': {'uid': s.CLUSTER}}
if args[0] == 'create':
if '--dry-run=server' in args:
return copy.deepcopy(payload)
created = copy.deepcopy(payload)
created['metadata'].update(uid='temp', resourceVersion='1')
objects[s.TEMP] = created
return created
if args[0] == 'delete':
self.assertEqual(payload['preconditions'], {'uid':'temp', 'resourceVersion':'1'})
del objects[s.TEMP]
return {'kind':'Status', 'status':'Success'}
if '--ignore-not-found' in args:
return objects.get(s.TEMP)
raise AssertionError('unexpected kube call')
def patched(kind, obj, path, value, dry=False):
result = copy.deepcopy(obj)
if path == '/spec':
result['spec'] = copy.deepcopy(value)
else:
result['data']['config.yaml'] = value
if not dry:
objects[obj['metadata']['name']] = result
return result
def delete(*args, **kwargs):
del objects[s.TEMP]
return type('Result', (), {'returncode': 0})()
class Discovery:
def __enter__(self):
import io
return io.StringIO('{"issuer":"https://kc.coulomb.social","token_endpoint":"https://kc.coulomb.social/token"}')
def __exit__(self, *args):
pass
with patch.object(s, 'verify_sources', return_value=150), patch.object(s, 'load_probe', return_value=Probe()), \
patch.object(s, 'SessionTransport') as transport_factory, \
patch.object(s, 'k', side_effect=kube), patch.object(s, 'get', side_effect=lambda kind, name: copy.deepcopy(objects[name])), \
patch.object(s, 'patch', side_effect=patched), patch.object(s, 'ready', return_value=True), \
patch.object(s.subprocess, 'run', side_effect=delete):
transport_factory.return_value.discovery.return_value = {
'issuer':'https://kc.coulomb.social', 'token_endpoint':'https://kc.coulomb.social/token'}
transport_factory.return_value.health_identity.return_value = e['bao_health_identity_sha256']
transport_factory.return_value.post.side_effect = Probe().http_post
if drift or not probe_pass:
with self.assertRaises(s.Refused):
s.execute(e, {'human_token': 'fake', 'coding_agent_token': 'fake'}, receipt)
else:
s.execute(e, {'human_token': 'fake', 'coding_agent_token': 'fake'}, receipt)
if drift:
self.assertFalse(receipt['cleanup_verified'])
self.assertIn(s.TEMP, objects)
self.assertEqual(objects['keycape-config']['data']['unrelated'], 'concurrent-owner-change')
else:
self.assertTrue(receipt['cleanup_verified'])
self.assertNotIn(s.TEMP, objects)
self.assertEqual(objects['keycape-config']['data'], original['keycape-config']['data'])
self.assertEqual(objects['keycape']['spec'], original['keycape']['spec'])
if __name__ == '__main__':
unittest.main()