cps-property-generator 0.2.16 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,27 +1,32 @@
1
1
  require_relative '../helpers/helpers'
2
+
2
3
  module PropertyGenerator
3
4
  require 'yaml'
5
+ require 'pathname'
4
6
  class GlobalsLinter
7
+ TESTS = [
8
+ 'globals_load_as_hashes',
9
+ 'globals_are_defined_for_valid_environemnts'
10
+ ].freeze
5
11
 
6
- def initialize(path, configs)
12
+ def initialize(path, configs, ignored_tests)
7
13
  @configs = configs
8
14
  @globals = {}
15
+ @ignored_tests = ignored_tests
9
16
  valid_paths = PropertyGenerator.valid_paths(path)
10
17
  valid_paths.each do |file_path|
11
- @globals[file_path] = YAML.load_file(file_path)
18
+ @globals[file_path] = YAML.load_file(file_path)
12
19
  end
13
20
  end
14
21
 
15
22
  def run_globals_tests
16
- tests = ['globals_load_as_hashes',
17
- 'globals_are_defined_for_valid_environemnts',
18
- ]
19
- results = PropertyGenerator.test_runner(self, tests)
20
- results
23
+ tests = TESTS - @ignored_tests
24
+
25
+ PropertyGenerator.test_runner(self, tests)
21
26
  end
22
27
 
23
28
  def globals_load_as_hashes
24
- status = {status: 'pass', error: ''}
29
+ status = { status: 'pass', error: '' }
25
30
  non_hash_globals = []
26
31
  @globals.each do |path, loaded|
27
32
  if loaded.class != Hash
@@ -36,13 +41,13 @@ module PropertyGenerator
36
41
  end
37
42
 
38
43
  def globals_have_no_hashes_as_values
39
- status = {status: 'pass', error: ''}
44
+ status = { status: 'pass', error: '' }
40
45
  globals_with_hash_props = []
41
46
  @globals.each do |path, loaded|
42
47
  if loaded.class == Hash
43
48
  loaded.each do |key, value|
44
49
  if value.class == Hash
45
- globals_with_hash_props << {path => key}
50
+ globals_with_hash_props << { path => key }
46
51
  end
47
52
  end
48
53
  end
@@ -55,30 +60,30 @@ module PropertyGenerator
55
60
  end
56
61
 
57
62
  def globals_are_defined_for_valid_environemnts
58
- status = {status: 'pass', error: ''}
63
+ status = { status: 'pass', error: '' }
59
64
  ignore_list = ['globals.yml']
60
- globals_with_invalid_environments = []
61
- accounts = []
62
- if @configs['accounts'] != nil
63
- @configs['accounts'].each do |account|
64
- accounts << account.to_s
65
- end
66
- @globals.each do |path, loaded|
67
- unless @configs['environments'].include?((path.split('/')[(path.split('/')).length - 1]).split('.')[0]) || accounts.include?((path.split('/')[(path.split('/')).length - 1]).split('.')[0])
68
- globals_with_invalid_environments << path unless ignore_list.include?(path.split('/')[(path.split('/')).length - 1])
69
- end
70
- end
71
- if globals_with_invalid_environments != []
72
- status[:status] = 'warn'
73
- status[:error] = "Files #{globals_with_invalid_environments} do not have names matching a declared environment."
74
- end
75
- else
65
+
66
+ if @configs['accounts'].nil?
76
67
  status[:status] = 'warn'
77
- status[:error] = "Accounts list in config file is missing."
68
+ status[:error] = 'Accounts list in config file is missing.'
69
+ return status
70
+ end
71
+
72
+ accounts = @configs['accounts'].map(&:to_s)
73
+ globals_with_invalid_environments = @globals.keys.select do |path|
74
+ p = Pathname.new(path)
75
+ filename = p.basename(File.extname(path)).to_s
76
+ next if ignore_list.include?(p.basename.to_s)
77
+
78
+ !(@configs['environments'].include?(filename) || accounts.include?(filename))
78
79
  end
79
- status
80
- end
81
80
 
81
+ unless globals_with_invalid_environments.empty?
82
+ status[:status] = 'warn'
83
+ status[:error] = "Files #{globals_with_invalid_environments} do not have names matching a declared environment."
84
+ end
82
85
 
86
+ status
87
+ end
83
88
  end
84
89
  end
data/lib/linter/linter.rb CHANGED
@@ -1,17 +1,32 @@
1
1
  module PropertyGenerator
2
- require_relative 'config_linter.rb'
3
- require_relative 'globals_linter.rb'
4
- require_relative 'services_linter.rb'
5
- require_relative 'report.rb'
2
+ require_relative 'config_linter'
3
+ require_relative 'globals_linter'
4
+ require_relative 'services_linter'
5
+ require_relative 'report'
6
6
  class Linter
7
+ attr_accessor :ignored_tests, :services_linter, :globals_linter, :config_linter, :report
7
8
 
8
9
  def initialize(path)
9
- ignore_list = ['README.md']
10
+ ignore_list = %w[README.md .cpsignore]
10
11
  invalid_paths = PropertyGenerator.invalid_paths(path, ignore_list)
11
- @config_linter = PropertyGenerator::ConfigLinter.new(path+"/config/config.yml")
12
- @globals_linter = PropertyGenerator::GlobalsLinter.new(path+"/globals/", @config_linter.configs)
13
- @services_linter = PropertyGenerator::ServicesLinter.new(path+"/services/", @config_linter.configs)
14
- @report = PropertyGenerator::Report.new(invalid_paths)
12
+ begin
13
+ @ignored_tests = YAML.load_file("#{path}/.cpsignore")
14
+ rescue StandardError
15
+ @ignored_tests = {}
16
+ end
17
+ @config_linter = PropertyGenerator::ConfigLinter.new("#{path}/config/config.yml", @ignored_tests['config'] || [])
18
+ @globals_linter = PropertyGenerator::GlobalsLinter.new("#{path}/globals/", @config_linter.configs, @ignored_tests['globals'] || [])
19
+ @services_linter = PropertyGenerator::ServicesLinter.new("#{path}/services/", @config_linter.configs, @ignored_tests['services'] || [])
20
+
21
+ unless @ignored_tests['display_skipped_tests'].nil?
22
+ if @ignored_tests['display_skipped_tests']
23
+ @ignored_tests.delete('display_skipped_tests')
24
+ else
25
+ @ignored_tests = []
26
+ end
27
+ end
28
+
29
+ @report = PropertyGenerator::Report.new(invalid_paths, @ignored_tests)
15
30
  end
16
31
 
17
32
  def run_tests
@@ -34,6 +49,5 @@ module PropertyGenerator
34
49
  def display_report
35
50
  @report.display_report
36
51
  end
37
-
38
52
  end
39
53
  end
data/lib/linter/report.rb CHANGED
@@ -2,9 +2,10 @@ module PropertyGenerator
2
2
  require 'terminal-table'
3
3
 
4
4
  class Report
5
- def initialize(files_failing_load)
5
+ def initialize(files_failing_load, ignored_tests)
6
6
  @files_failing_load = files_failing_load
7
7
  @full_report = {}
8
+ @ignored_tests = ignored_tests
8
9
  end
9
10
 
10
11
  def add_report(report)
@@ -12,12 +13,16 @@ module PropertyGenerator
12
13
  end
13
14
 
14
15
  def display_report
15
- if @files_failing_load != []
16
- make_failing_to_load_table
16
+ unless @files_failing_load.empty?
17
+ puts make_failing_to_load_table
18
+ puts '*****************'
19
+ puts "Check for property values that start with an interpolated value \nIf the first character of the value is a bracket yaml will fail to load \nPlace the value in quotes"
20
+ puts '*****************'
17
21
  end
18
- make_pass_table
19
- make_warn_table
20
- make_fail_table
22
+ puts make_skip_table
23
+ puts make_pass_table
24
+ puts make_warn_table
25
+ puts make_fail_table
21
26
  end
22
27
 
23
28
  def has_a_test_failed
@@ -39,45 +44,43 @@ module PropertyGenerator
39
44
  @files_failing_load.each do |failed|
40
45
  rows << [failed]
41
46
  end
42
- table = Terminal::Table.new :headings => ['Files'], :title => 'Files Failing to Load', :rows => rows, :style => {:width => 200}
43
- puts table
44
- puts "*****************"
45
- puts "Check for property values that start with an interpolated value \nIf the first character of the value is a bracket yaml will fail to load \nPlace the value in quotes"
46
- puts "*****************"
47
+ Terminal::Table.new :headings => ['Files'], :title => 'Files Failing to Load', :rows => rows, :style => { :width => 200 }
48
+ end
49
+
50
+ def make_skip_table
51
+ return if @ignored_tests.empty?
52
+
53
+ Terminal::Table.new(headings: ['Test'], title: 'Skipped Tests', rows: @ignored_tests.values, style: { width: 200 })
47
54
  end
48
55
 
49
56
  def make_pass_table
50
57
  rows = []
51
- @full_report.each do |test,status|
58
+ @full_report.each do |test, status|
52
59
  if status[:status] == 'pass'
53
60
  rows << [test.gsub('_', ' ')]
54
61
  end
55
62
  end
56
- table = Terminal::Table.new :headings => ['Test'], :title => 'Passing Tests', :rows => rows, :style => {:width => 200}
57
- puts table
63
+ Terminal::Table.new(headings: ['Test'], title: 'Passing Tests', rows: rows, style: { width: 200 })
58
64
  end
59
65
 
60
66
  def make_warn_table
61
67
  rows = []
62
- @full_report.each do |test,status|
68
+ @full_report.each do |test, status|
63
69
  if status[:status] == 'warn'
64
70
  rows << [test.gsub('_', ' '), status[:error].scan(/.{1,90}/).join("\n")]
65
71
  end
66
72
  end
67
- table = Terminal::Table.new :headings => ['Test', 'Error'], :title => 'Warning Tests', :rows => rows, :style => {:width => 200}
68
- puts table
73
+ Terminal::Table.new(headings: ['Test', 'Error'], title: 'Warning Tests', rows: rows, style: { width: 200 })
69
74
  end
70
75
 
71
76
  def make_fail_table
72
77
  rows = []
73
- @full_report.each do |test,status|
78
+ @full_report.each do |test, status|
74
79
  if status[:status] == 'fail'
75
80
  rows << [test.gsub('_', ' '), status[:error].scan(/.{1,90}/).join("\n")]
76
81
  end
77
82
  end
78
- table = Terminal::Table.new :headings => ['Test', 'Error'], :title => 'Failing Tests', :rows => rows, :style => {:width => 200}
79
- puts table
83
+ Terminal::Table.new(headings: ['Test', 'Error'], title: 'Failing Tests', rows: rows, style: { width: 200 })
80
84
  end
81
-
82
85
  end
83
86
  end
@@ -2,10 +2,19 @@ require_relative '../helpers/helpers'
2
2
  module PropertyGenerator
3
3
  require 'yaml'
4
4
  class ServicesLinter
5
+ TESTS = [
6
+ 'services_have_accepted_keys',
7
+ 'service_environments_are_not_empty',
8
+ 'service_environments_match_config_environments',
9
+ 'service_encrypted_environments_match_config_environments',
10
+ 'service_encrypted_fields_are_correct',
11
+ 'service_encrypted_region_field_is_accepted'
12
+ ].freeze
5
13
 
6
- def initialize(path, configs)
14
+ def initialize(path, configs, ignored_tests)
7
15
  @configs = configs
8
16
  @services = {}
17
+ @ignored_tests = ignored_tests
9
18
  valid_paths = PropertyGenerator.valid_paths(path)
10
19
  valid_paths.each do |file_path|
11
20
  @services[file_path] = YAML.load_file(file_path)
@@ -13,28 +22,19 @@ module PropertyGenerator
13
22
  end
14
23
 
15
24
  def run_services_tests
16
- tests = [
17
- 'services_have_accepted_keys',
18
- 'service_environments_are_not_empty',
19
- 'service_defaults_have_no_hashes_as_values',
20
- 'service_environments_match_config_environments',
21
- 'service_environments_have_no_hashes_as_values',
22
- 'service_encrypted_environments_match_config_environments',
23
- 'service_encrypted_fields_are_correct',
24
- 'service_encrypted_region_field_is_accepted'
25
- ]
26
- results = PropertyGenerator.test_runner(self, tests)
27
- results
25
+ tests = TESTS - @ignored_tests
26
+
27
+ PropertyGenerator.test_runner(self, tests)
28
28
  end
29
29
 
30
30
  def service_environments_are_not_empty
31
- status = {status: 'pass', error: ''}
31
+ status = { status: 'pass', error: '' }
32
32
  services_empty_environments = []
33
33
  @services.each do |path, loaded|
34
- unless loaded['environments'] == nil
34
+ unless loaded['environments'].nil?
35
35
  loaded['environments'].each do |environments, properties|
36
- if properties == nil
37
- services_empty_environments << {path => environments}
36
+ if properties.nil?
37
+ services_empty_environments << { path => environments }
38
38
  end
39
39
  end
40
40
  end
@@ -47,13 +47,13 @@ module PropertyGenerator
47
47
  end
48
48
 
49
49
  def services_have_accepted_keys
50
- status = {status: 'pass', error: ''}
50
+ status = { status: 'pass', error: '' }
51
51
  accepted_keys = ['default', 'environments', 'encrypted', 'configname', 'stringdata', 'configlabels', 'secretlabels', 'label']
52
52
  services_with_unacceptable_keys = []
53
53
  @services.each do |path, loaded|
54
54
  loaded.keys.each do |service_key|
55
55
  unless accepted_keys.include?(service_key)
56
- services_with_unacceptable_keys << {path => service_key}
56
+ services_with_unacceptable_keys << { path => service_key }
57
57
  end
58
58
  end
59
59
  end
@@ -64,38 +64,19 @@ module PropertyGenerator
64
64
  status
65
65
  end
66
66
 
67
- def service_defaults_have_no_hashes_as_values
68
- status = {status: 'pass', error: ''}
69
- services_with_hashes_in_defaults = []
70
- @services.each do |path, loaded|
71
- unless loaded['default'] == nil
72
- loaded['default'].each do |defaultkey, defaultvalue|
73
- if defaultvalue.class == Hash
74
- services_with_hashes_in_defaults << {path => defaultkey}
75
- end
76
- end
77
- end
78
- end
79
- if services_with_hashes_in_defaults != []
80
- status[:status] = 'fail'
81
- status[:error] = "Service files: #{services_with_hashes_in_defaults} have default properties with values as hashes."
82
- end
83
- status
84
- end
85
-
86
67
  def service_environments_match_config_environments
87
- status = {status: 'pass', error: ''}
68
+ status = { status: 'pass', error: '' }
88
69
  missmatched_environments = []
89
70
  @services.each do |path, loaded|
90
- if loaded['environments'] != nil
91
- loaded['environments'].keys.each do |environment|
92
- if @configs['environments'] != nil
93
- unless @configs['environments'].include?(environment)
94
- missmatched_environments << {path => environment}
95
- end
96
- else
97
- status[:status] = 'warn'
98
- status[:error] = "Environments list in config file is missing."
71
+ next if loaded['environments'].nil?
72
+
73
+ loaded['environments'].keys.each do |environment|
74
+ if @configs['environments'].nil?
75
+ status[:status] = 'warn'
76
+ status[:error] = 'Environments list in config file is missing.'
77
+ else
78
+ unless @configs['environments'].include?(environment)
79
+ missmatched_environments << { path => environment }
99
80
  end
100
81
  end
101
82
  end
@@ -107,42 +88,19 @@ module PropertyGenerator
107
88
  status
108
89
  end
109
90
 
110
- def service_environments_have_no_hashes_as_values
111
- status = {status: 'pass', error: ''}
112
- services_with_hashes_in_environments = []
113
- @services.each do |path, loaded|
114
- unless loaded['environments'] == nil
115
- loaded['environments'].each do |environments, properties|
116
- unless properties == nil
117
- properties.each do |key, value|
118
- if value.class == Hash
119
- services_with_hashes_in_environments << {path => {environments => key}}
120
- end
121
- end
122
- end
123
- end
124
- end
125
- end
126
- if services_with_hashes_in_environments != []
127
- status[:status] = 'fail'
128
- status[:error] = "Service files #{services_with_hashes_in_environments} have environment properties with values as hashes."
129
- end
130
- status
131
- end
132
-
133
91
  def service_encrypted_environments_match_config_environments
134
- status = {status: 'pass', error: ''}
92
+ status = { status: 'pass', error: '' }
135
93
  missmatched_environments = []
136
94
  @services.each do |path, loaded|
137
- if loaded['encrypted'] != nil
138
- loaded['encrypted'].keys.each do |environment|
139
- if @configs['environments'] != nil
140
- unless @configs['environments'].include?(environment)
141
- missmatched_environments << {path => environment}
142
- end
143
- else
144
- status[:status] = 'warn'
145
- status[:error] = "Environments list in config file is missing."
95
+ next if loaded['encrypted'].nil?
96
+
97
+ loaded['encrypted'].keys.each do |environment|
98
+ if @configs['environments'].nil?
99
+ status[:status] = 'warn'
100
+ status[:error] = 'Environments list in config file is missing.'
101
+ else
102
+ unless @configs['environments'].include?(environment)
103
+ missmatched_environments << { path => environment }
146
104
  end
147
105
  end
148
106
  end
@@ -154,66 +112,103 @@ module PropertyGenerator
154
112
  status
155
113
  end
156
114
 
115
+ def recursive_find_keys(obj, key)
116
+ if obj.respond_to?(:key?) && obj.key?(key)
117
+ obj[key]
118
+ elsif obj.is_a?(Hash) or obj.is_a?(Array)
119
+ r = nil
120
+ obj.find{ |*a| r = recursive_find_keys(a.last,key) }
121
+ r
122
+ end
123
+ end
124
+
157
125
  def service_encrypted_fields_are_correct
158
- status = {status: 'pass', error: ''}
159
- accepted_keys = ['region', 'encrypted', 'service']
126
+ status = { status: 'pass', error: '' }
127
+ accepted_keys = ['region', 'encrypted', 'service', 'label']
160
128
  services_with_unacceptable_keys = []
161
129
  @services.each do |path, loaded|
162
- if loaded['encrypted'] != nil
163
- loaded['encrypted'].each do |environment, properties|
164
- properties.each do |property, value|
165
- if value == nil
166
- services_with_unacceptable_keys << {path => {environment => property}}
167
- elsif value['$ssm'] == nil
168
- services_with_unacceptable_keys << {path => {environment => property}}
169
- else
170
- if value['$ssm'] != nil
171
- value['$ssm'].keys.each do |key|
172
- unless accepted_keys.include?(key)
173
- services_with_unacceptable_keys << {path => {environment => property}}
174
- end
175
- end
130
+ next if loaded['encrypted'].nil?
131
+
132
+ loaded['encrypted'].each do |environment, properties|
133
+ properties.each do |property, value|
134
+ if value.nil?
135
+ services_with_unacceptable_keys << { path => { environment => property } }
136
+ next
137
+ end
138
+
139
+ s = recursive_find_keys(value, '$ssm')
140
+ k = recursive_find_keys(value, '$kms')
141
+ if s.nil? && k.nil?
142
+ services_with_unacceptable_keys << { path => { environment => property } }
143
+ next
144
+ end
145
+
146
+ unless s.nil?
147
+ s.keys.each do |key|
148
+ unless accepted_keys.include?(key)
149
+ services_with_unacceptable_keys << { path => { environment => property } }
150
+ next
176
151
  end
177
152
  end
178
153
  end
154
+
155
+ unless k.nil?
156
+ if (k.keys & ['region', 'encrypted']).count != 2
157
+ services_with_unacceptable_keys << { path => { environment => property } }
158
+ end
159
+ end
179
160
  end
180
161
  end
181
162
  end
182
- if services_with_unacceptable_keys != []
163
+ unless services_with_unacceptable_keys.empty?
183
164
  status[:status] = 'fail'
184
- status[:error] = "Service files: #{services_with_unacceptable_keys} have encrypted properties with bad indentation or keys other than 'region' and 'encrypted'."
165
+ status[:error] = "Service files: #{services_with_unacceptable_keys} has an encrypted block without " +
166
+ "properties, encrypted properties without $kms or $ssm blocks, or encrypted blocks with either bad " +
167
+ "indentation or incorrect keys."
185
168
  end
186
169
  status
187
170
  end
188
171
 
189
172
  def service_encrypted_region_field_is_accepted
190
- status = {status: 'pass', error: ''}
173
+ status = { status: 'pass', error: '' }
191
174
  services_with_unacceptable_keys = []
192
175
  @services.each do |path, loaded|
193
- if loaded['encrypted'] != nil
194
- loaded['encrypted'].each do |environment, property|
195
- if loaded['encrypted'][environment][property] != nil
196
- loaded['encrypted'][environment][property].each do |ssm, keys|
197
- if @configs['environments'] != nil
198
- unless @configs['environments'].include?(loaded['encrypted'][environment][property]['$ssm'][keys]['region'])
199
- services_with_unacceptable_keys << {path => {environment => property}}
200
- end
201
- else
202
- status[:status] = 'warn'
203
- status[:error] = "Environments list in config file is missing."
204
- end
176
+ next if loaded['encrypted'].nil?
177
+
178
+ loaded['encrypted'].each do |environment, properties|
179
+ if loaded['encrypted'][environment].nil?
180
+ status[:status] = 'error'
181
+ status[:error] = 'Encrypted properties are missing from the encrypted environment'
182
+ return status
183
+ end
184
+
185
+ encrypted_env = loaded['encrypted'][environment]
186
+
187
+ # next if encrypted_env[property].nil?
188
+
189
+ encrypted_env.each do |property, encrypted_values|
190
+ if @configs['environments'].nil?
191
+ status[:status] = 'warn'
192
+ status[:error] = 'Environments list in config file is missing.'
193
+ break
194
+ end
195
+
196
+ %w[$ssm $kms].each do |encryption_type|
197
+ values = recursive_find_keys(encrypted_values, encryption_type)
198
+ next if values.nil?
199
+
200
+ unless @configs['environments'].include?(values['region'])
201
+ services_with_unacceptable_keys << { path => { environment => property } }
205
202
  end
206
203
  end
207
204
  end
208
205
  end
209
206
  end
210
- if services_with_unacceptable_keys != []
207
+ if !services_with_unacceptable_keys.empty? && status[:status] == 'pass'
211
208
  status[:status] = 'warn'
212
209
  status[:error] = "Service files: #{services_with_unacceptable_keys} have encrypted properties a region field not matching a declared environment in the configs."
213
210
  end
214
211
  status
215
212
  end
216
-
217
-
218
213
  end
219
214
  end