Anvil.PII.Retention (Anvil v0.1.1)
View SourceRetention policy enforcement for PII fields.
This module provides functions for identifying expired labels and applying retention actions (soft delete, hard delete, or field-level redaction).
Retention Actions
:soft_delete- Tombstone: keep metadata, strip payload:hard_delete- Permanent deletion (breaks reproducibility):field_redaction- Redact only expired fields, keep unexpired
Examples
iex> schema_def = %{
...> fields: [
...> %{name: "notes", pii: :possible, retention_days: 90}
...> ]
...> }
iex> label = %{submitted_at: ~U[2024-01-01 00:00:00Z], payload: %{"notes" => "test"}}
iex> now = ~U[2025-01-01 00:00:00Z]
iex> Anvil.PII.Retention.has_expired_fields?(schema_def, label, now)
true
Summary
Functions
Applies retention action to a label.
Extracts field metadata from schema definition.
Finds labels with expired PII fields based on retention policies.
Checks if a label has any expired fields based on schema definition.
Processes a batch of expired labels with the specified retention action.
Types
Functions
@spec apply_retention_action( Anvil.Schema.Label.t(), retention_action(), map(), keyword() ) :: {:ok, Anvil.Schema.Label.t()} | {:error, term()}
Applies retention action to a label.
Parameters
label- The label to processaction- Retention action to apply (:soft_delete,:hard_delete,:field_redaction)schema_definition- Schema definition with field metadataopts- Additional options
Returns
{:ok, label} on success, {:error, reason} on failure.
Extracts field metadata from schema definition.
Returns a map of field names to metadata maps.
Examples
iex> schema_def = %{
...> fields: [
...> %{name: "notes", metadata: %{pii: :possible, retention_days: 90}}
...> ]
...> }
iex> Anvil.PII.Retention.extract_field_metadata(schema_def)
%{"notes" => %{pii: :possible, retention_days: 90}}
@spec find_expired_labels(keyword()) :: [Anvil.Schema.Label.t()]
Finds labels with expired PII fields based on retention policies.
Returns a list of labels where at least one field has exceeded its retention period.
Options
:now- Current time for expiration check (default: DateTime.utc_now()):queue_id- Filter by specific queue:limit- Limit number of results
Examples
iex> labels = Anvil.PII.Retention.find_expired_labels()
[%Label{...}, ...]
@spec has_expired_fields?(map(), map(), DateTime.t()) :: boolean()
Checks if a label has any expired fields based on schema definition.
Examples
iex> schema_def = %{fields: [%{name: "notes", metadata: %{retention_days: 90}}]}
iex> label = %{submitted_at: ~U[2024-01-01 00:00:00Z], payload: %{"notes" => "test"}}
iex> now = ~U[2025-01-01 00:00:00Z]
iex> Anvil.PII.Retention.has_expired_fields?(schema_def, label, now)
true
@spec process_expired_labels(keyword()) :: {:ok, non_neg_integer()} | {:error, term()}
Processes a batch of expired labels with the specified retention action.
Returns {:ok, count} where count is the number of labels processed.
Options
:dry_run- If true, only counts labels without processing (default: false):now- Current time for expiration check (default: DateTime.utc_now()):action- Retention action to apply (default::field_redaction)
Examples
iex> Anvil.PII.Retention.process_expired_labels(queue_id: queue_id, dry_run: true)
{:ok, 42}
iex> Anvil.PII.Retention.process_expired_labels(action: :soft_delete)
{:ok, 15}