Modules
The port: the one place an application asks whether a subject can perform an operation on an object. It is also the contract every adapter implements. The words are NIST SP 800-162's: subject, object, operation, and environment.
The access event: one telemetry event for each mediated read of a
protected schema. The seam publishes it after the read returns, at the
one site every query function passes through. So it covers get, one,
all, exists?, aggregate, stream, preload, and reload alike.
Only a read that carried a decision publishes. An exempt read, a read
through the owner-role repo, and a raw query publish nothing.
The contract every adapter implements. The port calls each callback with
a subject, an operation, an object or an object type, the environment,
and the adapter's validated options. The adapter answers and never raises
on the request path. around_query/3, options_schema/0, and settle/0
are optional. The port and the seam check at runtime whether the adapter
exports them, so one build serves every adapter. What produced an answer
travels on the answer's meta, where the adapter can say.
What a decider answers for one subject, operation, and object. It holds
the verdict, the reason in one word, the version of the rules that gave
it, and meta.
The change event: one telemetry event for each single-row write to an audited schema. The seam computes it from the write itself and publishes it inside the write's transaction. So a consumer that writes to the same repository from its handler joins that transaction.
The only runtime configuration the library reads. boot!/1 validates it
once at boot from a NimbleOptions schema and stores it. The adapter is
a module or a {module, keyword} pair, and a bare module means [],
which the adapter's options_schema/0 still validates. The port and the
seam call resolve/0. It answers the boot struct under the overrides
Mediate.Test.with_config/1 put in the process dictionary. It takes the
first non-empty override, from the caller and then from each process in
its $callers chain, and merges it over the boot struct field by field.
The stamped answer: what the port said, when, from what state, under which rules. It is the value the seam accepts under mediate:.
The one exception. reason is the word that says why, and detail is the
sentence a reader needs, which is also the message.
A named, logged opt-out from mediation, per call. :declared carries the
caller's reason. :library marks the seam's own writes, and the seam
accepts it only from a Mediate.* module.
An identifier: a UUID string, the shape every subject, object, decision, and operation id has.
One published version of an adapter's rules. content holds the text by
value when it is under the configured cap. Otherwise pointer names where
the text lives. A decision record carries only the version identifier.
The mechanism behind the functions of Mediate. It resolves the
configuration and builds the environment from the caller's map and the
clock. It asks the adapter. It fails closed on an engine error or on an
exception the decider raised. It stamps a Mediate.Decision and
publishes it.
The seam. Its purpose is log completeness: no read or write of a protected schema goes unrecorded, because a call that carries no decision and no exemption raises before any SQL. It is not a reference monitor. It sees repo calls and nothing else, and no control asks it for more.
Declarations on an Ecto schema. They say
One declared fact column. It holds the kind, the column that names the
subject, the column that names the object, and the element type of a
set-valued column. Mediate.Schema.fact/2 records it, and the seam reads
it.
A row that is a grant: the subject column, the object column, and the
columns that are attributes of the relationship.
Mediate.Schema.relationship/1 records it.
Helpers every test tier and a third party's adapter suite share
The clock a test sets. set/1 overrides the configured clock for the rest
of the current process and answers the moment it set. So a test that
needs a fixed time names it once, and every call the port makes reads it.
The adapter Tier 1 runs first and the seam's tests bind. Its rules are a
table in an Agent, one per test. A test binds it through the
configuration override as {Mediate.Test.Fake, rules: pid}. An entry
allows one holder one operation on one object or on any object of a
type. A holder is one subject, an account whatever its kind, or any
subject. The fake allows nothing else.