Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1abf1-7e95-7141-87c9-ee78332bf790
175 lines
9.1 KiB
Python
175 lines
9.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Founder workstation transport for the isolated native restore rehearsal.
|
|
|
|
Default reviews only. --execute stages the provider-retrieved point privately,
|
|
runs the scoped node helper, then removes its stage after successful cleanup.
|
|
--cleanup NONCE removes only that journal's owned clone and the private stage.
|
|
"""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import re
|
|
import shlex
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
import vergabe_pilot_export as export
|
|
import vergabe_pilot_export_remote as transfer
|
|
import vergabe_pilot_restore as restore
|
|
from vergabe_pilot_recovery_store import Refused, digest, private_directory, require
|
|
|
|
PINS = {
|
|
"vergabe_pilot_recovery_store": "724a2dd9db8a0f57e1efa709ec989d8a47c681a86b1fca923bfdfea1698ae23c",
|
|
"vergabe_pilot_export": "b45733fa10ae59b56563045c43c53b5f824a74e1114f68fbed28404f14b43e3a",
|
|
"vergabe_pilot_restore": "407df786ce8994744df7079771ddadf56019f2d384d4b6cbda8dc8d051270dd4",
|
|
}
|
|
PROVIDER_RECEIPT = "provider-receipt-db975b7a730f.json"
|
|
STAGING = r'''
|
|
import json,os,pwd,re,stat,sys
|
|
from pathlib import Path
|
|
try:
|
|
nonce,mode=sys.argv[1:]
|
|
assert re.fullmatch('[0-9a-f]{12}',nonce) and mode in ('create','cleanup')
|
|
account=pwd.getpwuid(os.getuid())
|
|
assert account.pw_name=='tegwick' and account.pw_dir=='/home/tegwick'
|
|
directory=Path(account.pw_dir)/('vergabe-pilot-restore-'+nonce)
|
|
if mode=='create':directory.mkdir(mode=0o700)
|
|
else:
|
|
if directory.exists() or directory.is_symlink():
|
|
info=directory.lstat()
|
|
assert stat.S_ISDIR(info.st_mode) and info.st_uid==os.getuid() and not info.st_mode&0o077
|
|
allowed={'database.dump','stores.tar.gz','manifest.private.json','receipt.json','provider.json','origin.json'}
|
|
assert {p.name for p in directory.iterdir()}<=allowed
|
|
for path in directory.iterdir():
|
|
assert stat.S_ISREG(path.lstat().st_mode) and path.lstat().st_uid==os.getuid()
|
|
path.unlink()
|
|
directory.rmdir()
|
|
print(json.dumps({'status':'restore_stage_'+('ready' if mode=='create' else 'removed'),'nonce':nonce}))
|
|
except Exception:
|
|
print(json.dumps({'status':'restore_stage_failed','details_suppressed':True}))
|
|
raise SystemExit(1)
|
|
'''
|
|
|
|
|
|
def remote_command(nonce, cleanup=False):
|
|
require(re.fullmatch(r"[0-9a-f]{12}", nonce), "invalid_restore_nonce")
|
|
sources = {}
|
|
for name, pin in PINS.items():
|
|
raw = Path(__file__).with_name(name + ".py").read_bytes()
|
|
require(hashlib.sha256(raw).hexdigest() == pin, "restore_source_pin_mismatch")
|
|
sources[name] = raw.decode()
|
|
bootstrap = "import sys,types;"
|
|
for name in ("vergabe_pilot_recovery_store", "vergabe_pilot_export"):
|
|
bootstrap += ("m=types.ModuleType(" + repr(name) + ");sys.modules[m.__name__]=m;"
|
|
"exec(compile(" + repr(sources[name]) + "," + repr(name + ".py") + ",'exec'),m.__dict__);")
|
|
bootstrap += ("sys.argv=['vergabe_pilot_restore.py',*sys.argv[1:]];exec(compile(" +
|
|
repr(sources["vergabe_pilot_restore"]) + ",'vergabe_pilot_restore.py','exec'),{'__name__':'__main__'})")
|
|
operation = ["sudo", "/usr/bin/env", "KUBECONFIG=/etc/rancher/k3s/k3s.yaml", "/usr/bin/python3", "-c",
|
|
bootstrap, "--nonce", nonce, *(["--cleanup"] if cleanup else [])]
|
|
text = shlex.join(operation)
|
|
require(len(text.encode()) < 120000, "restore_transport_size_bound")
|
|
return ["ssh", "-t", "railiance01", text]
|
|
|
|
|
|
def stage_command(nonce, mode):
|
|
return ["ssh", "-t", "railiance01", shlex.join(["/usr/bin/python3", "-c", STAGING, nonce, mode])]
|
|
|
|
|
|
def verify_input(receipt_path):
|
|
require(receipt_path.is_absolute() and transfer.outside_git(receipt_path.resolve()),
|
|
"private_provider_receipt_outside_git_required")
|
|
export.regular(receipt_path, os.geteuid())
|
|
require(receipt_path.stat().st_size <= 16384, "provider_receipt_bound")
|
|
body = json.loads(receipt_path.read_text())
|
|
kit = receipt_path.parent
|
|
private_directory(kit)
|
|
require(body["status"] == "published_read_back_and_decrypted" and body["run_id"] == export.RUN_ID
|
|
and body["warden_exit_code"] == 0 and body["ciphertext_sha256"] == restore.CIPHER
|
|
and body["plaintext_packet_sha256"] == restore.PLAIN
|
|
and all(body.get(k) is True for k in ("provider_publication_verified", "independent_readback_verified",
|
|
"decryption_verified", "session_cleanup_confirmed")), "successful_provider_receipt_required")
|
|
recovery = Path(body["recovery_directory"])
|
|
require(recovery.is_absolute() and recovery.parent == kit and recovery.name.startswith("provider-recovery-"),
|
|
"provider_recovery_directory_required")
|
|
private_directory(recovery)
|
|
require(digest(recovery / "recovery-point.zip") == restore.PLAIN
|
|
and digest(recovery / "fetched.zip.age") == restore.CIPHER, "provider_retrieved_packet_changed")
|
|
point = recovery / "point"
|
|
private_directory(point)
|
|
metadata = json.loads((kit / (export.NAME + ".transfer.json")).read_text())["packet"]
|
|
require(metadata["run_id"] == export.RUN_ID and metadata["image"] == export.IMAGE, "wrong_recovery_point")
|
|
for name in restore.FILES[:4]:
|
|
export.regular(point / name, os.geteuid())
|
|
require(metadata["files"][name] == {"bytes": (point / name).stat().st_size,
|
|
"sha256": digest(point / name)}, "provider_recovered_file_changed")
|
|
for name, (size, checksum) in export.EXPECTED.items():
|
|
require(metadata["files"][name] == {"bytes": size, "sha256": checksum}, "capture_hash_mismatch")
|
|
return kit, point, metadata["files"]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
modes = parser.add_mutually_exclusive_group()
|
|
modes.add_argument("--execute", action="store_true")
|
|
modes.add_argument("--cleanup")
|
|
parser.add_argument("--receipt", type=Path)
|
|
args = parser.parse_args()
|
|
nonce = args.cleanup or uuid.uuid4().hex[:12]
|
|
command = remote_command(nonce, bool(args.cleanup))
|
|
if not args.execute and not args.cleanup:
|
|
print(json.dumps({"status": "prepared", "run_id": export.RUN_ID, "target": "railiance01",
|
|
"fresh_namespace": "vergabe-restore-<nonce>", "fresh_claims": list(restore.CLAIMS.values()),
|
|
"application_changed": False, "next": "--execute", "sources": PINS}))
|
|
return 0
|
|
require(sys.stdin.isatty(), "founder_interactive_terminal_required")
|
|
if args.cleanup:
|
|
result = subprocess.run(command, check=False)
|
|
staged = subprocess.run(stage_command(nonce, "cleanup"), check=False)
|
|
return 0 if result.returncode == staged.returncode == 0 else 1
|
|
receipt_path = args.receipt or Path.home() / ".local/state/vergabe-pilot-recovery" / export.RUN_ID / PROVIDER_RECEIPT
|
|
kit, point, files = verify_input(receipt_path)
|
|
result = subprocess.run(stage_command(nonce, "create"), check=False)
|
|
require(result.returncode == 0, "restore_stage_creation_failed")
|
|
print(json.dumps({"status": "restore_transport_started", "nonce": nonce}), flush=True)
|
|
with tempfile.TemporaryDirectory(prefix="restore-transfer-", dir=kit) as temporary:
|
|
temporary = Path(temporary)
|
|
for name in restore.FILES[:4]:
|
|
shutil.copy2(point / name, temporary / name)
|
|
shutil.copy2(receipt_path, temporary / "provider.json")
|
|
(temporary / "origin.json").write_text(json.dumps({"run_id": export.RUN_ID, "files": files}))
|
|
(temporary / "origin.json").chmod(0o600)
|
|
for name in restore.FILES:
|
|
copied = subprocess.run(["scp", "-p", str(temporary / name),
|
|
"railiance01:vergabe-pilot-restore-" + nonce + "/" + name],
|
|
capture_output=True, timeout=120, check=False)
|
|
require(copied.returncode == 0, "restore_private_transfer_failed")
|
|
result = subprocess.run(command, check=False)
|
|
stage_removed = False
|
|
if result.returncode == 0:
|
|
stage_removed = subprocess.run(stage_command(nonce, "cleanup"), check=False).returncode == 0
|
|
metadata = {"schema": "railiance.vergabe-pilot-native-restore-transport.v1", "nonce": nonce,
|
|
"run_id": export.RUN_ID, "worker_exit_code": result.returncode,
|
|
"node_stage_removed": stage_removed,
|
|
"status": "complete" if result.returncode == 0 and stage_removed else "requires_review"}
|
|
output = kit / ("native-restore-transport-" + nonce + ".json")
|
|
fd = os.open(output, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
|
|
with os.fdopen(fd, "w") as stream:
|
|
json.dump(metadata, stream, indent=2)
|
|
print(json.dumps(metadata, indent=2))
|
|
return 0 if metadata["status"] == "complete" else 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
os.umask(0o077)
|
|
try:
|
|
raise SystemExit(main())
|
|
except Exception as error: # noqa: BLE001 — suppress private path/transport details
|
|
print(json.dumps({"status": "restore_transport_failed", "failure": str(error) if isinstance(error, Refused)
|
|
else "restore_transport_error", "details_suppressed": True}))
|
|
raise SystemExit(1)
|