Class: Placet::Definition

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

Overview

Policy 定義の保持と検証。正規形(spec/schema/policy-document.schema.json)と 1:1

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeDefinition

Returns a new instance of Definition.



15
16
17
18
# File 'lib/placet/document.rb', line 15

def initialize
  @policies = {}     # name => [Statement]
  @attachments = {}  # principal => [policy names]
end

Instance Attribute Details

#attachmentsObject (readonly)

Returns the value of attribute attachments.



13
14
15
# File 'lib/placet/document.rb', line 13

def attachments
  @attachments
end

#policiesObject (readonly)

Returns the value of attribute policies.



13
14
15
# File 'lib/placet/document.rb', line 13

def policies
  @policies
end

Class Method Details

.from_canonical(doc) ⇒ Object

正規形(JSON 互換 Hash・文字列キー)からの読み込み

Raises:



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/placet/document.rb', line 21

def self.from_canonical(doc)
  raise DefinitionError, "ドキュメントが Hash ではない" unless doc.is_a?(Hash)

  version = doc["version"]
  raise DefinitionError, "未対応の version: #{version.inspect}" unless version == 1

  definition = new
  Array(doc["policies"]).each do |policy|
    statements = Array(policy["statements"]).map do |st|
      effect = st["effect"]
      raise DefinitionError, "effect が不正: #{effect.inspect}" unless %w[allow deny].include?(effect)

      Statement.new(effect: effect, actions: Array(st["actions"]))
    end
    definition.add_policy(policy["name"], statements)
  end
  Array(doc["attachments"]).each do |attachment|
    definition.add_attachment(attachment["principal"], Array(attachment["policies"]))
  end
  definition.validate!
  definition
end

Instance Method Details

#add_attachment(principal, names) ⇒ Object



52
53
54
55
56
57
58
# File 'lib/placet/document.rb', line 52

def add_attachment(principal, names)
  unless principal.is_a?(String) && principal =~ PRINCIPAL_RE
    raise DefinitionError, "principal が不正(type:id 形式・* 不可): #{principal.inspect}"
  end

  @attachments[principal] = (@attachments[principal] || []) | names
end

#add_policy(name, statements) ⇒ Object

Raises:



44
45
46
47
48
49
50
# File 'lib/placet/document.rb', line 44

def add_policy(name, statements)
  raise DefinitionError, "policy 名が不正: #{name.inspect}" unless name.is_a?(String) && name =~ POLICY_NAME_RE
  raise DefinitionError, "policy 名が重複: #{name}" if @policies.key?(name)
  raise DefinitionError, "statements が空: #{name}" if statements.empty?

  @policies[name] = statements
end

#to_canonicalObject



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/placet/document.rb', line 75

def to_canonical
  {
    "version" => 1,
    "policies" => @policies.map do |name, statements|
      { "name" => name,
        "statements" => statements.map { |s| { "effect" => s.effect, "actions" => s.actions } } }
    end,
    "attachments" => @attachments.map do |principal, names|
      { "principal" => principal, "policies" => names }
    end
  }
end

#validate!(registry = nil) ⇒ Object

registry を渡すと、action パターンのレジストリ照合(lint)もあわせて行う



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/placet/document.rb', line 61

def validate!(registry = nil)
  @attachments.each do |principal, names|
    names.each do |name|
      unless @policies.key?(name)
        raise DefinitionError, "attachment が未定義の policy を参照: #{name} (principal: #{principal})"
      end
    end
  end
  @policies.each do |name, statements|
    statements.each { |st| st.actions.each { |pattern| validate_pattern!(pattern, name, registry) } }
  end
  self
end