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,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
|