pub struct PersonalDataSet {
pub table: &'static str,
pub subject: &'static str,
pub kind: DataKind,
pub disposition: Disposition,
pub description: &'static str,
pub redacted: &'static [&'static str],
pub subject_via: Option<SubjectVia>,
}Expand description
One table’s worth of personal data, declared by the module that owns it.
Deliberately not #[non_exhaustive], unlike the enums above: every
declaration is a const literal written in a module’s own crate, and
#[non_exhaustive] forbids exactly that from outside this one. The type
would be undeclarable by the only people who declare it. Adding a field is
therefore a breaking change here, which is the honest trade — a new required
field ought to make every module state its answer rather than inherit a
default nobody chose.
Fields§
§table: &'static strThe table. Must be one this module claims in
Module::tables; a name that is not is a build
error, so a rename that misses this declaration cannot ship.
subject: &'static strThe column holding the subject’s id — the value export and erasure match on.
kind: DataKindWhat kind of data this is.
disposition: DispositionWhat erasure does to it.
description: &'static strOne sentence, for a person deciding whether to trust this. It is published verbatim, so write it for them rather than for a colleague.
redacted: &'static [&'static str]Columns an export names but never copies: the row is the subject’s, and one of its columns is credential material.
A push token and a Web Push endpoint are the case this exists for. They
are the subject’s — the table has to be declared, or erasure never
reaches them — but an endpoint is a bearer capability: whoever holds
it can notify that device, so a copy in an export file is a copy of the
credential, and ADR 0015 keeps that material out of a response body.
Dropping the column silently would be worse than either: an export is
read by somebody checking whether anything is missing, so the column is
listed with its value replaced by [redacted], which says “held, not
handed over” rather than “not held”.
It changes nothing about erasure. A row that is deleted takes its columns with it, and a column named here is still counted, still erased, and still described.
subject_via: Option<SubjectVia>How this table reaches its subject through another table, when the column that identifies a person here is not the column the requests are made with.
The privacy query builders run one subject value across every
declaration, and by default match it against subject
directly. A table whose rows are written before an account is known —
a provider callback naming a person by their app-scoped id — has an
honest subject that no request value will ever match. Naming a route
through the table that does hold the account id makes the export find
the row and the erasure preview count it:
WHERE <subject> IN (SELECT <via.key> FROM <via.table> WHERE <via.subject> = ?)Some replaces direct matching rather than adding to it: the row
is found only through the join, so there is exactly one answer to
“which rows are this person’s”, the same one for export, preview,
delete and verify. The subject value is still bound, never
interpolated, and the three names are checked to be plain identifiers
exactly like the rest.
The case that demanded this is deletion_jobs (issue #281): keyed on
provider_subject, reached through identities(user_id → provider_subject).
Implementations§
Source§impl PersonalDataSet
impl PersonalDataSet
Sourcepub const fn none(table: &'static str, reason: &'static str) -> Self
pub const fn none(table: &'static str, reason: &'static str) -> Self
A table this module owns that holds nothing personal, and the reason.
The reason is the point. A module may legitimately own reference data keyed to nobody — pose definitions, plan tiers, a cue library — and those tables should not appear in an export. But “no declaration” and “nothing personal here” look identical in source, and only one of them is a decision. This makes the second one say so.
Sourcepub const fn unreachable(
table: &'static str,
kind: DataKind,
description: &'static str,
reason: &'static str,
) -> Self
pub const fn unreachable( table: &'static str, kind: DataKind, description: &'static str, reason: &'static str, ) -> Self
A table this module owns that holds personal data erasure cannot reach, and the reason.
The table does hold data about somebody — the sentence says what —
but no declaration can make it queryable, because the identifying
value is inside a rendered message or a composite key rather than in a
column an … = ? predicate can match. Declaring it
none would be a lie in the other direction: a
subject-facing manifest would report a table holding the person’s
message as not personal data (issue #274).
Like none, this sets a blank subject, so export,
erasure and PersonalDataCatalog::subject_sets skip the table —
they cannot reach it, and pretending otherwise would mean building a
predicate that matches nothing. Unlike none, the declaration counts
towards PersonalDataCatalog::is_empty: a deployment holding data
it cannot erase does hold data.
Sourcepub const fn is_none(&self) -> bool
pub const fn is_none(&self) -> bool
Whether this declaration says the table holds no personal data.
Read as “no subject column a request value can be bound to”, not
literally “nothing personal”: unreachable
declarations also have a blank subject, and a manifest must bucket
those with is_unreachable before treating
a blank subject as an answer about the table’s contents.
Sourcepub const fn is_unreachable(&self) -> bool
pub const fn is_unreachable(&self) -> bool
Whether this declaration describes personal data erasure cannot reach.
A table answering true holds somebody’s data and says so; the reason
is the Unreachable payload, published verbatim. It is not
queryable — there is no subject column a request value can be bound
to — so it never appears in an export, an erasure plan or
PersonalDataCatalog::subject_sets, but it is counted by
PersonalDataCatalog::is_empty and bucketed on its own by a
subject-facing manifest.
Sourcepub fn validate(&self, module: &str, owns: &[&'static str]) -> Vec<String>
pub fn validate(&self, module: &str, owns: &[&'static str]) -> Vec<String>
Rejects a declaration that cannot mean anything, reporting against the
module that made it. Called by HarnessBuilder::build.
The rules are the ones a typo breaks: a table the module does not own, a
subject column that is blank on a set that claims to hold data, an
Anonymise naming no columns (which would erase nothing and report
success), and a description missing from something that gets published.
Trait Implementations§
Source§impl Clone for PersonalDataSet
impl Clone for PersonalDataSet
Source§fn clone(&self) -> PersonalDataSet
fn clone(&self) -> PersonalDataSet
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for PersonalDataSet
Source§impl Debug for PersonalDataSet
impl Debug for PersonalDataSet
impl Eq for PersonalDataSet
Source§impl PartialEq for PersonalDataSet
impl PartialEq for PersonalDataSet
impl StructuralPartialEq for PersonalDataSet
Auto Trait Implementations§
impl Freeze for PersonalDataSet
impl RefUnwindSafe for PersonalDataSet
impl Send for PersonalDataSet
impl Sync for PersonalDataSet
impl Unpin for PersonalDataSet
impl UnsafeUnpin for PersonalDataSet
impl UnwindSafe for PersonalDataSet
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.