Files
werkjournal/scripts/deploy-prototype.py
2026-09-09 14:06:13 +02:00

56 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Validate the exact CI artifact, then transfer it with one SSH connection."""
import base64
import hashlib
import json
import os
from pathlib import Path
import re
import shlex
import subprocess
import sys
import tarfile
def validate(folder):
manifest = json.loads((folder / 'manifest.json').read_text())
if manifest.get('schemaVersion') != 1 or manifest.get('runtime') != 'java-25':
raise SystemExit('Unsupported release manifest/runtime')
if not re.fullmatch(r'[0-9a-f]{40}', manifest.get('commit', '')):
raise SystemExit('Missing full source commit')
with (folder / 'werkjournal.jar').open('rb') as stream:
actual = hashlib.file_digest(stream, 'sha256').hexdigest()
if actual != manifest.get('sha256') or manifest.get('files') != {'werkjournal.jar': actual}:
raise SystemExit('Artifact checksum does not match manifest')
return manifest
if __name__ == '__main__':
target, folder = sys.argv[1], Path(sys.argv[2]).resolve()
manifest = validate(folder)
mode = sys.argv[3] if len(sys.argv) == 4 else '--prototype'
remote_script = {'--prototype': 'deploy-prototype-remote.py', '--guest-preview': 'deploy-guest-preview-remote.py',
'--update': 'deploy-update-remote.py', '--upload': 'deploy-update-remote.py'}[mode]
script = Path(__file__).with_name(remote_script).read_bytes()
encoded = base64.b64encode(script).decode('ascii')
command = 'python3 -c ' + shlex.quote("import base64; exec(compile(base64.b64decode('" + encoded + "'), 'deploy-prototype-remote.py', 'exec'))")
if mode == '--upload':
command += ' --upload'
print(('Uploading' if mode == '--upload' else 'Deploying') + ' verified application commit ' + manifest['commit'], flush=True)
ssh = ['ssh', '-o', 'BatchMode=yes']
key = os.environ.get('WERKJOURNAL_DEPLOY_KEY')
host_keys = os.environ.get('WERKJOURNAL_DEPLOY_HOST_KEYS')
if bool(key) != bool(host_keys):
raise SystemExit('Deployment identity and pinned host keys must be configured together')
if key:
ssh += ['-i', key, '-o', 'IdentitiesOnly=yes', '-o', 'StrictHostKeyChecking=yes',
'-o', 'UserKnownHostsFile=' + host_keys]
process = subprocess.Popen([*ssh, target, command], stdin=subprocess.PIPE)
try:
with tarfile.open(fileobj=process.stdin, mode='w|') as archive:
for name in ['manifest.json', 'werkjournal.jar']:
archive.add(folder / name, arcname=name, recursive=False)
finally:
process.stdin.close()
raise SystemExit(process.wait())