Multi-tenancy: the inbuxa-features crate, the permission ceiling and tenant disk quota (MT-12, MT-13, MT-14, MT-15, MT-16, MT-19, MT-20)

New crate crates/features (inbuxa-features), AGPL-3.0-only, holding the
tenancy rules. Hooks in common: a tenant's roles and permission lists cap
its people's permissions; a change to a tenant, or to a role a tenant holds,
drops its members' cached permissions; delivery and every other write check
the tenant's maxDiskQuota; usedDiskQuota reads the tenant usage counter.
The default Tenant Administrator role gains sysTenantGet and sysTenantQuery.
This commit is contained in:
2026-09-18 15:19:58 -07:00
parent b6b345a129
commit ad0db8b2b0
18 changed files with 1398 additions and 5 deletions
+80
View File
@@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2026 John Coffey
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
//! Which registry object types a principal in a tenant can reach (MT-2,
//! MT-11, MT-12).
//!
//! Inside a tenant, a principal reaches the object types that can belong to
//! a tenant (filtered to its own), its own account's settings and
//! credentials, the queue (filtered by `queue`), and, to read only, its own
//! tenant. Everything else is server-level and refused, whatever permissions
//! it holds.
use registry::schema::prelude::{OBJ_FILTER_ACCOUNT, OBJ_FILTER_TENANT, ObjectType};
/// Whether a principal in a tenant can read objects of this type.
pub fn can_read(object_type: ObjectType) -> bool {
object_type.flags() & (OBJ_FILTER_TENANT | OBJ_FILTER_ACCOUNT) != 0
|| matches!(
object_type,
ObjectType::AccountSettings
| ObjectType::AccountPassword
| ObjectType::AppPassword
| ObjectType::ApiKey
| ObjectType::QueuedMessage
| ObjectType::Tenant
)
}
/// Whether a principal in a tenant can create, change or destroy objects of
/// this type. The tenant object itself is server-level (MT-12).
pub fn can_write(object_type: ObjectType) -> bool {
can_read(object_type) && object_type != ObjectType::Tenant
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tenant_types() {
for t in [
ObjectType::Account,
ObjectType::Domain,
ObjectType::DkimSignature,
ObjectType::AcmeProvider,
ObjectType::DnsServer,
ObjectType::Role,
ObjectType::MailingList,
ObjectType::OAuthClient,
ObjectType::Directory,
ObjectType::QueuedMessage,
] {
assert!(can_read(t) && can_write(t), "{t:?}");
}
}
#[test]
fn own_tenant_is_read_only() {
assert!(can_read(ObjectType::Tenant));
assert!(!can_write(ObjectType::Tenant));
}
#[test]
fn server_level_types() {
// Observed 3: listeners, certificates and system settings.
for t in [
ObjectType::NetworkListener,
ObjectType::Certificate,
ObjectType::SystemSettings,
ObjectType::Authentication,
ObjectType::Bootstrap,
ObjectType::Task,
] {
assert!(!can_read(t), "{t:?}");
}
}
}