Skip to main content

baukit_erasure/
lib.rs

1//! Erase product data atomically and choose whether to delete the identity account.
2#![deny(missing_docs)]
3
4#[cfg(feature = "api-providers")]
5mod api;
6#[cfg(feature = "keycloak")]
7mod keycloak;
8mod store;
9mod worker;
10
11use std::{future::Future, pin::Pin};
12
13#[cfg(feature = "api-providers")]
14pub use api::{ApiDeletionConfig, ClerkAccountDeleter, WorkOsAccountDeleter};
15#[cfg(feature = "keycloak")]
16pub use keycloak::{KeycloakAccountDeleter, KeycloakDeletionConfig};
17pub use store::{
18    ErasureError, ErasureOutcome, ErasurePreflight, ErasureService, ErasureState,
19    IdentityRetention, PostgresErasureStore, ProductErasure, reject_fenced_subject,
20};
21pub use worker::IdentityDeletionHandler;
22
23/// Reference migration to copy after the baukit-jobs migrations.
24pub const POSTGRES_MIGRATION_SQL: &str = include_str!("../migrations/0001_erasure.sql");
25/// Reference migration to copy after 0001 erasure.
26pub const POSTGRES_REONBOARDING_MIGRATION_SQL: &str =
27    include_str!("../migrations/0002_erasure_reonboarding.sql");
28/// Durable job identifier.
29pub const IDENTITY_DELETE_JOB_TYPE: &str = "identity.account.delete";
30/// Boxed asynchronous result used by erasure ports.
31pub type ErasureFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
32
33/// Safe failure classes. Errors never include provider bodies, subjects, or credentials.
34#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
35pub enum IdentityDeletionError {
36    /// Network, token acquisition, rate limit, or server failure.
37    #[error("identity deletion temporarily unavailable")]
38    Retryable,
39    /// Invalid request or missing provider permission.
40    #[error("identity deletion rejected permanently")]
41    Permanent,
42}
43
44/// Provider-neutral account deletion. An absent account is successful deletion.
45pub trait IdentityAccountDeleter: Send + Sync + 'static {
46    /// Deletes the account and its provider sessions.
47    fn delete_account<'a>(
48        &'a self,
49        subject: &'a str,
50    ) -> ErasureFuture<'a, Result<(), IdentityDeletionError>>;
51}