68 lines
3.3 KiB
Python
68 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Guarded repair of the two admitted scanner modes; capture no child diagnostics."""
|
|
import argparse
|
|
import datetime
|
|
import hashlib
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
|
|
HERE = Path(__file__).parent
|
|
spec = importlib.util.spec_from_file_location('template', HERE / 'activate_forge_template.py')
|
|
template = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(template)
|
|
|
|
|
|
def guard_script(original):
|
|
lines = ['#!/bin/sh', 'set +vx', 'set -eu', 'test "$(id -u)" = 1000']
|
|
# Validate all files before changing either. Never follow a substituted link.
|
|
for parent in ['/data', '/data/security', '/data/security/receive-secret-scan', original['version_directory']]:
|
|
lines.append(f'test -d {parent} && test ! -L {parent}')
|
|
for item in original['artifacts'][:2]:
|
|
path = original['version_directory'] + '/' + item['name']
|
|
lines.extend([f'test -f {path} && test ! -L {path}',
|
|
f'test "$(stat -c %u {path})" = 1000',
|
|
f'test "$(sha256sum {path} | cut -d " " -f 1)" = {item["sha256"]}',
|
|
f'case "$(stat -c %a {path})" in 755|775) ;; *) exit 21;; esac'])
|
|
lines.append('if [ "${1:-check}" = apply ]; then')
|
|
for item in original['artifacts'][:2]:
|
|
path = original['version_directory'] + '/' + item['name']
|
|
lines.extend([f' chmod 755 {path}', f' test "$(stat -c %a {path})" = 755'])
|
|
lines.extend(['fi', ''])
|
|
return '\n'.join(lines)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--proposal', type=Path, required=True)
|
|
parser.add_argument('--receipt', type=Path, required=True)
|
|
parser.add_argument('--apply', action='store_true')
|
|
args = parser.parse_args()
|
|
proposal = json.loads(args.proposal.read_text())
|
|
original = json.loads((HERE / 'receive-hook-proposal.json').read_text())
|
|
script = guard_script(original).encode()
|
|
assert hashlib.sha256(Path(__file__).read_bytes()).hexdigest() == proposal['executor_sha256']
|
|
assert hashlib.sha256(script).hexdigest() == proposal['guard_sha256']
|
|
d = template.deployment()
|
|
pod = template.target_pod(d, original)
|
|
assert pod['pod_uid'] == proposal['pod_uid']
|
|
template.check_artifacts(pod)
|
|
mode = 'apply' if args.apply else 'check'
|
|
receipt = {'proposal_id': proposal['proposal_id'], 'revision': proposal['revision'],
|
|
'proposal_sha256': hashlib.sha256(args.proposal.read_bytes()).hexdigest(),
|
|
'pod_uid': pod['pod_uid'], 'mode': mode, 'result': 'unverified',
|
|
'at': datetime.datetime.now(datetime.timezone.utc).isoformat()}
|
|
args.receipt.write_text(json.dumps(receipt, indent=2) + '\n')
|
|
template.native.execute(pod, 'sh', '-s', '--', mode, payload=script)
|
|
observed = []
|
|
for item in original['artifacts'][:2]:
|
|
path = original['version_directory'] + '/' + item['name']
|
|
observed.append({'name': item['name'], 'stat': template.native.execute(pod, 'stat', '-c', '%a %u %g', path).decode().strip()})
|
|
receipt.update(result='modes-restored' if args.apply else 'preflight-passed', artifacts=observed,
|
|
push_acceptance='pending', restart_durability='pending')
|
|
args.receipt.write_text(json.dumps(receipt, indent=2) + '\n')
|
|
print(json.dumps(receipt))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|