Class: Sequel::Privacy::Policy

Inherits:
Proc
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/sequel/privacy/policy.rb

Overview

A Policy wraps a Proc/lambda with metadata about how it should be evaluated.

Policies are actor-first. Arities map to:

  • 0 args: -> { allow if Time.now.sunday? } # Global decision

  • 1 arg: ->(actor) { allow if actor.is_role?(:admin) }

  • 2 args: ->(actor, subject) { allow if subject.owner_id == actor.id }

  • 3 args: ->(actor, subject, direct_object) { … }

Any policy with arity >= 1 auto-denies for anonymous viewers (nil actor) unless declared with ‘allow_anonymous: true`. That flag is for state-gate policies that deliberately ignore actor — e.g. “post is published.”

Policies must return :allow, :deny, :pass, or an array of policies (for combinators).

Constant Summary collapse

VALID_CACHE_BY =
T.let(%i[actor subject direct_object].freeze, T::Array[Symbol])

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#commentObject (readonly)

Returns the value of attribute comment.



26
27
28
# File 'lib/sequel/privacy/policy.rb', line 26

def comment
  @comment
end

#policy_nameObject (readonly)

Returns the value of attribute policy_name.



23
24
25
# File 'lib/sequel/privacy/policy.rb', line 23

def policy_name
  @policy_name
end

Class Method Details

.create(policy_name, lam, comment = nil, cacheable: true, single_match: false, cache_by: nil, allow_anonymous: false) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/sequel/privacy/policy.rb', line 43

def self.create(policy_name, lam, comment = nil, cacheable: true, single_match: false, cache_by: nil,
                allow_anonymous: false)
  new(&lam).setup(
    policy_name: policy_name,
    comment: comment,
    cacheable: cacheable,
    single_match: single_match,
    cache_by: cache_by,
    allow_anonymous: allow_anonymous
  )
end

Instance Method Details

#allow_anonymous?Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/sequel/privacy/policy.rb', line 105

def allow_anonymous?
  @allow_anonymous || false
end

#cache_byObject



100
101
102
# File 'lib/sequel/privacy/policy.rb', line 100

def cache_by
  @cache_by
end

#cacheable?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/sequel/privacy/policy.rb', line 88

def cacheable?
  @cacheable || false
end

#setup(policy_name: nil, comment: nil, cacheable: true, single_match: false, cache_by: nil, allow_anonymous: false) ⇒ Object

Configure the policy after creation

Parameters:

  • policy_name (Symbol, nil) (defaults to: nil)

    Human-readable name for logging

  • comment (String, nil) (defaults to: nil)

    Description of what this policy does

  • cacheable (Boolean) (defaults to: true)

    Whether results can be cached (default: true)

  • single_match (Boolean) (defaults to: false)

    Whether only one subject/actor pair can match (default: false)

  • cache_by (Symbol, Array<Symbol>, nil) (defaults to: nil)

    Override the cache-key dimensions. By default the key is derived from the policy’s arity (all inputs the policy receives). Pass a subset of ‘:actor, :subject, :direct_object` to cache by only those — useful when the policy ignores inputs it nominally receives (e.g. an “is-admin” check that takes `(actor, subject)` but only examines actor should use `cache_by: :actor` to share a single entry across subjects).

  • allow_anonymous (Boolean) (defaults to: false)

    If true, skip the auto-deny that normally fires when a policy of arity >= 1 is evaluated for an anonymous viewer (nil actor). Use for state-gate policies that ignore the actor and decide purely on subject state.



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/sequel/privacy/policy.rb', line 73

def setup(policy_name: nil, comment: nil, cacheable: true, single_match: false, cache_by: nil,
          allow_anonymous: false)
  raise 'Privacy Policy is frozen' if @frozen

  @cacheable = cacheable
  @policy_name = policy_name.to_s
  @comment = comment
  @frozen = true
  @single_match = single_match
  @cache_by = normalize_cache_by(cache_by)
  @allow_anonymous = allow_anonymous
  self
end

#single_match?Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/sequel/privacy/policy.rb', line 95

def single_match?
  @single_match || false
end