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.
- checksums.yaml +4 -4
- data/bin/cps-property-generator +3 -5
- data/lib/generator/config.rb +1 -2
- data/lib/generator/generator.rb +7 -9
- data/lib/generator/globals.rb +11 -11
- data/lib/generator/service.rb +9 -19
- data/lib/helpers/helpers.rb +22 -22
- data/lib/linter/config_linter.rb +36 -37
- data/lib/linter/globals_linter.rb +35 -30
- data/lib/linter/linter.rb +24 -10
- data/lib/linter/report.rb +24 -21
- data/lib/linter/services_linter.rb +109 -70
- data/spec/lib/config_spec.rb +23 -18
- data/spec/lib/global_spec.rb +55 -30
- data/spec/lib/service_spec.rb +76 -67
- data/spec/resources/services/my-microservice-1.yml +8 -0
- metadata +27 -13
@@ -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
|
-
|
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 =
|
17
|
-
|
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
|
-
|
61
|
-
|
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] =
|
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
|
3
|
-
require_relative 'globals_linter
|
4
|
-
require_relative 'services_linter
|
5
|
-
require_relative 'report
|
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 = [
|
10
|
+
ignore_list = %w[README.md .cpsignore]
|
10
11
|
invalid_paths = PropertyGenerator.invalid_paths(path, ignore_list)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
18
|
-
|
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']
|
34
|
+
unless loaded['environments'].nil?
|
33
35
|
loaded['environments'].each do |environments, properties|
|
34
|
-
if properties
|
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']
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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']
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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']
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
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
|
-
|
163
|
+
unless services_with_unacceptable_keys.empty?
|
139
164
|
status[:status] = 'fail'
|
140
|
-
status[:error] = "Service files: #{services_with_unacceptable_keys}
|
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']
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|