cadrumo.adapters.outbound.storage._integrity module

Shared content-hash integrity verification for outbound storage backends.

Both adapters.outbound.storage.local.LocalFileSystemProvider and adapters.outbound.storage._google_drive.GoogleDriveProvider persist a content_hash (optionally sha256--prefixed) alongside each object and re-check it on read. This module centralises the strip_sha256_prefix() convention and the verify_content_hash() compare-and-raise kernel so the two backends share one integrity contract; each backend keeps its own message, context, and verification policy.

One duty is applied by ONE backend only, and it is declared here rather than left to be re-derived as an oversight. require_full_sha256_content_hash() is called by the Drive backend and not by the local one, so Drive refuses metadata that does not carry a full valid SHA-256 while local does not check the digest’s SHAPE at all – it compares whatever non-empty digest the sidecar holds, and verify_content_hash() is a documented no-op on an empty one.

Measured rather than assumed, when the asymmetry was reviewed: put refuses a blank content_hash on both backends, so the application cannot create an unverifiable object through its own write path; the malformed-but-non-empty values put does accept already raise on read for both; and the local read path now refuses a sidecar carrying no digest outright rather than inventing one. What remains uncovered on local is a sidecar whose digest is present, non-empty and structurally wrong in a way that still matches the payload – which requires an editor who could equally rewrite the digest to match, so the check would not stop them either.

The residue is therefore “local does not detect sidecar CORRUPTION by digest shape”, worth catching only if that case becomes real rather than hypothetical. Deliberately not closed by tightening local, because doing so is a behaviour change against a hole the application cannot open. Revisit if a corruption report ever arrives.

strip_sha256_prefix(stored_hash)[source]

Return the bare hex digest from a possibly sha256--prefixed stored hash.

Used by verify_content_hash() before comparing a stored provider digest with a caller-supplied core.hashing.sha256_hex() value.

Return type:

str

Parameters:

stored_hash (str)

verify_content_hash(actual_hash, stored_hash, *, message, context, translated_message, require_full_digest=False)[source]

Raise OutboundStorageIntegrityError when a stored hash disagrees.

A no-op when stored_hash is empty or carries no digest. With require_full_digest the check is skipped unless the stripped digest is a full 64-character hex string (adapters.outbound.storage._google_drive.GoogleDriveProvider policy); without it any non-empty stripped digest is compared against actual_hash (adapters.outbound.storage.local.LocalFileSystemProvider policy). actual_hash is supplied by the caller because the local backend reuses it to stamp the written sidecar.

Return type:

None

Parameters:
require_full_sha256_content_hash(stored_hash, *, message, context, translated_message)[source]

Return a canonical SHA-256 digest or refuse unverified provider metadata.

Return type:

str

Parameters:
verify_payload_byte_length(payload, stored_byte_length, *, message, context, translated_message)[source]

Raise when provider metadata does not describe the returned payload bytes.

Both local sidecars and Drive file metadata declare the size of opaque stored bytes. The declaration is an integrity assertion, not display-only metadata: callers must never receive payload bytes paired with a different claimed size.

Parameters:
  • payload (bytes) – Downloaded opaque provider bytes.

  • stored_byte_length (int) – Validated byte length declared by the provider.

  • message (str) – Human-readable provider-specific error message.

  • context (dict[str, str]) – Non-sensitive diagnostic context for the error envelope.

  • translated_message (str) – Localisation key for the provider-specific error.

Raises:

OutboundStorageIntegrityError – When the declared and actual lengths differ.

Return type:

None