conjur-asset-dsl2 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.dockerignore +2 -0
- data/.gitignore +14 -0
- data/.project +18 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/CHANGELOG +1 -0
- data/Dockerfile.dev +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +248 -0
- data/Rakefile +18 -0
- data/backup.tar +0 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/conjur-asset-dsl2.gemspec +32 -0
- data/jenkins.sh +36 -0
- data/lib/conjur/command/dsl2.rb +175 -0
- data/lib/conjur/dsl2/executor/base.rb +50 -0
- data/lib/conjur/dsl2/executor/create.rb +117 -0
- data/lib/conjur/dsl2/executor/deny.rb +13 -0
- data/lib/conjur/dsl2/executor/give.rb +12 -0
- data/lib/conjur/dsl2/executor/grant.rb +13 -0
- data/lib/conjur/dsl2/executor/permit.rb +16 -0
- data/lib/conjur/dsl2/executor/retire.rb +7 -0
- data/lib/conjur/dsl2/executor/revoke.rb +11 -0
- data/lib/conjur/dsl2/executor/update.rb +31 -0
- data/lib/conjur/dsl2/executor.rb +99 -0
- data/lib/conjur/dsl2/invalid.rb +12 -0
- data/lib/conjur/dsl2/plan.rb +49 -0
- data/lib/conjur/dsl2/planner/base.rb +215 -0
- data/lib/conjur/dsl2/planner/grants.rb +85 -0
- data/lib/conjur/dsl2/planner/permissions.rb +80 -0
- data/lib/conjur/dsl2/planner/record.rb +102 -0
- data/lib/conjur/dsl2/planner.rb +38 -0
- data/lib/conjur/dsl2/ruby/loader.rb +263 -0
- data/lib/conjur/dsl2/types/base.rb +376 -0
- data/lib/conjur/dsl2/types/create.rb +15 -0
- data/lib/conjur/dsl2/types/deny.rb +17 -0
- data/lib/conjur/dsl2/types/give.rb +14 -0
- data/lib/conjur/dsl2/types/grant.rb +24 -0
- data/lib/conjur/dsl2/types/member.rb +14 -0
- data/lib/conjur/dsl2/types/permit.rb +22 -0
- data/lib/conjur/dsl2/types/policy.rb +129 -0
- data/lib/conjur/dsl2/types/records.rb +243 -0
- data/lib/conjur/dsl2/types/retire.rb +14 -0
- data/lib/conjur/dsl2/types/revoke.rb +14 -0
- data/lib/conjur/dsl2/types/update.rb +16 -0
- data/lib/conjur/dsl2/yaml/handler.rb +400 -0
- data/lib/conjur/dsl2/yaml/loader.rb +29 -0
- data/lib/conjur-asset-dsl2-version.rb +7 -0
- data/lib/conjur-asset-dsl2.rb +27 -0
- data/syntax.md +147 -0
- metadata +237 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
module Conjur::DSL2
|
2
|
+
module Executor
|
3
|
+
# Builds a list of execution actions for a statement. The statement
|
4
|
+
# is an object from Conjur::DSL2::Types. Each execution action is
|
5
|
+
# an HTTP method, a request path, and request parameters.
|
6
|
+
class Base
|
7
|
+
attr_reader :statement, :actions, :default_account
|
8
|
+
|
9
|
+
def initialize statement, actions, default_account
|
10
|
+
@statement = statement
|
11
|
+
@actions = actions
|
12
|
+
@default_account = default_account
|
13
|
+
end
|
14
|
+
|
15
|
+
def action obj
|
16
|
+
@actions.push obj
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute
|
20
|
+
raise "execute not implemented in #{self.class.name}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def resource_path record = nil
|
24
|
+
record ||= self.statement
|
25
|
+
[ "authz", record.account || default_account, "resources", record.resource_kind, record.id ].join('/')
|
26
|
+
end
|
27
|
+
|
28
|
+
def role_path record = nil
|
29
|
+
record ||= self.statement
|
30
|
+
[ "authz", record.account || default_account, "roles", record.role_kind, record.id ].join('/')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Annotate
|
35
|
+
def annotate
|
36
|
+
Array(annotate_record.annotations).each do |k,v|
|
37
|
+
action({
|
38
|
+
'method' => 'put',
|
39
|
+
'path' => update_annotation_path,
|
40
|
+
'parameters' => { "name" => k, "value" => v }
|
41
|
+
})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_annotation_path
|
46
|
+
[ "authz", annotate_record.account || default_account, "annotations", annotate_record.resource_kind, annotate_record.id ].join('/')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Conjur::DSL2::Executor
|
2
|
+
# Abstract base class for creating a new record.
|
3
|
+
class Create < Base
|
4
|
+
def record
|
5
|
+
statement.record
|
6
|
+
end
|
7
|
+
|
8
|
+
def account
|
9
|
+
record.account || default_account
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Generic 'create' implementation which POSTs to a resources URL.
|
14
|
+
class CreateRecord < Create
|
15
|
+
include Annotate
|
16
|
+
|
17
|
+
def execute
|
18
|
+
action({
|
19
|
+
'method' => 'post',
|
20
|
+
'path' => create_path,
|
21
|
+
'parameters' => create_parameters
|
22
|
+
})
|
23
|
+
annotate
|
24
|
+
end
|
25
|
+
|
26
|
+
def annotate_record
|
27
|
+
record
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_path
|
31
|
+
[ kind_path ].join('/')
|
32
|
+
end
|
33
|
+
|
34
|
+
def kind_path
|
35
|
+
record.resource_kind.pluralize
|
36
|
+
end
|
37
|
+
|
38
|
+
# Each record is assumed to have an 'id' attribute required for creation.
|
39
|
+
# In addition, other create parameters can be specified by the +custom_attribute_names+
|
40
|
+
# method on the record.
|
41
|
+
def create_parameters
|
42
|
+
{
|
43
|
+
record.id_attribute => record.id
|
44
|
+
}.tap do |params|
|
45
|
+
custom_attrs = record.custom_attribute_names.inject({}) do |memo, attr|
|
46
|
+
value = record.send(attr)
|
47
|
+
memo[attr.to_s] = value if value
|
48
|
+
memo
|
49
|
+
end
|
50
|
+
params.merge! custom_attrs
|
51
|
+
params["ownerid"] = record.owner.roleid(record.owner.account || default_account) if record.owner
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# When creating a host factory, the +roleid+ and +layer+ are required.
|
57
|
+
class CreateHostFactory < CreateRecord
|
58
|
+
def create_parameters
|
59
|
+
super.tap do |params|
|
60
|
+
params['roleid'] = record.role.roleid(default_account)
|
61
|
+
params['layers'] = Array(record.layers).map(&:id)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# When creating a variable, set default values for the +mime_type+ and +kind+.
|
67
|
+
class CreateVariable < CreateRecord
|
68
|
+
def create_parameters
|
69
|
+
super.tap do |params|
|
70
|
+
params['mime_type'] ||= 'text/plain'
|
71
|
+
params['kind'] ||= 'secret'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# When creating a raw Role or Resource, the owner of the new record is specified by
|
77
|
+
# the +acting_as+ parameter.
|
78
|
+
module ActingAs
|
79
|
+
def acting_as_parameters
|
80
|
+
{}.tap do |params|
|
81
|
+
params["acting_as"] = record.owner.roleid(default_account) if record.owner
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Create a new Resource with a PUT request to the resource path.
|
87
|
+
class CreateResource < Create
|
88
|
+
include ActingAs
|
89
|
+
include Annotate
|
90
|
+
|
91
|
+
def execute
|
92
|
+
action({
|
93
|
+
'method' => 'put',
|
94
|
+
'path' => resource_path(statement.record),
|
95
|
+
'parameters' => acting_as_parameters
|
96
|
+
})
|
97
|
+
annotate
|
98
|
+
end
|
99
|
+
|
100
|
+
def annotate_record
|
101
|
+
statement.record
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Create a new Role with a PUT request to the role path.
|
106
|
+
class CreateRole < Create
|
107
|
+
include ActingAs
|
108
|
+
|
109
|
+
def execute
|
110
|
+
action({
|
111
|
+
'method' => 'put',
|
112
|
+
'path' => role_path(statement.record),
|
113
|
+
'parameters' => acting_as_parameters
|
114
|
+
})
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Conjur::DSL2::Executor
|
2
|
+
# Deny a privilege with a POST request to the +deny+ url of the resource, with the privilege
|
3
|
+
# and role as parameters.
|
4
|
+
class Deny < Base
|
5
|
+
def execute
|
6
|
+
action({
|
7
|
+
'method' => 'post',
|
8
|
+
'path' => "#{resource_path(statement.resource)}?deny",
|
9
|
+
'parameters' => { "privilege" => statement.privilege, "role" => statement.role.roleid(default_account) }
|
10
|
+
})
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Conjur::DSL2::Executor
|
2
|
+
# Change the owner of a resource with a PUT request to the resource path, specifying the new owner.
|
3
|
+
class Give < Base
|
4
|
+
def execute
|
5
|
+
action({
|
6
|
+
'method' => 'put',
|
7
|
+
'path' => resource_path(statement.resource),
|
8
|
+
'parameters' => { "owner" => statement.owner.roleid(default_account) }
|
9
|
+
})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Conjur::DSL2::Executor
|
2
|
+
class Grant < Base
|
3
|
+
def execute
|
4
|
+
parameters = { "member" => statement.member.role.roleid(default_account) }
|
5
|
+
parameters['admin_option'] = statement.member.admin unless statement.member.admin.nil?
|
6
|
+
action({
|
7
|
+
'method' => 'put',
|
8
|
+
'path' => "authz/#{statement.role.account || default_account}/roles/#{statement.role.role_kind}/#{statement.role.id}?members",
|
9
|
+
'parameters' => parameters
|
10
|
+
})
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Conjur::DSL2::Executor
|
2
|
+
# Permit a privilege with a POST request to the +permit+ url of the resource, with the privilege
|
3
|
+
# and role as parameters. +grant_option+ is also provided if it is explicitly stated on the Permit
|
4
|
+
# record.
|
5
|
+
class Permit < Base
|
6
|
+
def execute
|
7
|
+
parameters = { "privilege" => statement.privilege, "role" => statement.role.role.roleid(default_account) }
|
8
|
+
parameters['grant_option'] = admin unless statement.role.admin.nil?
|
9
|
+
action({
|
10
|
+
'method' => 'post',
|
11
|
+
'path' => "#{resource_path(statement.resource)}?permit",
|
12
|
+
'parameters' => parameters
|
13
|
+
})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Conjur::DSL2::Executor
|
2
|
+
class Update < Base
|
3
|
+
include Annotate
|
4
|
+
|
5
|
+
def execute
|
6
|
+
statement.record.custom_attribute_names.each do |attr|
|
7
|
+
value = statement.record.send(attr)
|
8
|
+
action({
|
9
|
+
'method' => 'put',
|
10
|
+
'path' => update_path,
|
11
|
+
'parameters' => { attr.to_s => value }
|
12
|
+
})
|
13
|
+
end
|
14
|
+
|
15
|
+
annotate
|
16
|
+
end
|
17
|
+
|
18
|
+
def kind_path
|
19
|
+
statement.record.resource_kind.pluralize
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_path
|
23
|
+
require 'cgi'
|
24
|
+
[ kind_path, CGI.escape(statement.record.id) ].join('/')
|
25
|
+
end
|
26
|
+
|
27
|
+
def annotate_record
|
28
|
+
statement.record
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Executor
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'conjur/dsl2/executor/base'
|
9
|
+
require 'conjur/dsl2/executor/create'
|
10
|
+
require 'conjur/dsl2/executor/give'
|
11
|
+
require 'conjur/dsl2/executor/grant'
|
12
|
+
require 'conjur/dsl2/executor/revoke'
|
13
|
+
require 'conjur/dsl2/executor/permit'
|
14
|
+
require 'conjur/dsl2/executor/deny'
|
15
|
+
require 'conjur/dsl2/executor/retire'
|
16
|
+
require 'conjur/dsl2/executor/update'
|
17
|
+
|
18
|
+
module Conjur
|
19
|
+
module DSL2
|
20
|
+
module Executor
|
21
|
+
class << self
|
22
|
+
def class_for action
|
23
|
+
if action.is_a?(Conjur::DSL2::Types::Create)
|
24
|
+
class_name = action.record.class.name.split("::")[-1]
|
25
|
+
begin
|
26
|
+
Conjur::DSL2::Executor.const_get([ "Create", class_name ].join)
|
27
|
+
rescue NameError
|
28
|
+
Conjur::DSL2::Executor::CreateRecord
|
29
|
+
end
|
30
|
+
else
|
31
|
+
class_name = action.class.name.split("::")[-1]
|
32
|
+
Conjur::DSL2::Executor.const_get(class_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class HTTPExecutor
|
39
|
+
def initialize api
|
40
|
+
@api = api
|
41
|
+
end
|
42
|
+
|
43
|
+
def execute actions
|
44
|
+
require 'net/https'
|
45
|
+
uri = URI.parse(Conjur.configuration.appliance_url)
|
46
|
+
@base_path = uri.path
|
47
|
+
Net::HTTP.start uri.host, uri.port, use_ssl: true do |http|
|
48
|
+
@http = http
|
49
|
+
actions.each do |step|
|
50
|
+
invoke step
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def invoke step
|
58
|
+
send step['method'], step['path'], step['parameters']
|
59
|
+
end
|
60
|
+
|
61
|
+
def create path, parameters
|
62
|
+
request = Net::HTTP::Post.new [ @base_path, path ].join('/')
|
63
|
+
request.set_form_data parameters
|
64
|
+
send_request request
|
65
|
+
end
|
66
|
+
|
67
|
+
alias post create
|
68
|
+
|
69
|
+
def update path, parameters
|
70
|
+
request = Net::HTTP::Put.new [ @base_path, path ].join('/')
|
71
|
+
request.set_form_data parameters
|
72
|
+
send_request request
|
73
|
+
end
|
74
|
+
|
75
|
+
alias put update
|
76
|
+
|
77
|
+
def delete path, parameters
|
78
|
+
uri = URI.parse([ @base_path, path ].join('/'))
|
79
|
+
uri.query = [uri.query, parameters.map{|k,v| [ k, URI.escape(v) ].join('=')}.join("&")].compact.join('&')
|
80
|
+
request = Net::HTTP::Delete.new [ uri.path, '?', uri.query ].join
|
81
|
+
|
82
|
+
send_request request
|
83
|
+
end
|
84
|
+
|
85
|
+
def send_request request
|
86
|
+
# $stderr.puts "#{request.method.upcase} #{request.path} #{request.body}"
|
87
|
+
require 'base64'
|
88
|
+
request['Authorization'] = "Token token=\"#{Base64.strict_encode64 @api.token.to_json}\""
|
89
|
+
response = @http.request request
|
90
|
+
# $stderr.puts response.code
|
91
|
+
if response.code.to_i >= 300
|
92
|
+
$stderr.puts "#{request.method.upcase} #{request.path} #{request.body} failed with error #{response.code}:"
|
93
|
+
# $stderr.puts "Request failed with error #{response.code}:"
|
94
|
+
$stderr.puts response.body
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
class Invalid < Exception
|
4
|
+
attr_reader :mark
|
5
|
+
|
6
|
+
def initialize message, filename, mark
|
7
|
+
super [ "Error at line #{mark.line}, column #{mark.column} in #{filename}", message ].join(' : ')
|
8
|
+
@mark = mark
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
class Plan
|
4
|
+
attr_reader :actions, :policy, :roles_created, :resources_created
|
5
|
+
attr_accessor :namespace, :ownerid
|
6
|
+
|
7
|
+
|
8
|
+
def initialize namespace = nil
|
9
|
+
@namespace = namespace
|
10
|
+
@actions = []
|
11
|
+
@policy = nil
|
12
|
+
@roles_created = Set.new
|
13
|
+
@resources_created = Set.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def scoped_id id
|
17
|
+
id = id.id if id.respond_to?(:id)
|
18
|
+
|
19
|
+
# id is nil means it should have the same id as the policy
|
20
|
+
id = '' if id.nil?
|
21
|
+
|
22
|
+
if id[0] == '/'
|
23
|
+
id[1..-1]
|
24
|
+
else
|
25
|
+
|
26
|
+
tokens = []
|
27
|
+
tokens.push @namespace if @namespace
|
28
|
+
tokens.push @policy.id if @policy
|
29
|
+
|
30
|
+
if id.start_with?(tokens.join('/') + '/')
|
31
|
+
id
|
32
|
+
else
|
33
|
+
tokens.push id unless id.empty?
|
34
|
+
tokens.join('/')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def policy= policy
|
40
|
+
raise "Plan policy is already specified" if @policy && policy
|
41
|
+
@policy = policy
|
42
|
+
end
|
43
|
+
|
44
|
+
def action a
|
45
|
+
@actions.push a
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Planner
|
4
|
+
class Base
|
5
|
+
|
6
|
+
attr_reader :record, :api
|
7
|
+
attr_accessor :plan
|
8
|
+
|
9
|
+
|
10
|
+
def initialize record, api
|
11
|
+
@record = record
|
12
|
+
@api = api
|
13
|
+
end
|
14
|
+
|
15
|
+
def action a
|
16
|
+
@plan.action a
|
17
|
+
end
|
18
|
+
|
19
|
+
def scoped_id id
|
20
|
+
@plan.scoped_id id
|
21
|
+
end
|
22
|
+
|
23
|
+
def scoped_roleid record
|
24
|
+
record = record.roleid(default_account) unless record.kind_of?(String)
|
25
|
+
account, kind, id = record.split(':', 3)
|
26
|
+
[ account, kind, scoped_id(id) ].join(":")
|
27
|
+
end
|
28
|
+
|
29
|
+
def scoped_resourceid record
|
30
|
+
record = record.resourceid(default_account) unless record.kind_of?(String)
|
31
|
+
account, kind, id = record.split(':', 3)
|
32
|
+
[ account, kind, scoped_id(id) ].join(":")
|
33
|
+
end
|
34
|
+
|
35
|
+
def account
|
36
|
+
(record.account rescue nil) || default_account
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_account
|
40
|
+
Conjur.configuration.account
|
41
|
+
end
|
42
|
+
|
43
|
+
def role_record fullid
|
44
|
+
account, kind, id = fullid.split(':', 3)
|
45
|
+
if kind == '@'
|
46
|
+
Conjur::DSL2::Types::ManagedRole.build fullid, default_account
|
47
|
+
else
|
48
|
+
if record_class = record_type(kind)
|
49
|
+
record_class.new.tap do |record|
|
50
|
+
record.account = account unless account == default_account
|
51
|
+
unless record.is_a?(Conjur::DSL2::Types::Variable)
|
52
|
+
record.kind = kind if record.respond_to?(:kind=)
|
53
|
+
end
|
54
|
+
record.id = id
|
55
|
+
end
|
56
|
+
else
|
57
|
+
Conjur::DSL2::Types::Role.new(fullid, default_account: default_account)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def record_type kind
|
63
|
+
begin
|
64
|
+
Conjur::DSL2::Types.const_get(kind.classify)
|
65
|
+
rescue NameError
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
alias resource_record role_record
|
71
|
+
|
72
|
+
def resource
|
73
|
+
api.resource(scoped_resourceid record)
|
74
|
+
end
|
75
|
+
|
76
|
+
def role
|
77
|
+
api.role(scoped_roleid record)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sort in canonical order -- basically, a `Record` or `Create` comes before everything
|
81
|
+
# else. So the base class's sort just places those before us, and anything else gets 0.
|
82
|
+
def <=> other
|
83
|
+
other.kind_of?(Conjur::DSL2::Planner::ActsAsRecord) ? 1 : 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def resource_exists? resource
|
87
|
+
resource_id = resource.kind_of?(String) ? resource : scoped_resourceid(resource)
|
88
|
+
(plan.resources_created.include?(resource_id) || api.resource(resource_id).exists?)
|
89
|
+
end
|
90
|
+
|
91
|
+
def role_exists? role
|
92
|
+
role_id = role.kind_of?(String) ? role : scoped_roleid(role)
|
93
|
+
# I believe it's correct to assume manged roles exist?
|
94
|
+
return true if role_id.split(':',2).last.start_with?('@')
|
95
|
+
|
96
|
+
plan.roles_created.include?(role_id) || api.role(role_id).exists?
|
97
|
+
end
|
98
|
+
|
99
|
+
def error message
|
100
|
+
# For now raise it, we can think about trying to recover down the road
|
101
|
+
raise message
|
102
|
+
end
|
103
|
+
|
104
|
+
def trace message
|
105
|
+
if trace_enabled?
|
106
|
+
$stderr.puts "[trace #{record}] #{message}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def trace_enabled?
|
111
|
+
ENV["DSL_PLANNER_TRACE"] || !!@trace_enabled
|
112
|
+
end
|
113
|
+
|
114
|
+
def trace_enabled= enabled
|
115
|
+
@trace_enabled = enabled
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def update_record
|
120
|
+
update = Conjur::DSL2::Types::Update.new
|
121
|
+
update.record = record
|
122
|
+
record.id = scoped_id(record)
|
123
|
+
|
124
|
+
changed = false
|
125
|
+
record.custom_attribute_names.each do |attr|
|
126
|
+
existing_value = object.attributes[attr]
|
127
|
+
new_value = record.send(attr)
|
128
|
+
if new_value
|
129
|
+
if new_value == existing_value
|
130
|
+
record.send "#{attr}=", nil
|
131
|
+
else
|
132
|
+
raise "Cannot modify immutable attribute '#{record.resource_kind}.#{attr}'" if record.immutable_attribute_names.member?(attr)
|
133
|
+
changed = true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
if record.resource?
|
139
|
+
existing = resource.exists? ? resource.annotations : {}
|
140
|
+
current = record.annotations.kind_of?(::Array) ? record.annotations[0] : record.annotations
|
141
|
+
(record.annotations||{}).keys.each do |attr|
|
142
|
+
existing_value = existing[attr]
|
143
|
+
new_value = record.annotations[attr]
|
144
|
+
if new_value == existing_value
|
145
|
+
record.annotations.delete attr
|
146
|
+
else
|
147
|
+
changed = true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
if record.owner && resource.owner != scoped_roleid(record.owner)
|
152
|
+
give = Conjur::DSL2::Types::Give.new
|
153
|
+
give.resource = Conjur::DSL2::Types::Resource.new(record.resourceid(default_account), default_account: default_account)
|
154
|
+
give.owner = Conjur::DSL2::Types::Role.new(scoped_roleid(record.owner), default_account: default_account)
|
155
|
+
action give
|
156
|
+
|
157
|
+
if record.role?
|
158
|
+
grant = Conjur::DSL2::Types::Grant.new
|
159
|
+
grant.role = Conjur::DSL2::Types::Role.new(record.roleid(default_account), default_account: default_account)
|
160
|
+
grant.member = Conjur::DSL2::Types::Member.new
|
161
|
+
grant.member.role = Conjur::DSL2::Types::Role.new(scoped_roleid(record.owner), default_account: default_account)
|
162
|
+
grant.member.admin = true
|
163
|
+
action grant
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
action update if changed
|
169
|
+
end
|
170
|
+
|
171
|
+
def create_record
|
172
|
+
create = Conjur::DSL2::Types::Create.new
|
173
|
+
create.record = record
|
174
|
+
record.id = scoped_id(record)
|
175
|
+
if record.owner
|
176
|
+
record.owner = Conjur::DSL2::Types::Role.new(scoped_roleid(record.owner), default_account: default_account)
|
177
|
+
elsif plan.ownerid
|
178
|
+
record.owner = Conjur::DSL2::Types::Role.new(plan.ownerid, default_account: default_account)
|
179
|
+
end
|
180
|
+
|
181
|
+
if record.resource?
|
182
|
+
existing = resource.exists? ? resource.annotations : {}
|
183
|
+
# And this is why we don't name a class Array.
|
184
|
+
current = record.annotations.kind_of?(::Array) ? record.annotations[0] : record.annotations
|
185
|
+
(current||{}).keys.each do |attr|
|
186
|
+
existing_value = existing[attr]
|
187
|
+
new_value = current[attr]
|
188
|
+
if new_value == existing_value
|
189
|
+
current.delete attr
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
plan.roles_created.add(record.roleid(account)) if record.role?
|
195
|
+
plan.resources_created.add(record.resourceid(account)) if record.resource?
|
196
|
+
action create
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
class Array < Base
|
201
|
+
|
202
|
+
def do_plan
|
203
|
+
planners = record.map do |item|
|
204
|
+
Planner.planner_for(item, api)
|
205
|
+
end.sort
|
206
|
+
|
207
|
+
planners.each do |planner|
|
208
|
+
planner.plan = self.plan
|
209
|
+
planner.do_plan
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|