Prepare independent ledger backup and isolated no-send recovery
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a11538-05ea-7b63-b3c7-a2df5f38898d
This commit is contained in:
parent
c8c018496a
commit
2ff24e991d
11 changed files with 1837 additions and 0 deletions
199
scripts/rehearse-ledger.py
Normal file
199
scripts/rehearse-ledger.py
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Attended recovered-ledger rehearsal in the cached receiver image, no network."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import secrets
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from ledger_archive import (
|
||||
Refused,
|
||||
checkpoint,
|
||||
private_directory,
|
||||
private_file,
|
||||
validate_capture,
|
||||
)
|
||||
|
||||
IMAGE = (
|
||||
"forgejo.coulomb.social/coulomb/email-connect@sha256:"
|
||||
"1e613d43734c44c5cd32c6083fda8b4da5d01ef43d10c6ca9c29a33c788cf75c"
|
||||
)
|
||||
|
||||
CODE = """import io,json,os,sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0,'/opt/ledger-rehearsal')
|
||||
from ledger_archive import fingerprint
|
||||
from email_connect.transactional import SQLiteDeliveryStore,TransactionalApplication,ProviderError
|
||||
assert os.getuid()==10001
|
||||
path=Path('/tmp/recovered.sqlite3')
|
||||
os.umask(0o077)
|
||||
path.write_bytes(sys.stdin.buffer.read())
|
||||
path.chmod(0o600)
|
||||
before=fingerprint(path)
|
||||
store=SQLiteDeliveryStore(str(path))
|
||||
assert fingerprint(path)==before
|
||||
class ForbiddenProvider:
|
||||
def send(self,*args):raise AssertionError('recovery_provider_call_forbidden')
|
||||
app=TransactionalApplication(store,ForbiddenProvider(),'synthetic-recovery-token','https://issuer.example.test')
|
||||
checks={'accepted_verifications':0,'unknown_verifications':0,'invalidated_handles':0,
|
||||
'suppressions':0,'accepted_deliveries':0,'unknown_sends':0}
|
||||
query=("SELECT v.registration_id,v.email,v.username,v.client_id,v.tenant,v.display_name,a.state "
|
||||
"FROM verifications v JOIN verification_attempts a ON a.request_id=v.request_id "
|
||||
"WHERE a.state IN ('accepted','in_flight')")
|
||||
for row in store.db.execute(query).fetchall():
|
||||
payload=dict(zip(['registration_id','normalized_email','preferred_username','client_id','tenant','display_name'],row[:6]))
|
||||
payload['correlation_id']='synthetic-recovery-probe'
|
||||
raw=json.dumps(payload).encode();response={}
|
||||
body=json.loads(b''.join(app({'PATH_INFO':'/v1/registration-verifications','REQUEST_METHOD':'POST',
|
||||
'CONTENT_LENGTH':str(len(raw)),'wsgi.input':io.BytesIO(raw),
|
||||
'HTTP_AUTHORIZATION':'Bearer synthetic-recovery-token'},
|
||||
lambda status,headers:response.update(status=status))))
|
||||
if row[6]=='accepted':
|
||||
assert response['status'].startswith('202') and body['accepted']
|
||||
checks['accepted_verifications']+=1
|
||||
else:
|
||||
assert response['status'].startswith('422') and body['error']=='delivery_outcome_unknown'
|
||||
checks['unknown_verifications']+=1
|
||||
query=("SELECT handle_hash FROM verifications "
|
||||
"WHERE consumed_at IS NOT NULL OR canceled_at IS NOT NULL")
|
||||
for row in store.db.execute(query).fetchall():
|
||||
try:store.consume_verification(row[0]);raise AssertionError('invalid_handle_reactivated')
|
||||
except ValueError as error:assert str(error)=='verification_invalid'
|
||||
checks['invalidated_handles']+=1
|
||||
for row in store.db.execute('SELECT email FROM suppressions').fetchall():
|
||||
assert store.is_suppressed(row[0]);checks['suppressions']+=1
|
||||
query=("SELECT d.event_id,a.fingerprint FROM deliveries d "
|
||||
"LEFT JOIN send_attempts a ON a.event_id=d.event_id")
|
||||
for row in store.db.execute(query).fetchall():
|
||||
assert store.delivery_status(row[0])['state']=='provider_accepted'
|
||||
assert store.reserve_send(row[0],row[1] or 'synthetic-legacy-probe') is False
|
||||
checks['accepted_deliveries']+=1
|
||||
query=("SELECT event_id,fingerprint FROM send_attempts WHERE state='in_flight' "
|
||||
"AND event_id NOT IN (SELECT event_id FROM deliveries)")
|
||||
for row in store.db.execute(query).fetchall():
|
||||
assert store.delivery_status(row[0])['state']=='unknown'
|
||||
try:store.reserve_send(row[0],row[1]);raise AssertionError('unknown_send_retried')
|
||||
except ProviderError as error:assert error.code=='delivery_outcome_unknown'
|
||||
checks['unknown_sends']+=1
|
||||
store.db.close()
|
||||
assert fingerprint(path)==before
|
||||
print(json.dumps({'status':'isolated_ledger_verified','ledger_fingerprint':before,
|
||||
'checks':checks,'mail_sent':False,'uid':os.getuid()}))
|
||||
"""
|
||||
|
||||
|
||||
def rehearse(recovered, receipt_path):
|
||||
private_directory(recovered)
|
||||
private_directory(receipt_path.parent)
|
||||
if receipt_path.exists() or receipt_path.is_symlink():
|
||||
raise Refused("fresh_receipt_required")
|
||||
capture = validate_capture(recovered)
|
||||
private_file(recovered / "unpack-receipt.json")
|
||||
unpacked = json.loads((recovered / "unpack-receipt.json").read_text())
|
||||
if (
|
||||
capture["image"] != IMAGE
|
||||
or unpacked.get("status") != "decrypted_ledger_verified"
|
||||
or unpacked.get("ledger_fingerprint") != capture["ledger_fingerprint"]
|
||||
):
|
||||
raise Refused("pinned_recovered_ledger_required")
|
||||
# Never pull a recovery image from the production forge during this rehearsal.
|
||||
inspected = subprocess.run(
|
||||
["docker", "image", "inspect", IMAGE], capture_output=True, timeout=30
|
||||
)
|
||||
if inspected.returncode:
|
||||
raise Refused("cached_pinned_recovery_image_required")
|
||||
started = time.monotonic()
|
||||
module = Path(__file__).with_name("ledger_archive.py").resolve()
|
||||
name = "email-ledger-rehearsal-" + secrets.token_hex(8)
|
||||
try:
|
||||
with (recovered / "database.sqlite3").open("rb") as source:
|
||||
result = subprocess.run(
|
||||
[
|
||||
"docker",
|
||||
"run",
|
||||
"--rm",
|
||||
"--name",
|
||||
name,
|
||||
"-i",
|
||||
"--network",
|
||||
"none",
|
||||
"--read-only",
|
||||
"--user",
|
||||
"10001:10001",
|
||||
"--cap-drop",
|
||||
"ALL",
|
||||
"--security-opt",
|
||||
"no-new-privileges",
|
||||
"--memory",
|
||||
"512m",
|
||||
"--cpus",
|
||||
"0.5",
|
||||
"--tmpfs",
|
||||
"/tmp:rw,noexec,nosuid,size=160m,uid=10001,gid=10001,mode=0700",
|
||||
"--mount",
|
||||
"type=bind,source="
|
||||
+ str(module)
|
||||
+ ",target=/opt/ledger-rehearsal/ledger_archive.py,readonly",
|
||||
"-e",
|
||||
"PYTHONDONTWRITEBYTECODE=1",
|
||||
"--entrypoint",
|
||||
"python",
|
||||
IMAGE,
|
||||
"-c",
|
||||
CODE,
|
||||
],
|
||||
stdin=source,
|
||||
capture_output=True,
|
||||
timeout=120,
|
||||
)
|
||||
finally:
|
||||
subprocess.run(["docker", "rm", "-f", name], capture_output=True, timeout=30)
|
||||
if result.returncode:
|
||||
raise Refused("isolated_rehearsal_failed")
|
||||
verification = json.loads(result.stdout)
|
||||
if verification.get("ledger_fingerprint") != capture["ledger_fingerprint"]:
|
||||
raise Refused("isolated_fingerprint_mismatch")
|
||||
receipt = dict(
|
||||
unpacked,
|
||||
status="application_restored_verified",
|
||||
application_restore_verified=True,
|
||||
recovery_image=IMAGE,
|
||||
network="disabled",
|
||||
production_restored=False,
|
||||
checks=verification["checks"],
|
||||
uid=verification["uid"],
|
||||
mail_sent=False,
|
||||
evidence_ceiling="isolated_ledger_rehearsal",
|
||||
elapsed_seconds=round(time.monotonic() - started, 2),
|
||||
)
|
||||
checkpoint(receipt_path, receipt)
|
||||
return receipt
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--recovered", required=True, type=Path)
|
||||
parser.add_argument("--receipt", required=True, type=Path)
|
||||
parser.add_argument("--execute", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if not args.execute:
|
||||
print(
|
||||
json.dumps(
|
||||
{"status": "reviewed", "container_started": False, "production_restored": False}
|
||||
)
|
||||
)
|
||||
return 0
|
||||
print(json.dumps(rehearse(args.recovered, args.receipt)))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except Exception as error:
|
||||
print(json.dumps({"status": "failed", "failure_type": type(error).__name__}))
|
||||
raise SystemExit(1)
|
||||
Loading…
Add table
Add a link
Reference in a new issue