cfn-model 0.4.28 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df1ac14db4c825a752953a999fca09e56eaaa3e7141146bea1892cfe0c1f350c
4
- data.tar.gz: 010c17ccd4d19b1999768d8b41b71dd98f6cca02713cf3065ac6cf208ee4d4f2
3
+ metadata.gz: 9aef1495499472493a59d8d4a674eb275bad575fccf3b7eaa6d91db4308d3914
4
+ data.tar.gz: cd9340c44f684f0e6eeedbbd7f7e2a84826b79bede5f09c5930f3b7bdca2f3f3
5
5
  SHA512:
6
- metadata.gz: 2530d80cc408f921c69ec5757c6b4c73a064a1d6e7c980cce9dd3a0441bdd501e82685ceff915c756ea7a4cd4fd52f712ddb7cd63a190686abc9b8613b63de05
7
- data.tar.gz: 8f053b02001d51fb7f4130e6b77d0e9cc7d3c36f35d8e3b9c3d55b6d9cc610a9ab02cdb8604c4385556819aa4e7581f2bf23cd912b910220b0f7c7bfd13d8dd6
6
+ metadata.gz: 33b02918cbb23f06c2c74b05bf7897f17d78896b74bfcdf80fd8be619cb69d7385a161809ddbb7a8ad632e4f5af618e2508712b7615ae6ec72980180823a2338
7
+ data.tar.gz: 3cfb410027085088f737643e4197ad7e1238ebff994bfac19b62738ff53d0a609583cfe1919c4ec89ff1c9e968276fc5727c0bf07f90ab3a17ce4d898da79001
@@ -3,7 +3,7 @@
3
3
  require_relative 'references'
4
4
 
5
5
  class CfnModel
6
- attr_reader :resources, :parameters, :line_numbers, :conditions, :globals
6
+ attr_reader :resources, :parameters, :line_numbers, :conditions, :globals, :mappings
7
7
 
8
8
  ##
9
9
  # if you really want it, here it is - the raw Hash from YAML.load. you'll have to mess with structural nits of
@@ -16,6 +16,7 @@ class CfnModel
16
16
  @resources = {}
17
17
  @conditions = {}
18
18
  @globals = {}
19
+ @mappings = {}
19
20
  @raw_model = nil
20
21
  @line_numbers = {}
21
22
  end
@@ -38,6 +39,9 @@ class CfnModel
38
39
  @resources.each do |k, v|
39
40
  new_cfn_model.resources[k] = v
40
41
  end
42
+ @mappings.each do |k, v|
43
+ new_cfn_model.mappings[k] = v
44
+ end
41
45
  new_cfn_model.raw_model = @raw_model.dup unless @raw_model.nil?
42
46
  new_cfn_model
43
47
  end
@@ -9,25 +9,58 @@ require 'cfn-model/parser/parser_error'
9
9
  # references yet... in the meantime pile things up here and hope a pattern becomes
10
10
  # clear
11
11
  module References
12
+ def self.unsupported_passthru?(value)
13
+ value.has_key?('Fn::GetAtt') || value.has_key?('Fn::ImportValue') || value.has_key?('Fn::Transform') || value.has_key?('Fn::Cidr')
14
+ end
15
+
12
16
  def self.resolve_value(cfn_model, value)
13
17
  if value.is_a? Hash
14
18
  if value.has_key?('Ref')
15
- ref_id = value['Ref']
16
- if ref_id.is_a? String
17
- if cfn_model.parameters.has_key?(ref_id)
18
- return value if cfn_model.parameters[ref_id].synthesized_value.nil?
19
- return cfn_model.parameters[ref_id].synthesized_value
20
- else
21
- return value
22
- end
23
- else
24
- return value
25
- end
19
+ resolve_reference(cfn_model, value)
20
+ elsif value.has_key?('Fn::FindInMap')
21
+ resolve_map(cfn_model, value)
22
+ elsif value.has_key?('Fn::If')
23
+ resolve_if(cfn_model, value)
24
+ elsif value.has_key?('Fn::Sub')
25
+ resolve_sub(cfn_model, value)
26
+ elsif value.has_key?('Fn::GetAZs')
27
+ resolve_getazs(cfn_model, value)
28
+ elsif value.has_key?('Fn::Split')
29
+ resolve_split(cfn_model, value)
30
+ elsif value.has_key?('Fn::Join')
31
+ resolve_join(cfn_model, value)
32
+ elsif value.has_key?('Fn::Base64')
33
+ resolve_base64(cfn_model, value)
34
+ elsif value.has_key?('Fn::Select')
35
+ resolve_select(cfn_model, value)
36
+ elsif unsupported_passthru?(value)
37
+ value
38
+ else # another mapping
39
+ value.map do |k,v|
40
+ [k, resolve_value(cfn_model, v)]
41
+ end.to_h
42
+ end
43
+ elsif value.is_a? Array
44
+ value.map { |item| resolve_value(cfn_model, item) }
45
+ else
46
+ value
47
+ end
48
+ end
49
+
50
+ ##
51
+ # For a !Ref to another resource.... just returns the !REf
52
+ # For a !Ref to a Parameter, then try to synthesize the value
53
+ def self.resolve_reference(cfn_model, value)
54
+ ref_id = value['Ref']
55
+ if ref_id.is_a? String
56
+ if cfn_model.parameters.has_key?(ref_id)
57
+ return value if cfn_model.parameters[ref_id].synthesized_value.nil?
58
+ return cfn_model.parameters[ref_id].synthesized_value
26
59
  else
27
60
  return value
28
61
  end
29
62
  else
30
- return value
63
+ value
31
64
  end
32
65
  end
33
66
 
@@ -57,8 +90,146 @@ module References
57
90
  resolve_resource_id group_id, 'GroupId'
58
91
  end
59
92
 
93
+ ##
94
+ # Try to compute the FindInMap against a real Mapping
95
+ #
96
+ # If anything doesn't match up - either a syntax error,
97
+ # a missing Mapping, or some other kind Cfn evaluation
98
+ # we don't understand, just return the call to FindInMap
99
+ def self.resolve_map(cfn_model, find_in_map)
100
+ map_name = find_in_map['Fn::FindInMap'][0]
101
+ top_level_key = find_in_map['Fn::FindInMap'][1]
102
+ second_level_key = find_in_map['Fn::FindInMap'][2]
103
+
104
+ map = cfn_model.mappings[map_name]
105
+
106
+ return find_in_map if map.nil?
107
+
108
+ top_level_resolved = resolve_value(cfn_model, top_level_key)
109
+
110
+ return find_in_map if !map.has_key?(top_level_resolved)
111
+
112
+ top_level = map[top_level_resolved]
113
+ second_level = top_level[resolve_value(cfn_model, second_level_key)]
114
+
115
+ return find_in_map if second_level.nil?
116
+
117
+ second_level
118
+ end
119
+
60
120
  private
61
121
 
122
+ def self.resolve_sub(cfn_model, expression)
123
+ if expression['Fn::Sub'].is_a? String
124
+ resolve_shorthand_sub(cfn_model, expression)
125
+ elsif expression['Fn::Sub'].is_a? Array
126
+ resolve_longform_sub(cfn_model, expression)
127
+ else
128
+ expression
129
+ end
130
+ end
131
+
132
+ def self.resolve_select(cfn_model, reference)
133
+ index = reference['Fn::Select'][0]
134
+ collection = References.resolve_value(cfn_model, reference['Fn::Select'][1])
135
+ if collection.is_a? Array
136
+ collection[index]
137
+ else
138
+ reference
139
+ end
140
+ end
141
+
142
+ def self.resolve_base64(cfn_model, reference)
143
+ References.resolve_value(cfn_model, reference['Fn::Base64'])
144
+ end
145
+
146
+ def self.resolve_join(cfn_model, reference)
147
+ delimiter = reference['Fn::Join'][0]
148
+ items = References.resolve_value(cfn_model, reference['Fn::Join'][1])
149
+ return reference unless items.is_a?(Array)
150
+ items.join(delimiter)
151
+ end
152
+
153
+ def self.resolve_split(cfn_model, reference)
154
+ delimiter = reference['Fn::Split'][0]
155
+ target_string = References.resolve_value(cfn_model, reference['Fn::Split'][1])
156
+ return reference unless target_string.is_a?(String)
157
+ target_string.split(delimiter)
158
+ end
159
+
160
+ def self.resolve_getazs(cfn_model, reference)
161
+ number_azs = References.resolve_value(cfn_model, { 'Ref' => 'AWS::NumberAZs' })
162
+ region = reference['Fn::GetAZs']
163
+ if region == '' || region == { 'Ref' => 'AWS::Region' }
164
+ region = References.resolve_value(cfn_model, { 'Ref' => 'AWS::Region' })
165
+ end
166
+ (('a'.ord)..('a'.ord+number_azs)).map do |az_number|
167
+ "#{region}#{az_number.chr}"
168
+ end
169
+ end
170
+
171
+ def self.strip_cfn_interpolation(reference)
172
+ reference[2..-2]
173
+ end
174
+
175
+ def self.references_in_sub(string_value)
176
+ # ignore ${!foo} as cfn interprets that as the literal ${foo}
177
+ references = string_value.scan /\${[^!].*?}/
178
+ references.map { |reference| strip_cfn_interpolation(reference) }
179
+ end
180
+
181
+ def self.resolvable_reference?(cfn_model, reference)
182
+ resolved_value = References.resolve_value(cfn_model, {'Ref'=>reference})
183
+ resolved_value != {'Ref'=>reference}
184
+ end
185
+
186
+ def self.resolve_shorthand_sub(cfn_model, expression)
187
+ string_value = expression['Fn::Sub']
188
+ subbed_string_value = string_value
189
+ has_unresolved_references = false
190
+ references_in_sub(string_value).each do |reference|
191
+ if resolvable_reference?(cfn_model, reference)
192
+ subbed_string_value = subbed_string_value.gsub(
193
+ "${#{reference}}",
194
+ References.resolve_value(cfn_model, {'Ref'=>reference})
195
+ )
196
+ end
197
+ end
198
+ subbed_string_value
199
+ end
200
+
201
+ def self.resolve_longform_sub(cfn_model, expression)
202
+ array_value = expression['Fn::Sub']
203
+ subbed_string_value = array_value[0]
204
+ substitution_mapping = array_value[1]
205
+ references_in_sub(subbed_string_value).each do |reference|
206
+ if substitution_mapping.has_key? reference
207
+ if References.resolve_value(cfn_model, substitution_mapping[reference]).is_a?(String)
208
+ subbed_string_value = subbed_string_value.gsub(
209
+ "${#{reference}}",
210
+ References.resolve_value(cfn_model, substitution_mapping[reference])
211
+ )
212
+ end
213
+ elsif resolvable_reference?(cfn_model, reference)
214
+ subbed_string_value = subbed_string_value.gsub(
215
+ "${#{reference}}",
216
+ References.resolve_value(cfn_model, {'Ref'=>reference})
217
+ )
218
+ end
219
+ end
220
+ subbed_string_value
221
+ end
222
+
223
+ def self.resolve_if(cfn_model, expression)
224
+ if_expression = expression['Fn::If']
225
+ condition_name = if_expression[0]
226
+ if cfn_model.conditions[condition_name]
227
+ resolve_value(cfn_model, if_expression[1])
228
+ else
229
+ resolve_value(cfn_model, if_expression[2])
230
+ end
231
+ end
232
+
62
233
  def self.logical_resource_id_from_get_att(attribute_spec, attr_to_retrieve=nil)
63
234
  if attribute_spec.is_a? Array
64
235
  if !attr_to_retrieve || attribute_spec[1] == attr_to_retrieve
@@ -44,6 +44,9 @@ class CfnParser
44
44
 
45
45
  apply_parameter_values(cfn_model, parameter_values_json)
46
46
 
47
+ # pass 2: tie together separate resources only where necessary to make life easier for rule logic
48
+ post_process_resource_model_elements cfn_model
49
+
47
50
  cfn_model
48
51
  end
49
52
 
@@ -76,6 +79,8 @@ class CfnParser
76
79
 
77
80
  process_conditions cfn_hash, cfn_model, condition_values_json
78
81
 
82
+ process_mappings cfn_hash, cfn_model
83
+
79
84
  # pass 1: wire properties into ModelElement objects
80
85
  if with_line_numbers
81
86
  transform_hash_into_model_elements_with_numbers cfn_hash, cfn_model
@@ -85,14 +90,21 @@ class CfnParser
85
90
  transform_hash_into_parameters cfn_hash, cfn_model
86
91
  transform_hash_into_globals cfn_hash, cfn_model
87
92
 
88
- # pass 2: tie together separate resources only where necessary to make life easier for rule logic
89
- post_process_resource_model_elements cfn_model
93
+
90
94
 
91
95
  cfn_model
92
96
  end
93
97
 
94
98
  private
95
99
 
100
+ def process_mappings(cfn_hash, cfn_model)
101
+ if cfn_hash.key?('Mappings')
102
+ cfn_hash['Mappings'].each do |mapping_key, mapping_value|
103
+ cfn_model.mappings[mapping_key] = mapping_value
104
+ end
105
+ end
106
+ end
107
+
96
108
  def process_conditions(cfn_hash, cfn_model, condition_values_json)
97
109
  if cfn_hash.key?('Conditions')
98
110
  if condition_values_json.nil?
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'cfn-model/model/iam_role'
4
4
  require 'cfn-model/model/policy'
5
+ require 'cfn-model/model/references'
5
6
  require_relative 'policy_document_parser'
6
7
 
7
8
  class IamGroupParser
@@ -12,8 +13,8 @@ class IamGroupParser
12
13
  next unless policy.has_key? 'PolicyName'
13
14
 
14
15
  new_policy = Policy.new
15
- new_policy.policy_name = policy['PolicyName']
16
- new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
16
+ new_policy.policy_name = References.resolve_value(cfn_model, policy['PolicyName'])
17
+ new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, policy['PolicyDocument'])
17
18
  new_policy
18
19
  end.reject { |policy| policy.nil? }
19
20
  iam_group
@@ -2,20 +2,21 @@
2
2
 
3
3
  require 'cfn-model/model/iam_role'
4
4
  require 'cfn-model/model/policy'
5
+ require 'cfn-model/model/references'
5
6
  require_relative 'policy_document_parser'
6
7
 
7
8
  class IamRoleParser
8
9
  def parse(cfn_model:, resource:)
9
10
  iam_role = resource
10
11
 
11
- iam_role.assume_role_policy_document = PolicyDocumentParser.new.parse(iam_role.assumeRolePolicyDocument)
12
+ iam_role.assume_role_policy_document = PolicyDocumentParser.new.parse(cfn_model, iam_role.assumeRolePolicyDocument)
12
13
 
13
14
  iam_role.policy_objects = iam_role.policies.map do |policy|
14
15
  next unless policy.has_key? 'PolicyName'
15
16
 
16
17
  new_policy = Policy.new
17
- new_policy.policy_name = policy['PolicyName']
18
- new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
18
+ new_policy.policy_name = References.resolve_value(cfn_model, policy['PolicyName'])
19
+ new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, policy['PolicyDocument'])
19
20
  new_policy
20
21
  end.reject { |policy| policy.nil? }
21
22
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'cfn-model/model/policy_document'
4
4
  require 'cfn-model/model/policy'
5
+ require 'cfn-model/model/references'
5
6
  require_relative 'policy_document_parser'
6
7
 
7
8
  class IamUserParser
@@ -12,8 +13,8 @@ class IamUserParser
12
13
  next unless policy.has_key? 'PolicyName'
13
14
 
14
15
  new_policy = Policy.new
15
- new_policy.policy_name = policy['PolicyName']
16
- new_policy.policy_document = PolicyDocumentParser.new.parse(policy['PolicyDocument'])
16
+ new_policy.policy_name = References.resolve_value(cfn_model, policy['PolicyName'])
17
+ new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, policy['PolicyDocument'])
17
18
  new_policy
18
19
  end.reject { |policy| policy.nil? }
19
20
 
@@ -22,8 +23,8 @@ class IamUserParser
22
23
  user_to_group_additions = cfn_model.resources_by_type 'AWS::IAM::UserToGroupAddition'
23
24
  user_to_group_additions.each do |user_to_group_addition|
24
25
 
25
- if user_to_group_addition_has_username(user_to_group_addition.users,iam_user)
26
- iam_user.group_names << user_to_group_addition.groupName
26
+ if user_to_group_addition_has_username(user_to_group_addition.users, iam_user)
27
+ iam_user.group_names << References.resolve_value(cfn_model, user_to_group_addition.groupName)
27
28
 
28
29
  # we need to figure out the story on resolving Refs i think for this to be real
29
30
  end
@@ -9,7 +9,7 @@ class KmsKeyParser
9
9
  kms_key = resource
10
10
 
11
11
  new_policy = Policy.new
12
- new_policy.policy_document = PolicyDocumentParser.new.parse(kms_key.keyPolicy)
12
+ new_policy.policy_document = PolicyDocumentParser.new.parse(cfn_model, kms_key.keyPolicy)
13
13
  kms_key.key_policy = new_policy
14
14
 
15
15
  kms_key
@@ -33,6 +33,33 @@ class ParameterSubstitution
33
33
  end
34
34
  end
35
35
 
36
+ def apply_pseudo_parameter_values(cfn_model, parameter_values)
37
+ # leave out 'AWS::NoValue'? not sure - we explicitly check it in some places...
38
+ # might make sense to substitute here?
39
+ pseudo_function_defaults = {
40
+ 'AWS::URLSuffix' => 'amazonaws.com',
41
+ 'AWS::Partition' => 'aws',
42
+ 'AWS::NotificationARNs' => '',
43
+ 'AWS::AccountId' => '111111111111',
44
+ 'AWS::Region' => 'us-east-1',
45
+ 'AWS::StackId' => 'arn:aws:cloudformation:us-east-1:111111111111:stack/stackname/51af3dc0-da77-11e4-872e-1234567db123',
46
+ 'AWS::StackName' => 'stackname',
47
+ 'AWS::NumberAZs' => 2
48
+ }
49
+ pseudo_function_defaults.each do |function_name, default_value|
50
+ parameter = Parameter.new
51
+ parameter.id = function_name
52
+ parameter.type = 'String'
53
+ cfn_model.parameters[function_name] = parameter
54
+
55
+ if parameter_values[PARAMETERS].has_key?(function_name)
56
+ parameter.synthesized_value = parameter_values[PARAMETERS][function_name]
57
+ else
58
+ parameter.synthesized_value = default_value
59
+ end
60
+ end
61
+ end
62
+
36
63
  def apply_parameter_values_impl(cfn_model, parameter_values)
37
64
  parameter_values[PARAMETERS].each do |parameter_name, parameter_value|
38
65
  if cfn_model.parameters.has_key?(parameter_name)
@@ -50,6 +77,7 @@ class ParameterSubstitution
50
77
  parameter.synthesized_value = parameter.default.to_s
51
78
  end
52
79
  end
80
+ apply_pseudo_parameter_values(cfn_model, parameter_values)
53
81
  end
54
82
 
55
83
  def is_aws_format?(parameter_values)
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cfn-model/model/iam_policy'
4
+ require 'cfn-model/model/references'
5
+
4
6
  require 'cfn-model/model/policy_document'
5
7
 
6
8
  class PolicyDocumentParser
7
- def parse(raw_policy_document)
9
+ def parse(cfn_model, raw_policy_document)
8
10
  policy_document = PolicyDocument.new
9
11
 
10
- policy_document.version = raw_policy_document['Version']
12
+ policy_document.version = References.resolve_value(cfn_model, raw_policy_document['Version'])
11
13
 
12
14
  policy_document.statements = streamline_array(raw_policy_document['Statement']) do |statement|
13
- parse_statement statement
15
+ parse_statement cfn_model, statement
14
16
  end
15
17
 
16
18
  policy_document
@@ -18,17 +20,17 @@ class PolicyDocumentParser
18
20
 
19
21
  private
20
22
 
21
- def parse_statement(raw_statement)
23
+ def parse_statement(cfn_model, raw_statement)
22
24
  statement = Statement.new
23
- statement.effect = raw_statement['Effect']
24
- statement.sid = raw_statement['Sid']
25
- statement.condition = raw_statement['Condition']
26
- statement.actions = streamline_array(raw_statement['Action'])
27
- statement.not_actions = streamline_array(raw_statement['NotAction'])
28
- statement.resources = streamline_array(raw_statement['Resource'])
29
- statement.not_resources = streamline_array(raw_statement['NotResource'])
30
- statement.principal = raw_statement['Principal']
31
- statement.not_principal = raw_statement['NotPrincipal']
25
+ statement.effect = References.resolve_value(cfn_model, raw_statement['Effect'])
26
+ statement.sid = References.resolve_value(cfn_model, raw_statement['Sid'])
27
+ statement.condition = References.resolve_value(cfn_model, raw_statement['Condition'])
28
+ statement.actions = References.resolve_value(cfn_model, streamline_array(raw_statement['Action']))
29
+ statement.not_actions = References.resolve_value(cfn_model, streamline_array(raw_statement['NotAction']))
30
+ statement.resources = References.resolve_value(cfn_model, streamline_array(raw_statement['Resource']))
31
+ statement.not_resources = References.resolve_value(cfn_model, streamline_array(raw_statement['NotResource']))
32
+ statement.principal = References.resolve_value(cfn_model, raw_statement['Principal'])
33
+ statement.not_principal = References.resolve_value(cfn_model, raw_statement['NotPrincipal'])
32
34
  statement
33
35
  end
34
36
 
@@ -38,7 +38,7 @@ class SecurityGroupParser
38
38
  ingress_object = AWS::EC2::SecurityGroupIngress.new cfn_model
39
39
  ingress.each do |k, v|
40
40
  silently_fail do
41
- ingress_object.send("#{initialLower(k)}=", v)
41
+ ingress_object.send("#{initialLower(k)}=", References.resolve_value(cfn_model, v))
42
42
  mapped_at_least_one_attribute = true
43
43
  end
44
44
  end
@@ -59,7 +59,7 @@ class SecurityGroupParser
59
59
  egress.each do |k, v|
60
60
  next if k.match /::/
61
61
  silently_fail do
62
- egress_object.send("#{initialLower(k)}=", v)
62
+ egress_object.send("#{initialLower(k)}=", References.resolve_value(cfn_model, v))
63
63
  mapped_at_least_one_attribute = true
64
64
  end
65
65
 
@@ -6,7 +6,7 @@ require_relative 'policy_document_parser'
6
6
 
7
7
  class WithPolicyDocumentParser
8
8
  def parse(cfn_model:, resource:)
9
- resource.policy_document = PolicyDocumentParser.new.parse(resource.policyDocument)
9
+ resource.policy_document = PolicyDocumentParser.new.parse(cfn_model, resource.policyDocument)
10
10
  resource
11
11
  end
12
12
  end
@@ -112,8 +112,14 @@ class CfnModel
112
112
  resource_name,
113
113
  with_line_numbers)
114
114
 
115
- cfn_hash['Resources'][resource_name] = lambda_function lambda_fn_params
116
-
115
+ cfn_hash['Resources'][resource_name] = lambda_function(
116
+ handler: lambda_fn_params[:handler],
117
+ code_bucket: lambda_fn_params[:code_bucket],
118
+ code_key: lambda_fn_params[:code_key],
119
+ role: lambda_fn_params[:role],
120
+ runtime: lambda_fn_params[:runtime],
121
+ with_line_numbers: lambda_fn_params[:with_line_numbers]
122
+ )
117
123
  unless serverless_function['Properties']['Role']
118
124
  cfn_hash['Resources'][resource_name + 'Role'] = function_role(serverless_function,
119
125
  resource_name,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.28
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-08 00:00:00.000000000 Z
11
+ date: 2020-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
167
  requirements: []
168
- rubygems_version: 3.1.2
168
+ rubygems_version: 3.1.3
169
169
  signing_key:
170
170
  specification_version: 4
171
171
  summary: cfn-model