tetthys/cake

Functional, layered business authorization: S(u,a,o,c) โˆง D(u,a,o,c), deny-by-default, composable rules, and Laravel integration.

Maintainers

Details

github.com/tetthys/cake

Source

Issues

Installs: 6

Dependents: 0

Suggesters: 0

Security: 0

Stars: 2

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/tetthys/cake

0.1.0 2025-09-17 10:27 UTC

This package is auto-updated.

Last update: 2025-10-17 11:13:45 UTC


README

Functional, Layered Business Authorization for PHP & Laravel

tetthys/cake provides a reusable authorization engine based on the idea of
layering subject-level checks (who the user is) and domain-level checks (what the object/context allows).
It is framework-agnostic but ships with helpers for Laravel integration.

๐Ÿ”‘ Core Idea

Every authorization rule is defined as:

$$ R(u, a, o, c) = S(u, a, o, c) ; \land ; D(u, a, o, c) $$

  • S โ†’ Subject condition (user role, identity, authentication, global permissions)
  • D โ†’ Domain condition (object state, relationships, business rules, context)
  • R โ†’ Authorization rule. Permit only if both S and D are true.

Multiple rules can be combined:

$$ R = (S_1 \land D_1) ; \lor ; (S_2 \land D_2) ; \lor ; \dots ; \lor ; (S_n \land D_n) $$

If no rule matches โ†’ deny by default.

๐Ÿ—๏ธ Layered Architecture

flowchart TD
    A[Request Entry] --> B[Middleware Layer]
    B -->|Check S (Subject)| C[Business Service Layer]
    C -->|Check D (Domain)| D[Permit or Deny]

    B -.->|Fail| X[403 Forbidden]
    C -.->|Fail| X
Loading
  • Middleware layer โ†’ subject checks (roles, auth, global flags)
  • Service/domain layer โ†’ domain checks (object state, business rules)
  • Defense in depth โ†’ both layers must succeed.

โœจ Features

  • Formal but simple model: R = S โˆง D
  • Composable: combine rules with AND / OR / NOT
  • Deny-by-default: safety guaranteed
  • Functional style: policies are pure functions, easy to test
  • Explainable decisions: trace shows why access was allowed/denied
  • Laravel ready: middleware and traits included

๐Ÿ“ฆ Installation

composer require tetthys/cake

๐Ÿš€ Quick Example

use Tetthys\Cake\Model\Actor;
use Tetthys\Cake\Model\Action;
use Tetthys\Cake\Model\ObjectRef;
use Tetthys\Cake\Model\Context;
use Tetthys\Cake\Engine\Engine;
use Tetthys\Cake\Rule\Rule;
use Tetthys\Cake\Rule\RuleSet;
use Tetthys\Cake\Contracts\SubjectPredicate;
use Tetthys\Cake\Contracts\DomainPredicate;

$isManager = new class implements SubjectPredicate {
    public function __invoke($u, $a, $o, $c): bool {
        return in_array('manager', $u->roles, true);
    }
};

$isLargePendingOrder = new class implements DomainPredicate {
    public function __invoke($u, $a, $o, $c): bool {
        return ($o->data->status ?? null) === 'PENDING'
            && ($o->data->amount ?? 0) >= 10_000_000;
    }
};

$rules = new RuleSet([
    new Rule('ManagerCanApprove', $isManager, $isLargePendingOrder),
]);

$engine = new Engine();

$actor   = new Actor(id: 1, roles: ['manager']);
$action  = new Action('order.approve');
$object  = new ObjectRef('Order', (object)['status' => 'PENDING', 'amount' => 12_000_000]);
$context = new Context([]);

$decision = $engine->decide($actor, $action, $object, $context, $rules);

echo $decision->outcome; // "PERMIT"
print_r($decision->trace);

๐Ÿงฉ Laravel Integration

1. Register middleware

// app/Http/Kernel.php
protected $routeMiddleware = [
    'cake' => \Tetthys\Cake\Integration\Laravel\AuthorizationMiddleware::class,
];

2. Define rules factory

final class OrderRules {
    public function approve(Request $request): RuleSet {
        // return a RuleSet with subject/domain predicates
    }
}

3. Protect a route

Route::post('/orders/{order}/approve', [OrderController::class, 'approve'])
    ->middleware('cake:order.approve,App\\Policies\\OrderRules@approve');

๐Ÿงช Testing

This repo uses Pest. We include Docker setup for isolated test runs:

bash ./run/test.sh

Filter tests:

bash ./run/test.sh --filter Engine

๐Ÿ“ License

MIT ยฉ Tetthys