m20260514_000001_fediverse_guard_schema.rs
242 lignes · 8546 octets
//! Migration `m20260514_000001_fediverse_guard_schema`. //! //! Creates the three tables backing the fediverse-guard runtime: //! //! - `fediverse_guard_events` — raw event log, indexed by //! `(domain, created_at DESC)` to feed sliding-window detectors. //! - `fediverse_guard_bans` — active + historical bans, indexed by //! `(domain)` with a partial-unique on rows whose `lifted_at IS NULL`. //! - `fediverse_guard_acl` — manual allow/deny rules with FK to //! `users.id`. //! //! All columns use UTC timestamps. UUID primary keys are caller- //! generated (Rust-side `uuid::Uuid::new_v4()`) — Postgres' `gen_random_uuid()` //! is reserved for the rare DDL-only inserts (none here). use sea_orm_migration::prelude::*; use sea_orm_migration::sea_orm::ConnectionTrait; #[derive(DeriveMigrationName)] pub struct Migration; #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { // ---- fediverse_guard_events ---------------------------------- manager .create_table( Table::create() .table(FediverseGuardEvents::Table) .col( ColumnDef::new(FediverseGuardEvents::Id) .uuid() .not_null() .primary_key(), ) .col( ColumnDef::new(FediverseGuardEvents::EventType) .text() .not_null(), ) .col( ColumnDef::new(FediverseGuardEvents::Domain) .text() .not_null(), ) .col(ColumnDef::new(FediverseGuardEvents::ActorUri).text().null()) .col( ColumnDef::new(FediverseGuardEvents::RemoteIdentityId) .uuid() .null(), ) .col( ColumnDef::new(FediverseGuardEvents::Severity) .text() .not_null(), ) .col( ColumnDef::new(FediverseGuardEvents::HttpStatus) .integer() .null(), ) .col( ColumnDef::new(FediverseGuardEvents::Details) .json_binary() .null(), ) .col( ColumnDef::new(FediverseGuardEvents::CreatedAt) .timestamp_with_time_zone() .not_null(), ) .to_owned(), ) .await?; let conn = manager.get_connection(); conn.execute_unprepared( "CREATE INDEX fediverse_guard_events_domain_time_idx \ ON fediverse_guard_events (domain, created_at DESC)", ) .await?; conn.execute_unprepared( "CREATE INDEX fediverse_guard_events_type_time_idx \ ON fediverse_guard_events (event_type, created_at DESC)", ) .await?; // ---- fediverse_guard_bans ------------------------------------ manager .create_table( Table::create() .table(FediverseGuardBans::Table) .col( ColumnDef::new(FediverseGuardBans::Id) .uuid() .not_null() .primary_key(), ) .col(ColumnDef::new(FediverseGuardBans::Domain).text().not_null()) .col(ColumnDef::new(FediverseGuardBans::ActorUri).text().null()) .col(ColumnDef::new(FediverseGuardBans::Reason).text().not_null()) .col( ColumnDef::new(FediverseGuardBans::Severity) .text() .not_null(), ) .col( ColumnDef::new(FediverseGuardBans::TriggeredBy) .text() .not_null(), ) .col( ColumnDef::new(FediverseGuardBans::BannedAt) .timestamp_with_time_zone() .not_null(), ) .col( ColumnDef::new(FediverseGuardBans::ExpiresAt) .timestamp_with_time_zone() .null(), ) .col( ColumnDef::new(FediverseGuardBans::LiftedAt) .timestamp_with_time_zone() .null(), ) .col(ColumnDef::new(FediverseGuardBans::LiftedBy).uuid().null()) .to_owned(), ) .await?; conn.execute_unprepared( "CREATE INDEX fediverse_guard_bans_active_idx \ ON fediverse_guard_bans (domain) WHERE lifted_at IS NULL", ) .await?; // ---- fediverse_guard_acl ------------------------------------- manager .create_table( Table::create() .table(FediverseGuardAcl::Table) .col( ColumnDef::new(FediverseGuardAcl::Id) .uuid() .not_null() .primary_key(), ) .col(ColumnDef::new(FediverseGuardAcl::Kind).text().not_null()) .col(ColumnDef::new(FediverseGuardAcl::Domain).text().not_null()) .col(ColumnDef::new(FediverseGuardAcl::Reason).text().null()) .col( ColumnDef::new(FediverseGuardAcl::CreatedBy) .uuid() .not_null(), ) .col( ColumnDef::new(FediverseGuardAcl::CreatedAt) .timestamp_with_time_zone() .not_null(), ) .col( ColumnDef::new(FediverseGuardAcl::UpdatedAt) .timestamp_with_time_zone() .not_null(), ) .to_owned(), ) .await?; conn.execute_unprepared( "CREATE UNIQUE INDEX fediverse_guard_acl_kind_domain_uniq \ ON fediverse_guard_acl (kind, domain)", ) .await?; Ok(()) } async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { let conn = manager.get_connection(); conn.execute_unprepared("DROP INDEX IF EXISTS fediverse_guard_acl_kind_domain_uniq") .await?; manager .drop_table(Table::drop().table(FediverseGuardAcl::Table).to_owned()) .await?; conn.execute_unprepared("DROP INDEX IF EXISTS fediverse_guard_bans_active_idx") .await?; manager .drop_table(Table::drop().table(FediverseGuardBans::Table).to_owned()) .await?; conn.execute_unprepared("DROP INDEX IF EXISTS fediverse_guard_events_type_time_idx") .await?; conn.execute_unprepared("DROP INDEX IF EXISTS fediverse_guard_events_domain_time_idx") .await?; manager .drop_table(Table::drop().table(FediverseGuardEvents::Table).to_owned()) .await?; Ok(()) } } #[derive(DeriveIden)] enum FediverseGuardEvents { Table, Id, EventType, Domain, ActorUri, RemoteIdentityId, Severity, HttpStatus, Details, CreatedAt, } #[derive(DeriveIden)] enum FediverseGuardBans { Table, Id, Domain, ActorUri, Reason, Severity, TriggeredBy, BannedAt, ExpiresAt, LiftedAt, LiftedBy, } #[derive(DeriveIden)] enum FediverseGuardAcl { Table, Id, Kind, Domain, Reason, CreatedBy, CreatedAt, UpdatedAt, }
GitRust