80 lines
3.5 KiB
Python
80 lines
3.5 KiB
Python
"""Exercise the real bootstrap shell with a local fake Vault transport."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
import yaml
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
MANIFEST = ROOT / 'services/keycloak/bootstrap-jobs/metis-node-passwords-secret-ensure-job.yaml'
|
|
FAKE_CURL = r'''#!/usr/bin/env python3
|
|
import json,os,pathlib,sys
|
|
args=sys.argv[1:]
|
|
state=pathlib.Path(os.environ['FAKE_STATE'])
|
|
s=json.loads(state.read_text())
|
|
if args[-1].endswith('/login'):
|
|
print(json.dumps({'auth':{'client_token':'synthetic-token'}})); sys.exit(0)
|
|
node=args[-1].rsplit('/',1)[-1]
|
|
out=pathlib.Path(args[args.index('-o')+1])
|
|
if '--data-binary' in args:
|
|
p=json.loads(pathlib.Path(args[args.index('--data-binary')+1][1:]).read_text())
|
|
s['writes'].append(p)
|
|
status='400' if s.get('conflict') else '200'
|
|
out.write_text('UNSAFE BODY MUST NOT APPEAR IN LOGS')
|
|
else:
|
|
d=s['records'].get(node)
|
|
status='200' if d else '404'
|
|
out.write_text(json.dumps({'data':{'data':d,'metadata':{'version':7}}}))
|
|
state.write_text(json.dumps(s)); print(status,end='')
|
|
'''
|
|
|
|
|
|
class BootstrapTests(unittest.TestCase):
|
|
def exercise(self, records, conflict=False):
|
|
manifest = yaml.safe_load(MANIFEST.read_text())
|
|
self.assertNotIn('ttlSecondsAfterFinished', manifest['spec'])
|
|
script = manifest['spec']['template']['spec']['containers'][0]['args'][0]
|
|
with tempfile.TemporaryDirectory() as d:
|
|
folder = Path(d)
|
|
fake = folder / 'curl'
|
|
fake.write_text(FAKE_CURL)
|
|
fake.chmod(0o755)
|
|
state = folder / 'state.json'
|
|
state.write_text(json.dumps({'records': records, 'writes': [], 'conflict': conflict}))
|
|
jwt = folder / 'jwt'
|
|
jwt.write_text('synthetic-jwt')
|
|
env = dict(os.environ, PATH=d + os.pathsep + os.environ['PATH'],
|
|
FAKE_STATE=str(state), SERVICE_ACCOUNT_TOKEN_FILE=str(jwt))
|
|
result = subprocess.run(['/bin/sh', '-c', script], env=env,
|
|
capture_output=True, text=True, timeout=30)
|
|
self.assertNotIn('UNSAFE BODY', result.stdout + result.stderr)
|
|
self.assertNotIn('synthetic-password', result.stdout + result.stderr)
|
|
return result, json.loads(state.read_text())
|
|
|
|
def test_preserves_passwords_extra_fields_and_cas(self):
|
|
result, state = self.exercise({'titan-jh': {'atlas_password': 'synthetic-password',
|
|
'root_password': 'synthetic-root', 'operator_note': 'keep'}})
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
first = state['writes'][0]
|
|
self.assertEqual(first['options']['cas'], 7)
|
|
self.assertEqual(first['data']['atlas_password'], 'synthetic-password')
|
|
self.assertEqual(first['data']['operator_note'], 'keep')
|
|
self.assertEqual(state['writes'][1]['options']['cas'], 0)
|
|
|
|
def test_unchanged_secret_has_no_new_version(self):
|
|
result, state = self.exercise({'titan-jh': {'atlas_password': 'synthetic-password',
|
|
'root_password': 'synthetic-root', 'intranet_ip': '192.168.22.8'}})
|
|
self.assertEqual(result.returncode, 0)
|
|
self.assertFalse(any(w['data']['intranet_ip'] == '192.168.22.8' for w in state['writes']))
|
|
|
|
def test_concurrent_write_fails_closed(self):
|
|
result, state = self.exercise({}, conflict=True)
|
|
self.assertNotEqual(result.returncode, 0)
|
|
self.assertEqual(len(state['writes']), 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|