cps-property-generator 0.2.19 → 0.3.2

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 Jenkinsfile]
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,26 +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_environments_match_config_environments',
20
- 'service_encrypted_environments_match_config_environments',
21
- 'service_encrypted_fields_are_correct',
22
- 'service_encrypted_region_field_is_accepted'
23
- ]
24
- results = PropertyGenerator.test_runner(self, tests)
25
- results
25
+ tests = TESTS - @ignored_tests
26
+
27
+ PropertyGenerator.test_runner(self, tests)
26
28
  end
27
29
 
28
30
  def service_environments_are_not_empty
29
- status = {status: 'pass', error: ''}
31
+ status = { status: 'pass', error: '' }
30
32
  services_empty_environments = []
31
33
  @services.each do |path, loaded|
32
- unless loaded['environments'] == nil
34
+ unless loaded['environments'].nil?
33
35
  loaded['environments'].each do |environments, properties|
34
- if properties == nil
35
- services_empty_environments << {path => environments}
36
+ if properties.nil?
37
+ services_empty_environments << { path => environments }
36
38
  end
37
39
  end
38
40
  end
@@ -45,13 +47,13 @@ module PropertyGenerator
45
47
  end
46
48
 
47
49
  def services_have_accepted_keys
48
- status = {status: 'pass', error: ''}
50
+ status = { status: 'pass', error: '' }
49
51
  accepted_keys = ['default', 'environments', 'encrypted', 'configname', 'stringdata', 'configlabels', 'secretlabels', 'label']
50
52
  services_with_unacceptable_keys = []
51
53
  @services.each do |path, loaded|
52
54
  loaded.keys.each do |service_key|
53
55
  unless accepted_keys.include?(service_key)
54
- services_with_unacceptable_keys << {path => service_key}
56
+ services_with_unacceptable_keys << { path => service_key }
55
57
  end
56
58
  end
57
59
  end
@@ -63,18 +65,18 @@ module PropertyGenerator
63
65
  end
64
66
 
65
67
  def service_environments_match_config_environments
66
- status = {status: 'pass', error: ''}
68
+ status = { status: 'pass', error: '' }
67
69
  missmatched_environments = []
68
70
  @services.each do |path, loaded|
69
- if loaded['environments'] != nil
70
- loaded['environments'].keys.each do |environment|
71
- if @configs['environments'] != nil
72
- unless @configs['environments'].include?(environment)
73
- missmatched_environments << {path => environment}
74
- end
75
- else
76
- status[:status] = 'warn'
77
- 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 }
78
80
  end
79
81
  end
80
82
  end
@@ -87,18 +89,18 @@ module PropertyGenerator
87
89
  end
88
90
 
89
91
  def service_encrypted_environments_match_config_environments
90
- status = {status: 'pass', error: ''}
92
+ status = { status: 'pass', error: '' }
91
93
  missmatched_environments = []
92
94
  @services.each do |path, loaded|
93
- if loaded['encrypted'] != nil
94
- loaded['encrypted'].keys.each do |environment|
95
- if @configs['environments'] != nil
96
- unless @configs['environments'].include?(environment)
97
- missmatched_environments << {path => environment}
98
- end
99
- else
100
- status[:status] = 'warn'
101
- 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 }
102
104
  end
103
105
  end
104
106
  end
@@ -110,66 +112,103 @@ module PropertyGenerator
110
112
  status
111
113
  end
112
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
+
113
125
  def service_encrypted_fields_are_correct
114
- status = {status: 'pass', error: ''}
126
+ status = { status: 'pass', error: '' }
115
127
  accepted_keys = ['region', 'encrypted', 'service', 'label']
116
128
  services_with_unacceptable_keys = []
117
129
  @services.each do |path, loaded|
118
- if loaded['encrypted'] != nil
119
- loaded['encrypted'].each do |environment, properties|
120
- properties.each do |property, value|
121
- if value == nil
122
- services_with_unacceptable_keys << {path => {environment => property}}
123
- elsif value['$ssm'] == nil
124
- services_with_unacceptable_keys << {path => {environment => property}}
125
- else
126
- if value['$ssm'] != nil
127
- value['$ssm'].keys.each do |key|
128
- unless accepted_keys.include?(key)
129
- services_with_unacceptable_keys << {path => {environment => property}}
130
- end
131
- 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
132
151
  end
133
152
  end
134
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
135
160
  end
136
161
  end
137
162
  end
138
- if services_with_unacceptable_keys != []
163
+ unless services_with_unacceptable_keys.empty?
139
164
  status[:status] = 'fail'
140
- status[:error] = "Service files: #{services_with_unacceptable_keys} have encrypted properties with bad indentation or keys other than 'region', 'encrypted' or 'label'."
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."
141
168
  end
142
169
  status
143
170
  end
144
171
 
145
172
  def service_encrypted_region_field_is_accepted
146
- status = {status: 'pass', error: ''}
173
+ status = { status: 'pass', error: '' }
147
174
  services_with_unacceptable_keys = []
148
175
  @services.each do |path, loaded|
149
- if loaded['encrypted'] != nil
150
- loaded['encrypted'].each do |environment, property|
151
- if loaded['encrypted'][environment][property] != nil
152
- loaded['encrypted'][environment][property].each do |ssm, keys|
153
- if @configs['environments'] != nil
154
- unless @configs['environments'].include?(loaded['encrypted'][environment][property]['$ssm'][keys]['region'])
155
- services_with_unacceptable_keys << {path => {environment => property}}
156
- end
157
- else
158
- status[:status] = 'warn'
159
- status[:error] = "Environments list in config file is missing."
160
- 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 } }
161
202
  end
162
203
  end
163
204
  end
164
205
  end
165
206
  end
166
- if services_with_unacceptable_keys != []
207
+ if !services_with_unacceptable_keys.empty? && status[:status] == 'pass'
167
208
  status[:status] = 'warn'
168
209
  status[:error] = "Service files: #{services_with_unacceptable_keys} have encrypted properties a region field not matching a declared environment in the configs."
169
210
  end
170
211
  status
171
212
  end
172
-
173
-
174
213
  end
175
214
  end