cps-property-generator 0.2.21 → 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.
@@ -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,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