Policies
A policy decides whether an actor may invoke an action. Every action in the graph has exactly one policy. The runtime evaluates it before any data is touched.
The Policy contract
interface Policy
{
public function evaluate(
Actor $actor,
string $actionFqn,
?Subject $subject,
Context $context,
): Decision;
}
A policy returns a Decision enum value:
| Decision | Meaning |
|---|---|
Permit | the action is allowed |
Deny | the action is refused |
Abstain | the policy makes no decision |
Deny-by-default, fail-closed
The PolicyEngine applies two safety rules when it evaluates a policy:
- Abstain becomes Deny. If a policy returns
Abstain, the engine treats it asDeny. There is no "allow because nothing objected". - An exception becomes Deny. If a policy throws, the engine catches it and
returns
Deny. A broken policy fails closed, never open.
If the decision is anything other than Permit, the runtime throws
PolicyDenied and the invocation stops before the transaction opens.
The built-in policy: RoleRequired
v0.1.0 ships one policy implementation: RoleRequired. It permits the action
if the actor holds a named role.
You attach it through the DSL with ->requireRole():
'issue' => Action::transition('status', from: 'DRAFT', to: 'ISSUED')
->requireRole('invoice.issuer'),
The compiler creates a PolicyNode for the action that constructs a
RoleRequired policy with role: 'invoice.issuer'. At invocation time the
engine checks the role against the actor's role list.
Actors
An actor is who is performing the action. The Actor contract exposes a
ref, a role list, a permission list, and a canonical roleHash().
v0.1.0 ships StubActor — a fixed in-memory actor:
use Ausus\{StubActor, ActorRef};
$actor = new StubActor(
new ActorRef('user', 'user42', 'acme'),
['invoice.creator', 'invoice.issuer', 'invoice.canceler', 'invoice.viewer'],
);
The HTTP API builds a StubActor from request headers (X-Actor-Id,
X-Actor-Roles) — see The HTTP API.
Current v0.1.0 limitations
RoleRequiredis the only policy implementation. There is no attribute-based policy, no permission-based policy, and no policy combination (all-of / any-of) in v0.1.0.- There is no authentication.
StubActoris a trusted, caller-supplied identity. Anything exposing the runtime — including the HTTP API — must put a real authentication layer in front of it. The reservedausus/auth-bridgepackage is the planned home for that and ships no code in v0.1.0. - Field-level and projection-level visibility policies are designed but not enforced in v0.1.0.
Related
- The Runtime — where the policy check runs.
- Entities, Fields & Actions — actions carry policies.
- Error Reference —
PolicyDeniedand related errors.