Module: OpenLoam::Permissions

Defined in:
lib/open_loam/permissions.rb

Overview

Feature-string permissions with wildcards (L-705) — a fine-grained capability layer that sits UNDER the coarse role. Roles answer "manager or clerk"; permissions answer "may this role do equipment.edit" without inventing a new role for every distinction. Orthogonal to OpenLoam::Policy (which gates field-level writes on a record) and to OpenLoam::Features (a per-tenant capability switch).

Declared once, in the initializer (like broadcast_events / scheduler defaults):

OpenLoam::Permissions.configure do
role :admin,   allow: "*"                              # everything
role :manager, allow: %w[equipment.* damage_report.* billing.read]
role :clerk,   allow: %w[equipment.read damage_report.create]
end

OpenLoam::Permissions.allow?(:clerk, "equipment.read")  # => true
OpenLoam::Permissions.allow?(:clerk, "equipment.edit")  # => false
OpenLoam.can?("equipment.edit")                          # for the current actor's role

DENY BY DEFAULT: a role with no matching grant (or no grants at all) is denied.

Wildcards: * grants everything; a trailing .* is a prefix ("equipment.*" matches "equipment.read" and "equipment.anything.deep", and "equipment" itself); anything else is an exact match. (Deliberately not a full glob — prefix + all covers the real cases; a mid-string * is not special.)

Defined Under Namespace

Classes: DSL

Class Method Summary collapse

Class Method Details

.allow?(role, permission) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
45
46
# File 'lib/open_loam/permissions.rb', line 42

def allow?(role, permission)
  return false if role.nil?

  granted(role).any? { |pattern| matches?(pattern, permission.to_s) }
end

.configure(&block) ⇒ Object



28
29
30
31
# File 'lib/open_loam/permissions.rb', line 28

def configure(&block)
  DSL.new.instance_eval(&block)
  registry
end

.granted(role) ⇒ Object



40
# File 'lib/open_loam/permissions.rb', line 40

def granted(role) = registry[role.to_s] || []

.matches?(pattern, permission) ⇒ Boolean

THE wildcard rule, in one place.

Returns:

  • (Boolean)


49
50
51
52
53
54
55
56
57
58
59
# File 'lib/open_loam/permissions.rb', line 49

def matches?(pattern, permission)
  pattern = pattern.to_s
  return true if pattern == "*"

  if pattern.end_with?(".*")
    prefix = pattern[0..-2]           # "equipment." (keep the dot)
    permission == pattern[0..-3] || permission.start_with?(prefix)
  else
    permission == pattern
  end
end

.reset! ⇒ Object



61
62
63
# File 'lib/open_loam/permissions.rb', line 61

def reset!
  @registry = {}
end

.role(name, allow:) ⇒ Object

Grant one role a pattern or list of patterns (additive).



34
35
36
37
38
# File 'lib/open_loam/permissions.rb', line 34

def role(name, allow:)
  registry[name.to_s] ||= []
  registry[name.to_s].concat(Array(allow).map(&:to_s)).uniq!
  registry[name.to_s]
end