AshReplicant.Resource.Verifiers.ValidateActionMultitenancy (AshReplicant v0.3.0)

Copy Markdown View Source

Compile-verifier (surfaced as a Spark diagnostic; build-blocking under --warnings-as-errors): the sink-selected actions of a multitenant replicant resource must not declare multitenancy :bypass / :bypass_all.

The sink mirrors through the host's PRIMARY create (upsert, and the SCD2 version-open), PRIMARY destroy, and — for an SCD2 resource — the configured history_close_action. It also READS through the PRIMARY read: the SCD2 close (Ash.bulk_update) and mirror delete (Ash.bulk_destroy) build an Ash.Query.do_filter over the primary read to match the rows they update/delete, and under the stream strategy that read must be tenant-scoped. Ash keys the tenant scoping on each action's :multitenancy mode:

  • :enforce (default) — force-sets/filters the discriminator AND requires a tenant → scoped;
  • :allow_global — force-sets/filters when a tenant is present (the sink ALWAYS passes a resolved tenant, fail-closed on nil/false) → scoped;
  • :bypass / :bypass_all — neither scopes nor requires → the tenant the sink passes is silently ignored and the write/read spans tenants (fail-open isolation). On a read this lets a bulk_update/bulk_destroy match and mutate ANOTHER tenant's rows.

So this verifier rejects :bypass / :bypass_all on any sink-selected action (primary read/create/destroy + SCD2 close) of a multitenant resource. It fires only when the resource declares multitenancy (a non-multitenant resource has no tenant to bypass). A non-sink action's mode is the host's business and is not checked. Messages are value-free — they name the action and its declared mode, never a row value.