cfn-model 0.4.28 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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