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

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()