audit_trail.privacy¶
GDPR operations: scrub and scrub_actor.
These are the only updates the library ever makes to audit rows. Each one
runs in the caller's transaction on a Connection and records itself as an
audit.scrubbed entry in that same transaction, so the erasure and its
record are committed together or not at all. The entry holds what was
scrubbed and how many rows changed, never an erased value.
ACTOR_FIELDS
module-attribute
¶
Columns of audit_transaction and keys of data.context that
scrub_actor clears.
ScrubNotAllowedError ¶
Bases: RuntimeError
scrub or scrub_actor was called without allow_scrub=True.
ScrubResult ¶
Bases: NamedTuple
Rows a scrub changed.
Attributes:
| Name | Type | Description |
|---|---|---|
activity_rows |
int
|
|
transaction_rows |
int
|
|
ScrubbedRecord ¶
Bases: NamedTuple
What the audit.scrubbed entry of a scrub is built from.
Attributes:
| Name | Type | Description |
|---|---|---|
severity |
int
|
Severity of the entry (the registry's |
context |
AuditContext
|
Context of whoever runs the scrub. |
json_encoder |
type[JSONEncoder] | None
|
Host encoder for |
check_allowed ¶
Refuse a scrub unless it was enabled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allow_scrub
|
bool
|
The |
required |
Raises:
| Type | Description |
|---|---|
ScrubNotAllowedError
|
|
Source code in audit_trail/privacy.py
check_since ¶
Refuse a naive since, which PostgreSQL would read in the session's zone.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
since
|
datetime | None
|
The lower bound of |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
|
Source code in audit_trail/privacy.py
check_scope_ids ¶
Refuse a str as scope_ids, which would be read as its letters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scope_ids
|
Collection[str] | None
|
The scope restriction, or |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
Source code in audit_trail/privacy.py
scrub_context ¶
Return the context of whoever runs a scrub; there is no session.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context_provider
|
Callable[[], AuditContext | None] | None
|
The host hook, checked before the context variable. |
required |
Returns:
| Type | Description |
|---|---|
AuditContext
|
The provided context, else the active |
AuditContext
|
anonymous one. |
Source code in audit_trail/privacy.py
scrub_statement ¶
scrub_statement(
tables: AuditTables,
object_type: str,
object_id: str,
*,
include_targets: bool,
since: datetime | None,
scope_ids: Collection[str] | None = None,
) -> Update
Build the UPDATE that erases the entries of one object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
AuditTables
|
The audit tables. |
required |
object_type
|
str
|
Stored |
required |
object_id
|
str
|
Stored |
required |
include_targets
|
bool
|
Also erase entries whose target is the object. |
required |
since
|
datetime | None
|
Only entries with |
required |
scope_ids
|
Collection[str] | None
|
Only entries whose |
None
|
Returns:
| Type | Description |
|---|---|
Update
|
The statement; its rowcount is the number of rows erased. |
Source code in audit_trail/privacy.py
scrub ¶
scrub(
connection: Connection,
tables: AuditTables,
object_type: str,
object_id: str,
*,
include_targets: bool,
since: datetime | None,
scope_ids: Collection[str] | None,
record: ScrubbedRecord,
) -> ScrubResult
Erase the values an object's entries hold, and record it.
In every matching audit_activity row (except the library's own
audit.* entries), each non-null value in data.changes and
data.payload becomes "[erased]", and object_label becomes
NULL. Field keys stay, so the history still shows what changed; a
null stays null. Column changes keep their [old, new] shape
and relationship changes their added/removed lists, with every id
erased; a payload value is erased whole, including anything nested in
it. data.context is left to scrub_actor.
With scope_ids, only entries whose scope_id is one of them are
erased: an empty collection erases nothing, and an entry without a scope
never matches. The audit.scrubbed entry records the restriction.
Runs in the connection's current transaction; the caller commits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
Connection
|
Connection whose role may update the audit tables. |
required |
tables
|
AuditTables
|
The audit tables. |
required |
object_type
|
str
|
Stored |
required |
object_id
|
str
|
Stored |
required |
include_targets
|
bool
|
Also erase entries whose target is the object, such as changes of its children. |
required |
since
|
datetime | None
|
Only entries with |
required |
scope_ids
|
Collection[str] | None
|
Only entries with one of these |
required |
record
|
ScrubbedRecord
|
Builds the |
required |
Returns:
| Type | Description |
|---|---|
ScrubResult
|
The number of rows erased. |
Raises:
| Type | Description |
|---|---|
ValueError
|
The connection is in |
Source code in audit_trail/privacy.py
scrub_actor ¶
scrub_actor(
connection: Connection,
tables: AuditTables,
actor_id: str,
*,
scope_ids: Collection[str] | None,
record: ScrubbedRecord,
) -> ScrubResult
Clear an actor's personal context, and record it.
audit_transaction rows with this actor_id get actor_label,
remote_addr, user_agent and meta set to NULL; the
audit_activity rows with this actor_id lose those keys from
data.context. actor_id itself stays everywhere.
A transaction row belongs to the actor it was created with: a request
that wrote its first entry anonymously and then called set_actor
keeps its address and user agent on that anonymous row.
With scope_ids, only activity rows whose scope_id is one of them
are changed, and a transaction row only when it has activity rows and
every one of them, whoever its actor, is in those scopes: its fields are
shared by all its entries, so a request that also wrote entries of
another scope, or without a scope, keeps them, as does a transaction row
without entries. An empty collection changes nothing. Clearing an
actor completely across scopes takes a run without scope_ids.
When the actor scrubs themself, the audit.scrubbed entry is written
without those fields too.
Runs in the connection's current transaction; the caller commits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
Connection
|
Connection whose role may update the audit tables. |
required |
tables
|
AuditTables
|
The audit tables. |
required |
actor_id
|
str
|
The actor's |
required |
scope_ids
|
Collection[str] | None
|
The scopes the scrub is restricted to; |
required |
record
|
ScrubbedRecord
|
Builds the |
required |
Returns:
| Type | Description |
|---|---|
ScrubResult
|
The numbers of rows changed. |
Raises:
| Type | Description |
|---|---|
ValueError
|
The connection is in |
Source code in audit_trail/privacy.py
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | |