"""Run the sealed installer in one enterprise-matched container after normal twin initialization.""" import argparse import base64 import json from pathlib import Path import re import subprocess import sys import uuid sys.dont_write_bytecode = True from bootstrap import HERE, Stopped, check_enterprise, need, plain, sealed def run(args, runner=subprocess.run, input_bytes=None): result = runner(args, input=input_bytes, capture_output=True, timeout=240) need(result.returncode == 0, 'HOST_COMMAND_FAILED') return result.stdout def initialize(checkout, commit, container, apply=False, runner=subprocess.run): checkout = plain(checkout) need(re.fullmatch('[a-f0-9]{40}', commit), 'PINNED_COMMIT_REQUIRED') need(re.fullmatch('[a-zA-Z0-9][a-zA-Z0-9_.-]{0,100}', container), 'INVALID_CONTAINER_NAME') cfg, files = sealed(checkout) actual = run(['git', '-C', str(checkout), 'rev-parse', 'HEAD'], runner).decode().strip() need(actual == commit, 'CONFIGURATION_COMMIT_MISMATCH') need(not run(['git', '-C', str(checkout), 'status', '--porcelain'], runner).strip(), 'CONFIGURATION_CHECKOUT_CHANGED') prefix = ['docker', 'exec', '--user', '10000:10000', container] need(run([*prefix, 'id', '-u'], runner).strip() == b'10000', 'CONTAINER_USER_MISMATCH') current = json.loads(run([*prefix, 'cat', '/opt/data/.fmode/config/enterprise/current.json'], runner)) check_enterprise(current, cfg) # A different enterprise is rejected before docker cp or any installation writes. if not apply: return {'ok': True, 'planOnly': True, 'companyObjectId': cfg['companyObjectId'], 'configurationCommit': commit, 'container': container, 'businessWrites': 0} # Transfer only public files over stdin, written by hermes. No root extraction or .git copying. copy_code = '''import base64,json,os,pathlib,sys,tempfile raw=sys.stdin.buffer.read(16000001) assert len(raw)<=16000000 files=json.loads(raw) base=pathlib.Path('/opt/data') assert all(not x.is_symlink() for x in (base,*base.parents)) root=pathlib.Path(tempfile.mkdtemp(prefix='ksf-enterprise-package-',dir=base)) for name,body in files.items(): parts=pathlib.PurePosixPath(name).parts assert name and name=='/'.join(parts) and not name.startswith('/') assert all(p not in ('.','..') for p in parts) and '\\\\' not in name and ':' not in name file=root/name file.parent.mkdir(parents=True,exist_ok=True,mode=0o700) with file.open('xb') as out: out.write(base64.b64decode(body,validate=True)) file.chmod(0o644) print(str(root)) ''' wire = json.dumps({n: base64.b64encode((checkout / n).read_bytes()).decode() for n in [*files, 'FILES.sha256']}).encode() target = run(['docker', 'exec', '--user', '10000:10000', '-i', container, 'python3', '-B', '-c', copy_code], runner, wire).decode().strip() need(re.fullmatch('/opt/data/ksf-enterprise-package-[a-zA-Z0-9_-]+', target), 'PACKAGE_TRANSFER_PATH_INVALID') out = '/opt/data/ksf-enterprise-results/' + uuid.uuid4().hex results = [] for command in ('plan', 'apply', 'verify'): value = json.loads(run([*prefix, 'python3', '-B', target + '/bootstrap.py', command, '--data-dir', '/opt/data', '--out', out], runner)) need(value.get('ok') is True, 'CONTAINER_INSTALL_FAILED') results.append(value) voc_results = [] for command in ('plan', 'apply', 'verify'): value = json.loads(run([*prefix, 'python3', '-B', target + '/voc.py', command, '--data-dir', '/opt/data', '--out', out + '/voc'], runner)) need(value.get('ok') is True, 'CONTAINER_VOC_INSTALL_FAILED') voc_results.append(value) return {'ok': True, 'container': container, 'companyObjectId': cfg['companyObjectId'], 'configurationCommit': commit, 'resultsDirectory': out, 'packageDirectory': target, 'installation': results[-1], 'voc': voc_results[-1], 'vocModified': voc_results[1].get('vocModified', False), 'authorizationProvisioned': False, 'automaticLifecycleHookInstalled': False, 'businessWrites': 0} def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--checkout', required=True, type=Path) parser.add_argument('--commit', required=True) parser.add_argument('--container', required=True) parser.add_argument('--apply', action='store_true') args = parser.parse_args() need(args.checkout.is_absolute(), 'ABSOLUTE_PATH_REQUIRED') print(json.dumps(initialize(args.checkout, args.commit, args.container, args.apply), ensure_ascii=False, indent=2)) if __name__ == '__main__': try: main() except (Stopped, OSError, ValueError, KeyError, subprocess.TimeoutExpired) as error: print(json.dumps({'ok': False, 'error': {'code': str(error) if isinstance(error, Stopped) else 'HOST_BOOTSTRAP_STOPPED'}}), file=sys.stderr) sys.exit(1)