feat(userLifecycle): plug actions to on_user_logout and on_user_deleted

- AuthzCacheLifecycleHook — invalidates the user_groups_cache Moka entry on logout/delete.
  - SessionRevocationLifecycleHook — explicit per-session firing of on_user_logout (currently per-call); session revocation inside the user-delete transaction.
  - DeletionMode-driven policy in HomeFolderLifecycleHook::on_user_deleted (trash vs hard-delete based on AdminDelete / GdprPurge).
  - Refactor delete_user_admin to expose a transaction handle so on_user_deleted can abort atomically.
This commit is contained in:
Edouard Vanbelle
2026-06-01 16:14:18 +02:00
parent d81f5dbe48
commit 6a6f070106
8 changed files with 342 additions and 50 deletions
+25 -6
View File
@@ -778,12 +778,31 @@ impl UserLifecycleHook for HomeFolderLifecycleHook {
Ok(())
}
async fn on_user_deleted(&self, _user: &User, _mode: DeletionMode) -> Result<(), DomainError> {
// PR 4 will fill this in with the trash-vs-hard-delete policy
// (AdminDelete → trash with retention, GdprPurge → hard delete).
// For PR 3 the eager `DELETE FROM auth.users` cascades via the
// existing FK on storage.folders to remove the home folder, so a
// no-op here matches behaviour parity.
async fn on_user_deleted(
&self,
user: &User,
mode: DeletionMode,
_tx: &mut sqlx::Transaction<'_, sqlx::Postgres>,
) -> Result<(), DomainError> {
// For both DeletionMode variants today the FK CASCADE on
// `storage.folders.user_id` (and downstream files/blobs)
// removes the home folder + contents when the user row goes.
// The hook emits a per-mode tracing event so audit can tell
// AdminDelete (currently recoverable only via DB-level rollback
// before commit) from GdprPurge (no sweeper exists yet — the
// variant is reserved for a future PR that adds retention).
//
// The `tx` is provided per the trait contract but unused here:
// emitting a tracing event doesn't require DB access. Future
// policy (trash with retention) would write to `storage.trash`
// inside this same tx.
tracing::info!(
target: "user_lifecycle",
hook = "home_folder",
user_id = %user.id(),
mode = ?mode,
"Home folder will be removed via FK CASCADE on user delete"
);
Ok(())
}
}