cadrumo.adapters.persistence.storage.sql._secure_object_writes module¶
Encrypted secure-object write and revision-lineage implementation.
- OBJECT_KEY_SELECT_CHUNK¶
Digests per
IN (...)slice of a batched object-key read (previous-write metadata, batch existence). Well under SQLite’s bound-variable ceiling, and large enough that a 20k-row batch costs ~40 reads instead of 20k.
- class RowcountResult(*args, **kwargs)[source]¶
Bases:
ProtocolStructural result shape for SQLAlchemy DML rowcount checks.
- class SecureObjectWriteOperations[source]¶
Bases:
objectCohesive encrypted write, batch-DML, and revision-lineage operations.
The concrete repository owns construction, registration policy, session freshness, and read decoding. This sibling owns the one write funnel that every public mutation reaches, keeping encryption, lineage, and guarded DML together without exposing another repository surface.
- save(*, namespace, object_key, classification, schema_version, written_at, payload, write_provenance='secure-object-repository', source_event_id=None, expected_revision_id=None)[source]¶
Encrypt and upsert one byte payload keyed by a natural string id.
The natural
object_keyis HMAC-digested at the column boundary. To upsert against a pre-computed digest (e.g. when restoring an archive bundle whose natural key was lost in the original HMAC), usesave_with_raw_key()instead.- Parameters:
namespace (
str) – The storage namespace to write into.object_key (
str) – Natural string identifier for this record. Digested via HMAC before being stored on disk.classification (
SensitivityClass) – TheSensitivityClassfor this record.schema_version (
int) – Envelope schema version to stamp on the row.written_at (
datetime) – UTC-aware write timestamp. A naive or offset-bearing instant is refused: the SQLite column dropstzinfo, so it would not recompute the revision it was stored under.payload (
bytes) – Plaintext envelope bytes. Encrypted at the column boundary.write_provenance (
str) – Human-readable string identifying the write origin.source_event_id (
str|None) – Optional opaque domain-event identifier for audit trails.expected_revision_id (
str|None) – Optional optimistic-concurrency guard.
- Return type:
- save_many(writes)[source]¶
Encrypt and upsert several payloads in one SQL unit of work.
- Return type:
- Parameters:
writes (tuple[SecureObjectWrite, ...])
- namespace_payload_hashes(namespace)[source]¶
Return
{object_key_digest: payload_hash}for every row innamespace.A decryption-free scan of the
object_key(HMAC digest) andpayload_hashcolumns, for diff-based writers that persist a namespace as one row per logical entry: an entry whose freshly-serialisedpayload_hashmatches the stored value is unchanged and need not be rewritten. The digest is the same valuesecure_object_key_digest()produces for the entry’s natural key, so a caller comparessecure_object_key_digest(key)against these keys without decrypting anything.
- apply_batch(writes, deletions=())[source]¶
Atomically upsert
writesand removedeletionsin one unit of work.The single
session_scopetransaction commits every upsert and every digest-addressed deletion together, so a diff-based per-row writer (e.g. the transaction catalogue) keeps the all-or-nothing guarantee the whole-blobsavehad — including when the same call must also commit sibling-catalogue writes (bucket-event history, invoices) passed inwrites. A crash mid-batch rolls the whole unit back.Deletions are addressed by raw HMAC digest (see
SecureObjectDeletion); the digest passes straight through theHashedLookupcolumn comparison without re-hashing.- Return type:
- Parameters:
writes (tuple[SecureObjectWrite, ...])
deletions (tuple[SecureObjectDeletion, ...])
- save_with_raw_key(*, namespace, hashed_object_key, classification, schema_version, written_at, payload, write_provenance='secure-object-repository', source_event_id=None, expected_revision_id=None)[source]¶
Encrypt and upsert one byte payload keyed by a pre-computed digest.
The 32-byte
hashed_object_keyis passed straight through theHashedLookupcolumn without re-hashing. Used by the archive restore path to round-trip rows whose natural key is not present in the bundle (e.g. the path-keyed setup-profile and inventory namespaces).- Parameters:
namespace (
str) – Storage namespace string.hashed_object_key (
bytes) – 32 raw HMAC-SHA256 bytes (the digest produced byHashedLookup.computeunder the same master key the row was originally written with).classification (
SensitivityClass) –SensitivityClassto upsert at.schema_version (
int) – Envelope schema version captured on the row.written_at (
datetime) – UTC-aware datetime captured on the row. A naive or offset-bearing instant is refused for the same reason assave().payload (
bytes) – Plaintext envelope bytes (the column encrypts).write_provenance (
str) – Human-readable string identifying the write origin (e.g. caller module or operation name). Defaults to the repository’s default provenance marker.source_event_id (
str|None) – Optional opaque identifier of the domain event that triggered this write; stored verbatim for audit trails.expected_revision_id (
str|None) – Optional optimistic-concurrency guard; when supplied the upsert is rejected if the row’s current revision does not match.
- Raises:
StorageValidationError – When
hashed_object_keyis not exactly 32 bytes.RepositoryError – On underlying SQL integrity errors.
- Return type: