Skip to main content

PersonalDataSet

Struct PersonalDataSet 

Source
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 str

The 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 str

The column holding the subject’s id — the value export and erasure match on.

§kind: DataKind

What kind of data this is.

§disposition: Disposition

What erasure does to it.

§description: &'static str

One 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

Source

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.

Source

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.

Source

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.

Source

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.

Source

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

Source§

fn clone(&self) -> PersonalDataSet

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for PersonalDataSet

Source§

impl Debug for PersonalDataSet

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for PersonalDataSet

Source§

impl PartialEq for PersonalDataSet

Source§

fn eq(&self, other: &PersonalDataSet) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for PersonalDataSet

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more