cadrumo.adapters.persistence.storage.bucket.sealed_archive_reader module

Sealed bucket-export archive reader.

Validates the gzipped tar layout, strict-parses the header, and yields the encrypted payload bytes for the caller to decrypt. Fast-fails on layout drift (extra, missing, out-of-order, or unknown members) before any decryption attempt so a tampered or wrong-framing archive surfaces precisely.

The accepted layout is one fixed tuple of member names, so the member set is not a function of anything the header says. An archive is either exactly those members in exactly that order or it is refused; there is no shape whose validity depends on a declaration inside the archive being truthful about itself.

class SealedArchiveContents(header, payload_bytes)[source]

Bases: object

Decoded sealed-archive contents ready for downstream decryption.

The reader returns this aggregate so the caller composes its own decryption and validation pipeline without re-parsing the archive.

payload_bytes is OPAQUE to this layer, in both directions: the writer stored whatever it was handed, and this reader returns those bytes verbatim without parsing, validating or verifying them. It names no payload type on purpose. An Envelope is one thing a caller may put here and was for a time the only one, which is how the writer’s own documentation came to promise it; the transport never required it and must not, or it could refuse a sealed payload it merely failed to recognise.

Integrity is the caller’s, not this layer’s. No digest is checked here – the header’s manifest_digest is carried, not verified – so a caller that needs to know the bytes are the bytes it sealed must check that itself.

Parameters:
header: ExportArchiveHeader
payload_bytes: bytes
read_sealed_archive(source_path)[source]

Read and strict-validate a sealed bucket-export archive.

Parameters:

source_path (Path) – Operator-specified input path.

Return type:

SealedArchiveContents

Returns:

A SealedArchiveContents carrying the parsed header and the encrypted payload bytes.

Raises:
  • SealedArchiveLayoutError – When the tar layout deviates from the expected contract (extra / missing / out-of-order / unknown members, non-regular members).

  • SealedArchiveHeaderError – When header.json fails strict validation as ExportArchiveHeader, which includes an archive_schema_version naming any framing other than the one this build reads.

  • SealedArchivePayloadError – When the payload member cannot be read, or when a torn write truncated the gzip stream so the decompression layer raises EOFError / gzip.BadGzipFile. Decryption failures surface from this same class when the caller’s Envelope parse fails.

Truncation-detection scope: a torn write that damages the gzip stream (the common case) is caught here at read time and surfaces as SealedArchivePayloadError. A near-complete truncation that still decompresses to the expected two members passes this reader; it is caught downstream by the AEAD tag on the encrypted payload, which the importer verifies before it provisions any bucket store, so a torn archive never restores a partial bucket. Read-time detection of a near-complete truncation would require a trailing integrity marker in the archive format (writer + reader change); that hardening is a tracked follow-up recorded in the crash-window reference.