pub async fn secure_insert<E>(
am: E::ActiveModel,
scope: &AccessScope,
runner: &impl DBRunner,
) -> Result<E::Model, ScopeError>where
E: ScopableEntity + EntityTrait,
E::Column: ColumnTrait + Copy,
E::ActiveModel: ActiveModelTrait<Entity = E> + Send,
E::Model: IntoActiveModel<E::ActiveModel>,Expand description
Secure insert helper for Scopable entities.
This helper performs a standard INSERT through SeaORM but wraps database
errors into a unified ScopeError type for consistent error handling across
secure data-access code.
§Scope Validation
Validates all scope constraints against the ActiveModel’s column values,
not just tenant_id. For each constraint in the scope, every filter’s property
is resolved to a column via ScopableEntity::resolve_property, and the
ActiveModel’s value for that column is checked against the filter’s values.
At least one constraint must match entirely (OR semantics) for the insert to
proceed.
§Responsibilities
- Does not inspect the
SecurityContextor enforce tenant scoping rules. - Does not automatically populate any entity fields.
- Callers are responsible for:
- Setting all required fields before calling.
- Validating that the operation is authorized within the current
SecurityContext(e.g., verifyingtenant_idor resource ownership).
§Behavior by Entity Type
§Tenant-scoped entities (have tenant_col)
- Must have a valid, non-empty
tenant_idset in theActiveModelbefore insert. - The
tenant_idshould come from the request payload or be validated againstSecurityContextby the service layer before calling this helper.
§Global entities (no tenant_col)
- May be inserted freely without tenant validation.
- Typical examples include system-wide configuration or audit logs.
§Recommended Field Population
When inserting entities, populate these fields from SecurityContext in service code:
tenant_id: from payload or validated viactx.scope()owner_id: fromctx.subject_id()created_by: fromctx.subject_id()if applicable
§Example
ⓘ
use modkit_db::secure::{secure_insert, SecurityContext};
// Domain/service layer validates tenant_id beforehand
let am = user::ActiveModel {
id: Set(Uuid::new_v4()),
tenant_id: Set(tenant_id),
owner_id: Set(ctx.subject_id()),
email: Set("user@example.com".to_string()),
..Default::default()
};
// Simple secure insert wrapper
let user = secure_insert::<user::Entity>(am, &ctx, conn).await?;§Errors
- Returns
ScopeError::Dbif the database insert fails. - Returns
ScopeError::Deniedif theActiveModelvalues do not satisfy any scope constraint. - Returns
ScopeError::TenantNotInScopefor tenant isolation violations.