56 lines
2.6 KiB
Python
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())
|