Class: Placet::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/placet/engine.rb

Overview

コア評価エンジン(PDP)。純粋関数として動作し、適合性テストの対象となる。 入力は principal 文字列の配列のみで、derive の由来(via)などランタイム層の 拡張は関知しない

Instance Method Summary collapse

Constructor Details

#initialize(definition, registry: nil) ⇒ Engine

Returns a new instance of Engine.



25
26
27
28
29
30
31
# File 'lib/placet/engine.rb', line 25

def initialize(definition, registry: nil)
  @definition = definition
  @registry = registry
  @grant_cache = {}
  @match_cache = {}
  @valid_actions = Set.new
end

Instance Method Details

#decide(principals, action) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/placet/engine.rb', line 33

def decide(principals, action)
  validate_action!(action)
  matches = matches_for(action)

  matched = []
  principals.each do |principal|
    @definition.attachments.fetch(principal, []).each do |policy_name|
      matches.fetch(policy_name, []).each do |index, effect|
        matched << Determinant.new(principal: principal, policy: policy_name,
                                   statement: index, effect: effect)
      end
    end
  end

  denies, allows = matched.partition { |m| m.effect == "deny" }
  return Decision.new(decision: :deny, basis: :explicit_deny, determinants: denies) if denies.any?
  return Decision.new(decision: :permit, basis: :explicit_allow, determinants: allows) if allows.any?

  Decision.new(decision: :deny, basis: :implicit_deny, determinants: [])
end

#scope_plan(static_principals, action, relations:) ⇒ Object

一覧フィルタリングの計画を返す。 static_principals: 静的 principal(rel: を含まない導出結果) relations: 対象モデルに定義された relation 名のリスト



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/placet/engine.rb', line 57

def scope_plan(static_principals, action, relations:)
  validate_action!(action)
  allow_ps, deny_ps = grants(action)
  static = static_principals.to_a

  if static.any? { |p| deny_ps.include?(p) }
    return ScopePlan.new(kind: "empty", include_relations: [], exclude_relations: [])
  end

  exclude = relations.select { |name| deny_ps.include?("rel:#{name}") }

  if static.any? { |p| allow_ps.include?(p) }
    return ScopePlan.new(kind: "all", include_relations: [], exclude_relations: exclude)
  end

  include_ = relations.select { |name| allow_ps.include?("rel:#{name}") }
  if include_.empty?
    ScopePlan.new(kind: "empty", include_relations: [], exclude_relations: [])
  else
    ScopePlan.new(kind: "union", include_relations: include_, exclude_relations: exclude)
  end
end

#validate_action!(action, error_class: Error) ⇒ Object

action 検証の一元的な入口。決定要求・scope 合成の action は具体的 (ワイルドカード不可)かつレジストリ宣言済み(使用時)でなければならない。 typo は静かな全拒否 / 空 scope になるため即エラーにする。 宣言時 fail-fast には error_class に DefinitionError を渡して使う



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/placet/engine.rb', line 84

def validate_action!(action, error_class: Error)
  return if @valid_actions.include?(action)

  unless action.is_a?(String) && action =~ CONCRETE_ACTION_RE
    raise error_class, "action は具体的でなければならない: #{action.inspect}"
  end
  unless @registry.nil? || @registry.known_action?(action)
    raise error_class, "未知の action: #{action}(レジストリに未宣言)"
  end

  @valid_actions << action
end