Skip to main content

Module store

Module store 

Source
Expand description

The BlobStore: containers on a filesystem, keys and bookkeeping in PostgreSQL.

The split is the design. Ciphertext is large, immutable, and content-named, which is what a filesystem is good at; the wrapped DEK, the pins, and the tombstone are small, mutable, and have to change atomically, which is what a database is good at. Putting the key in the row rather than the file is what makes rewrap and crypto-shred single writes (ADR 0003, and the container module’s own docs).

Nothing here takes a path from a caller. A committed blob lives at a path derived from its validated 64-hex digest, and an upload lives at a path derived from an id this store minted — is_upload_id re-checks that shape on the way back in, because a BlobUploadId is a plain string newtype that a caller can build out of anything.

Write ordering is chosen so every crash window leaves the SAFE remainder:

  • commit writes the container, then the row. A crash between them leaves a file whose key exists nowhere — inert ciphertext, and a retried commit overwrites it.
  • shred writes the tombstone and drops the key, then unlinks. A crash between them leaves an unreadable blob, never a readable one.
  • sweep deletes the row, then unlinks, for the same reason.

Structs§

PgBlobStore
Content-addressed blobs: containers under a root directory, key material and bookkeeping in gwk_internal.

Constants§

UPLOAD_EXPIRY_SECS
How long an uncommitted upload survives. Enforced on the way in as well as by PgBlobStore::expire_uploads, so an expired upload is dead even on a deployment where nothing has swept yet.

Functions§

is_upload_id
Is this the shape this store mints? Lowercase hex of a fixed width — no separator, no ., no .., so it cannot name anything but a leaf under the directory it is joined to.