"""Hash-pinned native recovery receipts, with original completion timestamps.""" import hashlib import json import re from pathlib import Path from service_assurance import timestamp ROOT = Path(__file__).resolve().parents[1] def recovery_signals(now, root=ROOT): index = json.loads((root / 'assurance/recovery-evidence.json').read_text()) if index['schema'] != 'railiance-platform.recovery-evidence.v1': raise ValueError('unknown recovery index') signals = {} for entry in index['receipts']: signal = entry['signal'] if signal in signals or signal not in ('apps-pg.restore', 'forgejo-db.restore', 'openbao.snapshot'): raise ValueError('unexpected recovery signal') sample = {'result': 'unavailable', 'observed_at': now.isoformat()} try: path = (root / entry['path']).resolve() allowed = [root / 'docs/evidence'] if signal == 'openbao.snapshot': allowed.append(root / 'reviews') if not any(path.is_relative_to(directory.resolve()) for directory in allowed): raise ValueError('receipt outside evidence directory') raw = path.read_bytes() if hashlib.sha256(raw).hexdigest() != entry['sha256']: raise ValueError('receipt drift') receipt = json.loads(raw) if signal == 'openbao.snapshot': required = ('snapshot_created', 'source_initialized', 'source_unsealed', 'snapshot_encrypted', 'encrypted_copy_off_host', 'encryption_verified', 'hash_verified', 'no_secret_material_recorded') if (receipt.get('receipt_version') != 1 or receipt.get('source_cluster') != 'railiance01' or receipt.get('source_namespace') != 'openbao' or receipt.get('cluster_id') != 'fd28df5d-98ec-57dd-42ec-9b3e4f4e53bf' or not all(receipt.get(key) is True for key in required) or not receipt.get('encrypted_location_ref', '').startswith('offhost-custody:')): raise ValueError('snapshot not accepted') for key in ('snapshot_sha256', 'encrypted_snapshot_sha256'): value = receipt.get(key, '') if not re.fullmatch(r'sha256:[0-9a-f]{64}', value): raise ValueError('snapshot hash missing') if timestamp(receipt['created_at']) > now: raise ValueError('future snapshot') signals[signal] = {'result': 'pass', 'observed_at': receipt['created_at']} continue cell = signal.removesuffix('.restore') if (receipt['schema'] != 'platform.scaleway-primary-restore.v1' or receipt['primary_destination'] != f's3://railiance-platform-pg-backup/platform-pg/{cell}/' or receipt['source'] != 'Scaleway Barman base backup and WAL' or receipt['stage'] != 'database_acceptance' or receipt['status'] != 'verified' or receipt['cleanup'] is not True or receipt['production_ready'] is not True): raise ValueError('receipt not accepted') completed = timestamp(receipt['finished_at']) if not timestamp(receipt['started_at']) <= completed <= now: raise ValueError('invalid receipt chronology') sample = {'result': 'pass', 'observed_at': receipt['finished_at']} except (OSError, ValueError, KeyError, TypeError): pass signals[signal] = sample return signals