ScopeQueryPolicy

class ScopeQueryPolicy(tenants: TenantPolicy = TenantPolicy.CALLERS, val order: Int = ORDER, ownerships: QueryOwnership = QueryOwnership.OWNERS, crossTenant: Boolean = false, access: AccessPolicies = AccessPolicies.NONE) : QueryPolicy

The caller's scope as a QueryPolicy, appended at admission step 2 to every query:

  • the tenant tenants gives the caller, when it gives one; else, for a cross-tenant caller, its tenants (none for every tenant): a type whose tenant is fixed keeps its own;

  • the default rule (ScopeAccess) of the caller's principal: an owner equality when it names an owner (an owner-level caller) and ownerships says the aggregate type belongs to its owner, and a space equality when it names a space: a tenant-level caller, whose principal names no owner, reads every aggregate of its tenant. The kernel holds a command to the same rule. It is the access rule of an aggregate without an access policy of its own: one with a policy (AccessPolicies.governs), and a dataset whose rows are such an aggregate's, read by that policy instead (AccessQueryPolicy). On the events, the owner and space compared are the aggregate's current ones each stream records among its access attributes (access.owner, access.space), not those of its commit: an aggregate's history shows to its owner of now, and a stream not yet stamped to no owner or space;

  • the deletion scope the model defaults to (a snapshot query sees active aggregates) unless the query states its own deletion filter. Admission's step 3 would add the same default; stating it here keeps the whole scope one audited policy.

An HTTP caller is first checked again against the read side's rules over tenants and crossTenant (QueryTargets.recheck), whoever built it. A caller without a tenant, owner or space (trusted in-process code) is restricted by none of them. A model that does not carry one of these fields rejects the filter at validation, so the scope fails closed rather than being dropped.

Constructors

Link copied to clipboard
constructor(tenants: TenantPolicy = TenantPolicy.CALLERS, order: Int = ORDER, ownerships: QueryOwnership = QueryOwnership.OWNERS, crossTenant: Boolean = false, access: AccessPolicies = AccessPolicies.NONE)

Types

Link copied to clipboard

Properties

Link copied to clipboard
open override val order: Int

Where this policy runs among the others, lowest first.

Functions

Link copied to clipboard
open suspend override fun evaluate(caller: QueryCaller, context: QueryContext<*>): FilterExpression