Mediate.Rbac.Policy (mediate_rbac v0.1.0)

Copy Markdown View Source

The policy module: the role table as data and, per protected schema, the clauses of its rule.

defmodule MyApp.Roles do
  use Mediate.Rbac.Policy, version: "2026.09.1", author: "platform", approval: "ticket 41"

  role :reader, [:read]
  role :editor, [:read, :edit]

  object MyApp.Folder do
    grant :membership, MyApp.Membership
    predicate :cleared, &MyApp.Predicates.cleared/2
  end
end

The rule allows an operation on a row when any grant holds a role that permits it, and when every applicable predicate holds. A grant's relationship schema declares its subject, object, and role columns with Mediate.Schema.relationship/1. The grant reads them, and takes on:, role:, or as: when the schema's declaration is not enough. through: serves a relationship that names a row the protected row points at, and not the protected row itself. It lists the hops from the protected row outward. Each hop is a schema, the column of it the inner set matches, and an optional where: capture that narrows the hop's rows:

object MyApp.Page do
  grant :membership, MyApp.Membership, on: :folder_id, through: [{MyApp.Folder, :id, where: &MyApp.Rules.open/0}]
end

Mediate.Rbac.Policy.Clause says what each option means. A predicate is a capture of a named function, so the policy stays data a hash can name. only: names the operations it applies to. version: defaults to the content hash of the policy's modules, author: and approval: to "unrecorded".

The role table is data at compile time. objects/1 builds the clauses at each read of the policy, and checks each against the schemas it names. Three declarations raise there:

  • a schema without an object type
  • a relationship the grant cannot read
  • a predicate that is not a named capture

So a bad policy fails at boot, when Mediate.Rbac.publish/0 reads it, and not on a request. A build at read time keeps the policy module free of compile-time dependencies on the schemas and predicates it names. A change to any of them recompiles nothing but itself.

Summary

Types

t()

A module that uses this one.

Functions

Makes the module a policy. use_schema/0 has the options.

A grant clause: the relationship schema whose rows hold a role on the protected row.

The modules the rules live in: the policy and the module of every predicate and hop filter, sorted.

A protected schema and, in the block, the clauses of its rule.

The protected schemas and their clauses, built and checked against the schemas they name.

Every operation some role permits.

The use options: version, author, approval.

A predicate clause: a capture of a named function of the subject and the environment.

A row of the role table.

The role table.

The roles that permit an operation.

The role table as data: each role's name to its permissions.

The options use accepts.

Types

t()

@type t() :: module()

A module that uses this one.

Functions

__using__(options)

(macro)

Makes the module a policy. use_schema/0 has the options.

grant(name, source, options \\ [])

(macro)

A grant clause: the relationship schema whose rows hold a role on the protected row.

modules(policy)

@spec modules(t()) :: [module()]

The modules the rules live in: the policy and the module of every predicate and hop filter, sorted.

object(schema, list)

(macro)

A protected schema and, in the block, the clauses of its rule.

objects(policy)

@spec objects(t()) :: [Mediate.Rbac.Policy.Object.t()]

The protected schemas and their clauses, built and checked against the schemas they name.

operations(policy)

@spec operations(t()) :: [atom()]

Every operation some role permits.

options(policy)

@spec options(t()) :: keyword()

The use options: version, author, approval.

predicate(name, fun, options \\ [])

(macro)

A predicate clause: a capture of a named function of the subject and the environment.

role(name, permissions)

(macro)

A row of the role table.

roles(policy)

@spec roles(t()) :: [Mediate.Rbac.Policy.Role.t()]

The role table.

roles_for(policy, operation)

@spec roles_for(t(), atom()) :: [atom()]

The roles that permit an operation.

table(policy)

@spec table(t()) :: keyword([atom()])

The role table as data: each role's name to its permissions.

use_schema()

@spec use_schema() :: NimbleOptions.t()

The options use accepts.