atlas-iac/testing/tests/test_node_secret_bootstrap.py

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()