Skip to main content

secure_insert

Function secure_insert 

Source
pub async fn secure_insert<E>(
    am: E::ActiveModel,
    scope: &AccessScope,
    runner: &impl DBRunner,
) -> Result<E::Model, ScopeError>
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 SecurityContext or 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., verifying tenant_id or resource ownership).

§Behavior by Entity Type

§Tenant-scoped entities (have tenant_col)

  • Must have a valid, non-empty tenant_id set in the ActiveModel before insert.
  • The tenant_id should come from the request payload or be validated against SecurityContext by 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.

When inserting entities, populate these fields from SecurityContext in service code:

  • tenant_id: from payload or validated via ctx.scope()
  • owner_id: from ctx.subject_id()
  • created_by: from ctx.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::Db if the database insert fails.
  • Returns ScopeError::Denied if the ActiveModel values do not satisfy any scope constraint.
  • Returns ScopeError::TenantNotInScope for tenant isolation violations.