0.0
The project is in a healthy, maintained state
Cerberus is a policy evaluation engine implementing ABAC authorization model.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

Cerberus

Cerberus is a rule engine for Ruby applications inspired by the XACML (eXtensible Access Control Markup Language) standard.

๐Ÿ‘‰ Learn more about XACML: https://en.wikipedia.org/wiki/XACML

It provides a structured way to define, manage, and evaluate rules and policies in a consistent and scalable manner. It provides a structured way to define, manage, and evaluate rules and policies in a consistent and scalable manner.

While internally it follows a modular architecture with pluggable adapters and dependency injection, its primary goal is to offer a familiar policy-based approach similar to XACML, adapted for Ruby applications.


๐Ÿ“‹ Requirements

  • Ruby >= 3.1
  • Rails >= 7.0 (only for ActiveRecord adapter)
  • PostgreSQL (recommended, due to JSONB support)

โœจ Features

  • Decoupled domain and infrastructure layers
  • Pluggable persistence adapters (ActiveRecord, future: Sequel, etc.)
  • Dependency injection via container
  • Composable operations (use-cases)
  • Flexible rule and expression system

๐Ÿš€ Installation

Add this line to your application's Gemfile:

gem 'cerberus-xacml'

And then execute:

bundle install

โš™๏ธ Configuration

Create an initializer:

# config/initializers/cerberus.rb

Cerberus::Base.plugin :active_record

๐Ÿงฑ Database Setup

Install migrations

Create task

Cerberus::Generators::Migrations.install!(:active_record, 'path/to/migrations/dir')
bin/rails db:migrate

Manual migration example

If you prefer to manage schema manually:

class InitCerberusMigration < ActiveRecord::Migration[7.0]
  create_table :cerberus_policies do |t|
    t.string :action, null: false
    t.string :resource_type, null: false
    t.string :strategy, null: false

    t.timestamp
  end

  add_index :cerberus_policies, %i[action resource_type], unique: true, name: 'index_cerberus_policies_uniqueness'

  create_table :cerberus_rules do |t|
    t.string :effect, null: false

    t.timestamps
  end

  create_table :cerberus_policy_rules do |t|
    t.belongs_to :policy, foreign_key: { to_table: :cerberus_policies }
    t.belongs_to :rule, foreign_key: { to_table: :cerberus_rules }

    t.timestamps
  end

  create_table :cerberus_operands do |t|
    t.string :kind, null: false
    t.string :value
    t.string :name
    t.string :value_type

    t.timestamps
  end

  create_table :cerberus_expressions do |t|
    t.string :type, null: false
    t.string :operator, null: false
    t.belongs_to :rule, foreign_key: { to_table: :cerberus_rules }
    t.belongs_to :parent, foreign_key: { to_table: :cerberus_expressions }
    t.belongs_to :left_operand, foreign_key: { to_table: :cerberus_operands }
    t.belongs_to :right_operand, foreign_key: { to_table: :cerberus_operands }

    t.timestamps
  end
end

๐Ÿงฉ Usage

Create a rule

rule = Cerberus::Domain::Rule.create(name: "Test rule")

Add expressions

rule.expressions.create!(kind: "equals", payload: { field: "status", value: "active" })

Using operations

result = Cerberus::Operations::Rules::Create.call(name: "Test")

if result.success?
  rule = result.value!
else
  puts result.failure
end

โš ๏ธ Do not use infrastructure models directly in your application. Always go through domain or operations layer.


๐Ÿงช Testing

Example with RSpec:

RSpec.describe Cerberus::Domain::Rule do
  it 'creates a rule' do
    expect { described_class.create(name: 'Test') }
      .to change(described_class, :count).by(1)
  end
end

๐Ÿ— Architecture

cerberus/
  domain/        # Pure business logic
  infra/         # Adapters (ActiveRecord, etc.)
  operations/    # Use cases
  plugins/       # Set up for plugins

โš ๏ธ Important Notes

  • Do not depend on infra layer directly
  • Always use public API (operations, domain interfaces)
  • Database schema may evolve โ€” check migrations on upgrade

๐Ÿ›  Roadmap

  • Sequel adapter
  • ROM adapter
  • YAML adapter
  • Async evaluation
  • Rule builder DSL

๐Ÿ’ก Example Workflow

# seeds
op1 = operand.create!(kind: :resource, name: 'nested.role')
op2 = operand.create!(kind: :subject, name: 'role')

r1 = rule.create!(effect: :permit)
c1 = condition.create!(rule: r1, operator: :eq, left_operand: op1, right_operand: op2)
p = policy.create!(action: :update, resource_type: :vehicle, strategy: :permit_overrides)
p.rules << r1

# usage
Cerberus::Base.authorize!(
  action: :update,
  resource_type: :vehicle,
  subject: Struct.new(:id, :role).new(1, 'admin'),
  resource: Struct.new(:nested).new(Struct.new(:role).new('admin'))
)

๐Ÿ“„ License

MIT