Encrypted.Rotate (Encrypted v0.1.0)

Copy Markdown View Source

Re-encrypts one encrypted field with its active key.

The runner processes rows in primary-key order and commits one transaction per batch. It does not lock rows while it decrypts and encrypts them. Instead, each update includes WHERE field = ^old_ciphertext. PostgreSQL writes the replacement only if the stored bytes still match the bytes that the runner read.

This optimistic check is safe because the database stores the complete ciphertext bytes. A concurrent application write changes those bytes and makes the rotation update affect zero rows. The runner then leaves the concurrent value intact. Run the rotation again before removing an old key so that rows skipped during concurrent writes are checked again.

Query shapes beyond plain where clauses are rejected. Ordering, limits, joins, explicit locks, and other structural expressions would change the runner's keyset-pagination semantics.

Summary

Functions

Re-encrypts field in schema and returns the number of rows updated.

Functions

run(repo, schema, field, options \\ [])

@spec run(module(), module(), atom(), keyword()) :: non_neg_integer()

Re-encrypts field in schema and returns the number of rows updated.

The field must use Encrypted, and the schema must have exactly one primary key.

Options

  • :batch_size — rows read per transaction; defaults to 100
  • :timeout — transaction and query timeout; defaults to 15 seconds
  • :query — a query containing only where clauses on schema

Rows already using the active key are left unchanged. A row changed by another writer after selection is also left unchanged because its ciphertext no longer matches the optimistic update predicate.