conjur-asset-dsl2 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,243 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module Types
|
4
|
+
# A createable record type.
|
5
|
+
class Record < Base
|
6
|
+
def role?
|
7
|
+
false
|
8
|
+
end
|
9
|
+
def resource?
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ActsAsResource
|
15
|
+
def self.included(base)
|
16
|
+
base.module_eval do
|
17
|
+
attribute :id, kind: :string, singular: true, dsl_accessor: true
|
18
|
+
attribute :account, kind: :string, singular: true
|
19
|
+
attribute :owner, kind: :role, singular: true, dsl_accessor: true
|
20
|
+
|
21
|
+
attribute :annotations, kind: :hash, type: Hash, singular: true
|
22
|
+
|
23
|
+
def description value
|
24
|
+
annotation 'description', value
|
25
|
+
end
|
26
|
+
|
27
|
+
def annotation name, value
|
28
|
+
self.annotations ||= {}
|
29
|
+
self.annotations[name] = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize id = nil
|
35
|
+
self.id = id if id
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
"#{resource_kind.gsub('_', ' ')} '#{id}'#{account ? ' in account \'' + account + '\'': ''}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def resourceid default_account = nil
|
43
|
+
[ account || default_account, resource_kind, id ].join(":")
|
44
|
+
end
|
45
|
+
|
46
|
+
def resource_kind
|
47
|
+
self.class.name.split("::")[-1].underscore
|
48
|
+
end
|
49
|
+
|
50
|
+
def resource_id
|
51
|
+
id
|
52
|
+
end
|
53
|
+
|
54
|
+
def action
|
55
|
+
:create
|
56
|
+
end
|
57
|
+
|
58
|
+
def resource?
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def immutable_attribute_names
|
63
|
+
[]
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
module ActsAsRole
|
69
|
+
def roleid default_account
|
70
|
+
[ account || default_account, role_kind, id ].join(":")
|
71
|
+
end
|
72
|
+
|
73
|
+
def role?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def role_kind
|
78
|
+
self.class.name.split("::")[-1].underscore
|
79
|
+
end
|
80
|
+
|
81
|
+
def role_id
|
82
|
+
id
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module ActsAsCompoundId
|
87
|
+
def initialize kind_or_id = nil, id_or_options = nil
|
88
|
+
if kind_or_id && id_or_options && id_or_options.is_a?(String)
|
89
|
+
self.kind = kind_or_id
|
90
|
+
self.id = id_or_options
|
91
|
+
elsif kind_or_id && kind_or_id.index(":")
|
92
|
+
id_or_options ||= {}
|
93
|
+
account, self.kind, self.id = kind_or_id.split(':', 3)
|
94
|
+
self.account = account if account != id_or_options[:default_account]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def == other
|
99
|
+
other.kind_of?(ActsAsCompoundId) && kind == other.kind && id == other.id && account == other.account
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s
|
103
|
+
"#{kind} #{self.class.short_name.underscore} '#{id}'#{account ? ' in account \'' + account + '\'': ''}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Role < Record
|
108
|
+
include ActsAsRole
|
109
|
+
include ActsAsCompoundId
|
110
|
+
|
111
|
+
attribute :id, kind: :string, singular: true, dsl_accessor: true
|
112
|
+
attribute :kind, kind: :string, singular: true, dsl_accessor: true
|
113
|
+
attribute :account, kind: :string, singular: true
|
114
|
+
attribute :owner, kind: :role, singular: true, dsl_accessor: true
|
115
|
+
|
116
|
+
def roleid default_account = nil
|
117
|
+
raise "account is required" unless account || default_account
|
118
|
+
[ account || default_account, kind, id ].join(":")
|
119
|
+
end
|
120
|
+
|
121
|
+
def role_id; id; end
|
122
|
+
def role_kind; kind; end
|
123
|
+
|
124
|
+
def immutable_attribute_names
|
125
|
+
[]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
class Resource < Record
|
130
|
+
include ActsAsResource
|
131
|
+
include ActsAsCompoundId
|
132
|
+
|
133
|
+
attribute :kind, kind: :string, singular: true, dsl_accessor: true
|
134
|
+
|
135
|
+
def resource_kind
|
136
|
+
kind
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class User < Record
|
141
|
+
include ActsAsResource
|
142
|
+
include ActsAsRole
|
143
|
+
|
144
|
+
attribute :uidnumber, kind: :integer, singular: true, dsl_accessor: true
|
145
|
+
|
146
|
+
def id_attribute; 'login'; end
|
147
|
+
|
148
|
+
def custom_attribute_names
|
149
|
+
[ :uidnumber ]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class Group < Record
|
154
|
+
include ActsAsResource
|
155
|
+
include ActsAsRole
|
156
|
+
|
157
|
+
attribute :gidnumber, kind: :integer, singular: true, dsl_accessor: true
|
158
|
+
|
159
|
+
def custom_attribute_names
|
160
|
+
[ :gidnumber ]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class Host < Record
|
165
|
+
include ActsAsResource
|
166
|
+
include ActsAsRole
|
167
|
+
end
|
168
|
+
|
169
|
+
class Layer < Record
|
170
|
+
include ActsAsResource
|
171
|
+
include ActsAsRole
|
172
|
+
end
|
173
|
+
|
174
|
+
class Variable < Record
|
175
|
+
include ActsAsResource
|
176
|
+
|
177
|
+
attribute :kind, kind: :string, singular: true, dsl_accessor: true
|
178
|
+
attribute :mime_type, kind: :string, singular: true, dsl_accessor: true
|
179
|
+
|
180
|
+
def custom_attribute_names
|
181
|
+
[ :kind, :mime_type ]
|
182
|
+
end
|
183
|
+
|
184
|
+
def immutable_attribute_names
|
185
|
+
[ :kind, :mime_type ]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class Webservice < Record
|
190
|
+
include ActsAsResource
|
191
|
+
end
|
192
|
+
|
193
|
+
class HostFactory < Record
|
194
|
+
include ActsAsResource
|
195
|
+
|
196
|
+
attribute :role, kind: :role, dsl_accessor: true, singular: true
|
197
|
+
attribute :layer, kind: :layer, dsl_accessor: true
|
198
|
+
end
|
199
|
+
|
200
|
+
class ManagedRole < Base
|
201
|
+
include ActsAsRole
|
202
|
+
|
203
|
+
def initialize record = nil, role_name = nil
|
204
|
+
self.record = record if record
|
205
|
+
self.role_name = role_name if role_name
|
206
|
+
end
|
207
|
+
|
208
|
+
attribute :record, kind: :role, singular: true
|
209
|
+
attribute :role_name, kind: :string, singular: true
|
210
|
+
|
211
|
+
class << self
|
212
|
+
def build fullid, default_account
|
213
|
+
account, kind, id = fullid.split(':', 3)
|
214
|
+
raise "Expecting @ for kind, got #{kind}" unless kind == "@"
|
215
|
+
record_kind, record_id, role_name = id.split('/', 3)
|
216
|
+
record = Conjur::DSL2::Types.const_get(record_kind.classify).new.tap do |record|
|
217
|
+
record.id = record_id
|
218
|
+
record.account = account unless account == default_account
|
219
|
+
end
|
220
|
+
self.new record, role_name
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_s
|
225
|
+
role_name = self.id.split('/')[-1]
|
226
|
+
"'#{role_name}' on #{record}"
|
227
|
+
end
|
228
|
+
|
229
|
+
def account
|
230
|
+
record.account
|
231
|
+
end
|
232
|
+
|
233
|
+
def role_kind
|
234
|
+
"@"
|
235
|
+
end
|
236
|
+
|
237
|
+
def id
|
238
|
+
[ record.role_kind, record.id, role_name ].join('/')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Conjur::DSL2::Types
|
2
|
+
class Update < Base
|
3
|
+
attribute :record
|
4
|
+
|
5
|
+
def to_s
|
6
|
+
messages = [ "Update #{record}" ]
|
7
|
+
(record.custom_attribute_names||[]).each do |k|
|
8
|
+
messages.push " Set field '#{k}'"
|
9
|
+
end
|
10
|
+
(record.annotations||{}).each do |k,v|
|
11
|
+
messages.push " Set annotation '#{k}'"
|
12
|
+
end
|
13
|
+
messages.join("\n")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,400 @@
|
|
1
|
+
module Conjur
|
2
|
+
module DSL2
|
3
|
+
module YAML
|
4
|
+
class Handler < Psych::Handler
|
5
|
+
attr_accessor :parser, :filename, :result
|
6
|
+
|
7
|
+
# Override the logger with this method.
|
8
|
+
cattr_accessor :logger
|
9
|
+
|
10
|
+
require 'logger'
|
11
|
+
|
12
|
+
self.logger = Logger.new(STDERR)
|
13
|
+
self.logger.level = Logger::INFO
|
14
|
+
|
15
|
+
# An abstract Base handler. The handler will receive each document message within
|
16
|
+
# its particular context (sequence, mapping, etc).
|
17
|
+
#
|
18
|
+
# The handler can decide that the message is not allowed by not implementing the message.
|
19
|
+
#
|
20
|
+
class Base
|
21
|
+
attr_reader :parent
|
22
|
+
|
23
|
+
def initialize parent
|
24
|
+
@parent = parent
|
25
|
+
end
|
26
|
+
|
27
|
+
# Each handler should implement this method to return the result object (which may only be
|
28
|
+
# partially constructed). This method is used by the root handler to associate the handler
|
29
|
+
# result with an anchor (if applicable).
|
30
|
+
def result; raise "Not implemented"; end
|
31
|
+
|
32
|
+
# Handlers are organized in a stack. Each handler can find the root Handler by traversing up the stack.
|
33
|
+
def handler
|
34
|
+
parent.handler
|
35
|
+
end
|
36
|
+
|
37
|
+
# Push this handler onto the stack.
|
38
|
+
def push_handler
|
39
|
+
handler.push_handler self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Pop this handler off the stack, indicating that it's complete.
|
43
|
+
def pop_handler
|
44
|
+
handler.pop_handler
|
45
|
+
end
|
46
|
+
|
47
|
+
# An alias is encountered in the document. The value may be looked up in the root Handler +anchor+ hash.
|
48
|
+
def alias anchor
|
49
|
+
raise "Unexpected alias #{anchor}"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Start a new mapping with the specified tag.
|
53
|
+
# If the handler wants to accept the message, it should return a new handler.
|
54
|
+
def start_mapping tag
|
55
|
+
raise "Unexpected mapping"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Start a new sequence.
|
59
|
+
# If the handler wants to accept the message, it should return a new handler.
|
60
|
+
def start_sequence
|
61
|
+
raise "Unexpected sequence"
|
62
|
+
end
|
63
|
+
|
64
|
+
# End the current sequence. The handler should populate the sequence into the parent handler.
|
65
|
+
def end_sequence
|
66
|
+
raise "Unexpected end of sequence"
|
67
|
+
end
|
68
|
+
|
69
|
+
# End the current mapping. The handler should populate the mapping into the parent handler.
|
70
|
+
def end_mapping
|
71
|
+
raise "Unexpected end of mapping"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Process a scalar value. It may be a map key, a map value, or a sequence value.
|
75
|
+
# The handler should return a result from this method, so that the root Handler can
|
76
|
+
# associate it with an anchor, if any.
|
77
|
+
def scalar value, tag, quoted
|
78
|
+
raise "Unexpected scalar"
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def scalar_value value, tag, quoted, record_type
|
84
|
+
if type = type_of(tag, record_type)
|
85
|
+
type.new.tap do |record|
|
86
|
+
record.id = value
|
87
|
+
end
|
88
|
+
else
|
89
|
+
SafeYAML::Transform.to_guessed_type(value, quoted, SafeYAML::OPTIONS)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def type_of tag, record_type
|
94
|
+
if tag && tag.match(/!(.*)/)
|
95
|
+
type_name = $1.underscore.camelize
|
96
|
+
begin
|
97
|
+
Conjur::DSL2::Types.const_get(type_name)
|
98
|
+
rescue NameError
|
99
|
+
raise "Unrecognized data type '#{tag}'"
|
100
|
+
end
|
101
|
+
else
|
102
|
+
record_type
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Handles the root document, which should be a sequence.
|
108
|
+
class Root < Base
|
109
|
+
attr_reader :result, :handler
|
110
|
+
|
111
|
+
def initialize handler
|
112
|
+
super nil
|
113
|
+
|
114
|
+
@handler = handler
|
115
|
+
@result = nil
|
116
|
+
end
|
117
|
+
|
118
|
+
def handler; @handler; end
|
119
|
+
|
120
|
+
def sequence seq
|
121
|
+
raise "Already got sequence result" if @result
|
122
|
+
@result = seq
|
123
|
+
end
|
124
|
+
|
125
|
+
# The document root is expected to start with a sequence.
|
126
|
+
# A Sequence handler is constructed with no implicit type. This
|
127
|
+
# sub-handler handles the message.
|
128
|
+
def start_sequence
|
129
|
+
Sequence.new(self, nil).tap do |h|
|
130
|
+
h.push_handler
|
131
|
+
end.result
|
132
|
+
end
|
133
|
+
|
134
|
+
# Finish the sequence, and the document.
|
135
|
+
def end_sequence
|
136
|
+
pop_handler
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Handles a sequence. The sequence has:
|
141
|
+
# +record_type+ default record type, inferred from the field name on the parent record.
|
142
|
+
# +args+ the start_sequence arguments.
|
143
|
+
class Sequence < Base
|
144
|
+
attr_reader :record_type
|
145
|
+
|
146
|
+
def initialize parent, record_type
|
147
|
+
super parent
|
148
|
+
|
149
|
+
@record_type = record_type
|
150
|
+
@list = []
|
151
|
+
end
|
152
|
+
|
153
|
+
def result; @list; end
|
154
|
+
|
155
|
+
# Adds a mapping to the sequence.
|
156
|
+
def mapping value
|
157
|
+
@list.push value
|
158
|
+
end
|
159
|
+
|
160
|
+
# Adds a sequence to the sequence.
|
161
|
+
def sequence value
|
162
|
+
@list.push value
|
163
|
+
end
|
164
|
+
|
165
|
+
# When the sequence receives an alias, the alias should be mapped to the previously stored
|
166
|
+
# value and added to the result list.
|
167
|
+
def alias anchor
|
168
|
+
@list.push handler.anchor(anchor)
|
169
|
+
end
|
170
|
+
|
171
|
+
# When the sequence contains a mapping, a new record should be created corresponding to either:
|
172
|
+
#
|
173
|
+
# * The explicit stated type (tag) of the mapping
|
174
|
+
# * The implicit field type of the sequence
|
175
|
+
#
|
176
|
+
# If neither of these is available, it's an error.
|
177
|
+
def start_mapping tag
|
178
|
+
if type = type_of(tag, record_type)
|
179
|
+
Mapping.new(self, type).tap do |h|
|
180
|
+
h.push_handler
|
181
|
+
end.result
|
182
|
+
else
|
183
|
+
raise "No type given or inferred for sequence entry"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Process a sequence within a sequence.
|
188
|
+
def start_sequence
|
189
|
+
Sequence.new(self, record_type).tap do |h|
|
190
|
+
h.push_handler
|
191
|
+
end.result
|
192
|
+
end
|
193
|
+
|
194
|
+
# When the sequence contains a scalar, the value should be appended to the result.
|
195
|
+
def scalar value, tag, quoted
|
196
|
+
scalar_value(value, tag, quoted, record_type).tap do |value|
|
197
|
+
@list.push value
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def end_sequence
|
202
|
+
parent.sequence @list
|
203
|
+
pop_handler
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Handles a mapping, each of which will be parsed into a structured record.
|
208
|
+
class Mapping < Base
|
209
|
+
attr_reader :type
|
210
|
+
|
211
|
+
def initialize parent, type
|
212
|
+
super parent
|
213
|
+
|
214
|
+
@record = type.new
|
215
|
+
end
|
216
|
+
|
217
|
+
def result; @record; end
|
218
|
+
|
219
|
+
def map_entry key, value
|
220
|
+
if @record.respond_to?(:[]=)
|
221
|
+
@record.send(:[]=, key, value)
|
222
|
+
else
|
223
|
+
begin
|
224
|
+
@record.send("#{key}=", value)
|
225
|
+
rescue NoMethodError
|
226
|
+
raise "No such attribute '#{key}' on type #{@record.class.short_name}"
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
# Begins a mapping with the anchor value as the key.
|
232
|
+
def alias anchor
|
233
|
+
key = handler.anchor(anchor)
|
234
|
+
MapEntry.new(self, @record, key).tap do |h|
|
235
|
+
h.push_handler
|
236
|
+
end.result
|
237
|
+
end
|
238
|
+
|
239
|
+
# Begins a new map entry.
|
240
|
+
def scalar value, tag, quoted
|
241
|
+
value = scalar_value(value, tag, quoted, type)
|
242
|
+
MapEntry.new(self, @record, value).tap do |h|
|
243
|
+
h.push_handler
|
244
|
+
end.result
|
245
|
+
end
|
246
|
+
|
247
|
+
def end_mapping
|
248
|
+
parent.mapping @record
|
249
|
+
pop_handler
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
# Processes a map entry. At this point, the parent record and the map key are known.
|
254
|
+
class MapEntry < Base
|
255
|
+
attr_reader :record, :key
|
256
|
+
|
257
|
+
def initialize parent, record, key
|
258
|
+
super parent
|
259
|
+
|
260
|
+
@record = record
|
261
|
+
@key = key
|
262
|
+
end
|
263
|
+
|
264
|
+
def result; nil; end
|
265
|
+
|
266
|
+
def sequence value
|
267
|
+
value value
|
268
|
+
end
|
269
|
+
|
270
|
+
def mapping value
|
271
|
+
value value
|
272
|
+
end
|
273
|
+
|
274
|
+
def value value
|
275
|
+
parent.map_entry @key, value
|
276
|
+
pop_handler
|
277
|
+
end
|
278
|
+
|
279
|
+
# Interpret the alias as the map value and populate in the parent.
|
280
|
+
def alias anchor
|
281
|
+
value handler.anchor(anchor)
|
282
|
+
end
|
283
|
+
|
284
|
+
# Start a mapping as a map value.
|
285
|
+
def start_mapping tag
|
286
|
+
if type = type_of(tag, yaml_field_type(key))
|
287
|
+
Mapping.new(self, type).tap do |h|
|
288
|
+
h.push_handler
|
289
|
+
end.result
|
290
|
+
else
|
291
|
+
# We got a mapping on a simple type
|
292
|
+
raise "Attribute '#{key}' can't be a mapping"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Start a sequence as a map value.
|
297
|
+
def start_sequence
|
298
|
+
Sequence.new(self, yaml_field_type(key)).tap do |h|
|
299
|
+
h.push_handler
|
300
|
+
end.result
|
301
|
+
end
|
302
|
+
|
303
|
+
def scalar value, tag, quoted
|
304
|
+
value scalar_value(value, tag, quoted, yaml_field_type(key))
|
305
|
+
end
|
306
|
+
|
307
|
+
protected
|
308
|
+
|
309
|
+
def yaml_field_type key
|
310
|
+
record.class.respond_to?(:yaml_field_type) ? record.class.yaml_field_type(key) : nil
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def initialize
|
315
|
+
@root = Root.new self
|
316
|
+
@handlers = [ @root ]
|
317
|
+
@anchors = {}
|
318
|
+
@filename = "<no-filename>"
|
319
|
+
end
|
320
|
+
|
321
|
+
def push_handler handler
|
322
|
+
log {"#{indent}pushing handler #{handler.class}"}
|
323
|
+
@handlers.push handler
|
324
|
+
end
|
325
|
+
|
326
|
+
def pop_handler
|
327
|
+
@handlers.pop
|
328
|
+
log {"#{indent}popped to handler #{handler.class}"}
|
329
|
+
end
|
330
|
+
|
331
|
+
# Get or set an anchor. Invoke with just the anchor name to get the value.
|
332
|
+
# Invoke with the anchor name and value to set the value.
|
333
|
+
def anchor *args
|
334
|
+
key, value, _ = args
|
335
|
+
if _
|
336
|
+
raise ArgumentError, "Expecting 1 or 2 arguments, got #{args.length}"
|
337
|
+
elsif key && value
|
338
|
+
raise "Duplicate anchor #{key}" if @anchors[key]
|
339
|
+
@anchors[key] = value
|
340
|
+
elsif key
|
341
|
+
@anchors[key]
|
342
|
+
else
|
343
|
+
nil
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def result; @root.result; end
|
348
|
+
|
349
|
+
def handler; @handlers.last; end
|
350
|
+
|
351
|
+
def alias key
|
352
|
+
log {"#{indent}anchor '#{key}'=#{anchor(key)}"}
|
353
|
+
handler.alias key
|
354
|
+
end
|
355
|
+
|
356
|
+
def start_mapping *args
|
357
|
+
log {"#{indent}start mapping #{args}"}
|
358
|
+
anchor, tag, _ = args
|
359
|
+
value = handler.start_mapping tag
|
360
|
+
anchor anchor, value
|
361
|
+
end
|
362
|
+
|
363
|
+
def start_sequence *args
|
364
|
+
log {"#{indent}start sequence : #{args}"}
|
365
|
+
anchor, _ = args
|
366
|
+
value = handler.start_sequence
|
367
|
+
anchor anchor, value
|
368
|
+
end
|
369
|
+
|
370
|
+
def end_sequence
|
371
|
+
log {"#{indent}end sequence"}
|
372
|
+
handler.end_sequence
|
373
|
+
end
|
374
|
+
|
375
|
+
def end_mapping
|
376
|
+
log {"#{indent}end mapping"}
|
377
|
+
handler.end_mapping
|
378
|
+
end
|
379
|
+
|
380
|
+
def scalar *args
|
381
|
+
# value, anchor, tag, plain, quoted, style
|
382
|
+
value, anchor, tag, _, quoted = args
|
383
|
+
log {"#{indent}got scalar #{tag ? tag + '=' : ''}#{value}#{anchor ? '#' + anchor : ''}"}
|
384
|
+
value = handler.scalar value, tag, quoted
|
385
|
+
anchor anchor, value
|
386
|
+
end
|
387
|
+
|
388
|
+
def log &block
|
389
|
+
logger.debug('conjur/dsl2/handler') {
|
390
|
+
yield
|
391
|
+
}
|
392
|
+
end
|
393
|
+
|
394
|
+
def indent
|
395
|
+
" " * [ @handlers.length - 1, 0 ].max
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|