Legal holds, step 2: who a hold covers
A hold reaches an account by name, through any of its addresses' domains, its groups or its tenant, as they are now, so an account added to a held domain later is held too. An account that leaves a held domain, group or tenant stays held: the registry write hook adds it to the hold by name on every account change, whoever makes it (LH-2). Server::holds_on answers for the deletion paths, from the store each time so a hold binds every node at once.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Coffey Labs
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
//! inbuxa: which legal holds cover an account (audit-hold-lock spec, LH-2,
|
||||
//! LH-11), for the paths that destroy data. Read from the store every time,
|
||||
//! not cached: a hold placed on one node must bind every node at once, and
|
||||
//! there are few holds.
|
||||
|
||||
use crate::Server;
|
||||
use inbuxa_features::hold::{self, Hold, Member};
|
||||
|
||||
impl Server {
|
||||
/// The active holds covering `account_id`, through its own name, its
|
||||
/// addresses' domains, its groups or its tenant. Empty for an account
|
||||
/// that no longer exists: a deleted one is kept by LH-8's own check.
|
||||
pub async fn holds_on(&self, account_id: u32) -> trc::Result<Vec<Hold>> {
|
||||
let Ok(account) = self.account(account_id).await else {
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
let mut domains = account
|
||||
.addresses
|
||||
.iter()
|
||||
.map(|address| address.domain_id)
|
||||
.collect::<Vec<_>>();
|
||||
domains.sort_unstable();
|
||||
domains.dedup();
|
||||
let member = Member {
|
||||
account: account_id,
|
||||
domains,
|
||||
groups: account.id_member_of.iter().copied().collect(),
|
||||
tenant: account.id_tenant,
|
||||
};
|
||||
hold::covering(self.store(), &member).await
|
||||
}
|
||||
|
||||
/// Whether any active hold covers `account_id` at all.
|
||||
pub async fn is_held(&self, account_id: u32) -> trc::Result<bool> {
|
||||
Ok(!self.holds_on(account_id).await?.is_empty())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user