the-custodian/docs/changes/CUST-WP-0080/verify_keycape_bootstrap.py

70 lines
3.4 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Verify the synthetic bootstrap output with KeyCape's current native loader.
Only local source, synthetic credentials and disposable files are used. Requires
pytest, PyYAML, OpenSSL and Go with dependencies already cached. No kubectl from
PATH is executed: the fixture installs its recording stub in a private PATH.
"""
import argparse
import base64
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
def digest(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--net-kingdom', type=Path, required=True)
parser.add_argument('--key-cape', type=Path, required=True)
args = parser.parse_args()
fixture = args.net_kingdom / 'tests/test_keycape_bootstrap.py'
spec = importlib.util.spec_from_file_location('bootstrap_fixture', fixture)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
with tempfile.TemporaryDirectory(prefix='keycape-bootstrap-native-') as directory:
root = Path(directory)
case_root = root / 'fixture'; case_root.mkdir()
case = module.setup.__wrapped__(case_root)
result = module.invoke(case)
if result.returncode:
raise RuntimeError('synthetic bootstrap failed')
writes = [c for c in module.calls(case) if c['args'][0] == 'create']
if len(writes) != 1:
raise RuntimeError('unexpected synthetic operation count')
manifest = json.loads(writes[0]['stdin'])
checkout = root / 'consumer'; checkout.mkdir()
shutil.copytree(args.key_cape / 'src', checkout / 'src',
ignore=shutil.ignore_patterns('.git', '__pycache__', '.pytest_cache'))
# Existing native config tests read only these public example fixtures.
(checkout / 'config').mkdir()
for name in ('dev-config.yaml', 'service-clients.example.yaml'):
shutil.copyfile(args.key_cape / 'config' / name, checkout / 'config' / name)
(checkout / 'src/bootstrap-fixture.json').write_bytes(base64.b64decode(manifest['data']['config.yaml']))
native_test = Path(__file__).with_name('keycape_bootstrap_native_test.go')
shutil.copyfile(native_test, checkout / 'src/internal/config/custody_bootstrap_test.go')
tested = subprocess.run(['go', 'test', '-count=1', './internal/config', './internal/adapters/privacyidea'],
cwd=checkout / 'src', capture_output=True, timeout=120,
env={**os.environ, 'GOPROXY': 'off', 'GOTOOLCHAIN': 'auto'})
if tested.returncode:
raise RuntimeError('native loader/adapter verification failed')
sources = ['src/internal/config/config.go', 'src/internal/adapters/privacyidea/config.go',
'src/internal/adapters/privacyidea/adapter.go',
'src/internal/adapters/privacyidea/credential_file_test.go']
print(json.dumps({'result': 'passed', 'bootstrap_fixture_sha256': digest(fixture),
'native_test_sha256': digest(native_test),
'consumer_sources': [{'path': p, 'sha256': digest(args.key_cape / p)} for p in sources],
'scope': 'Generated synthetic YAML parsed by native loader; local config and adapter suites. No live cluster or provider.'}, indent=2))
if __name__ == '__main__':
main()