Retain verified recovery proof independently and bind the protected point
All checks were successful
CCR intake gate / gate (push) Successful in 12s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a17f16-d99c-7ea3-95f0-8212897fba6b
This commit is contained in:
codex 2026-10-29 22:49:33 +01:00
parent e1918b3f88
commit 09f4fd33cb
7 changed files with 257 additions and 11 deletions

View file

@ -20,7 +20,7 @@ from application_recovery_identities import (
private_directory,
private_json,
)
from application_recovery_kit import PROJECT, download
from application_recovery_kit import PROJECT, download, protect_receipt
from application_recovery_resources import API, s3, status
@ -133,6 +133,7 @@ class Drill:
"--output", str(self.root / "application-receipt.json")]))
app = json.loads(app)
baseline = json.loads((contents / "application-recovery.json").read_text())
point = json.loads((contents / "primary-receipt.json").read_text())
for key in ("actual_pages_rendered_through_view", "same_tenant_ungranted_page_denials", "content_files_unchanged"):
if app.get(key) != baseline.get(key):
raise Refused("kit_application_baseline_differs")
@ -143,11 +144,16 @@ class Drill:
"recovery_seconds": round(time.monotonic() - began, 3), "protected_kit": self.reference,
"kit_members_verified": len(manifest["files"]) + 1, "application": "coulomb-social",
"captured_at": manifest["captured_at"], "application_restore_verified": True,
"all_data_images_and_tools_from_independent_provider_kit": True,
"application_data_images_and_recovery_tools_from_provider_kit": True,
"bootstrap_api_client_preinstalled": True,
"age_identity_from_separate_provider_escrow": True, "original_node_or_plaintext_used": False,
"personal_session_used": False, "registry_pulls_performed": False, "fresh_docker_daemon": False,
"operator_account_recovery_time_included": False, "real_browser_journey_verified": False,
"unpack": unpacked, "restore": restored, "application_checks": app, "timers_activated": False}
result.update({k: point[k] for k in ("object_key", "version_id", "ciphertext_sha256", "ciphertext_bytes",
"image", "age_recipient", "database_sha256", "content_sha256")})
result["protected_recovery_proof"] = protect_receipt(
s3(private_json(self.directory / "custodian-pair.json"), PROJECT), reader, result)
checkpoint(self.root / "recovery-receipt.json", result)
return result

View file

@ -49,8 +49,7 @@ def download(client, ref, output):
return dict(ref, independently_retrieved_hash_verified=True, automatic_expiry=False)
def publish(client, source):
archive.regular_file(source)
def require_protected_bucket(client):
if client.get_bucket_versioning(Bucket=BUCKET).get("Status") != "Enabled":
raise Refused("protected_bucket_versioning_required")
try:
@ -61,6 +60,40 @@ def publish(client, source):
lifecycle = []
if lifecycle:
raise Refused("protected_bucket_must_have_no_lifecycle_expiry")
def protect_receipt(writer, reader, receipt):
"""Retain the recovery proof independently, without a self-hash cycle."""
require_protected_bucket(writer)
payload = json.dumps(receipt, sort_keys=True, separators=(",", ":")).encode()
if len(payload) > 1024**2 or receipt.get("status") != "application_restored_verified":
raise Refused("bounded_successful_recovery_proof_required")
expected = hashlib.sha256(payload).hexdigest()
key = "kits/receipts/" + expected + "/recovery-proof.json"
try:
head = writer.head_object(Bucket=BUCKET, Key=key)
except Exception as error:
if status(error) != 404:
raise
response = writer.put_object(Bucket=BUCKET, Key=key, Body=payload,
IfNoneMatch="*", Metadata={"sha256": expected}, ContentType="application/json")
version = archive.require_version(response.get("VersionId"))
else:
if head["ContentLength"] != len(payload) or head.get("Metadata", {}).get("sha256") != expected:
raise Refused("existing_proof_binding_differs")
version = archive.require_version(head.get("VersionId"))
response = reader.get_object(Bucket=BUCKET, Key=key, VersionId=version)
with response["Body"] as stream:
if response.get("VersionId") != version or stream.read(len(payload) + 1) != payload:
raise Refused("independent_proof_readback_differs")
return {"project_id": PROJECT, "bucket": BUCKET, "object_key": key, "version_id": version,
"sha256": expected, "bytes": len(payload), "independent_readback_verified": True,
"automatic_expiry": False}
def publish(client, source):
archive.regular_file(source)
require_protected_bucket(client)
size = source.stat().st_size
if not 0 < size <= MAX_BYTES:
raise Refused("bounded_kit_required")