cps-property-generator 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +115 -0
- data/bin/cps-property-generator +45 -0
- data/lib/generator/config.rb +32 -0
- data/lib/generator/generator.rb +50 -0
- data/lib/generator/globals.rb +85 -0
- data/lib/generator/service.rb +89 -0
- data/lib/helpers/helpers.rb +81 -0
- data/lib/linter/config_linter.rb +106 -0
- data/lib/linter/globals_linter.rb +84 -0
- data/lib/linter/linter.rb +35 -0
- data/lib/linter/report.rb +76 -0
- data/lib/linter/services_linter.rb +186 -0
- data/spec/lib/config_spec.rb +35 -0
- data/spec/lib/global_spec.rb +28 -0
- data/spec/lib/service_spec.rb +35 -0
- data/spec/resources/config/config.yml +23 -0
- data/spec/resources/globals/accounts/123456789012/123456789012.yml +1 -0
- data/spec/resources/globals/accounts/123456789012/environments/my-test-env1.yml +1 -0
- data/spec/resources/globals/globals.yml +1 -0
- data/spec/resources/services/my-microservice-1.yml +16 -0
- data/spec/spec_helper.rb +85 -0
- metadata +136 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
module PropertyGenerator
|
2
|
+
require 'yaml'
|
3
|
+
class ConfigLinter
|
4
|
+
|
5
|
+
attr_accessor :configs
|
6
|
+
|
7
|
+
def initialize(path)
|
8
|
+
@configs = check_for_config(path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def run_config_tests
|
12
|
+
if @configs == {}
|
13
|
+
tests = ['config_file_is_present']
|
14
|
+
else
|
15
|
+
tests = ['config_has_correct_keys',
|
16
|
+
'environment_configs_match_environments_list',
|
17
|
+
'environment_configs_have_matching_region_and_account_values',
|
18
|
+
'environment_configs_have_well_formatted_interpolations',
|
19
|
+
'config_file_is_present']
|
20
|
+
end
|
21
|
+
results = PropertyGenerator.test_runner(self, tests)
|
22
|
+
results
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_for_config(path)
|
26
|
+
#Tries to load the config file - if is unable to load config.yml it returns an empty hash
|
27
|
+
#Empty hash is returned so that the rest of the files are still able to be linted instead of stopping at this point.
|
28
|
+
begin
|
29
|
+
YAML.load_file(path)
|
30
|
+
rescue
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def config_file_is_present
|
36
|
+
status = {status: 'pass', error: ''}
|
37
|
+
if @configs == {}
|
38
|
+
status[:status] = 'fail'
|
39
|
+
status[:error] = "Config.yml file is missing, it is required."
|
40
|
+
end
|
41
|
+
status
|
42
|
+
end
|
43
|
+
|
44
|
+
def config_has_correct_keys
|
45
|
+
status = {status: 'pass', error: ''}
|
46
|
+
config_keys = ['environments', 'accounts',
|
47
|
+
'environment_configs']
|
48
|
+
if @configs.keys != config_keys
|
49
|
+
status[:status] = 'fail'
|
50
|
+
status[:error] = "Config keys should be 'environments', 'accounts', and 'environment_configs'."
|
51
|
+
end
|
52
|
+
status
|
53
|
+
end
|
54
|
+
|
55
|
+
def environment_configs_match_environments_list
|
56
|
+
status = {status: 'pass', error: ''}
|
57
|
+
if @configs['environments'] != @configs['environment_configs'].keys
|
58
|
+
status[:status] = 'fail'
|
59
|
+
status[:error] = "Environments in environment_configs do not match environments listed in config environments."
|
60
|
+
end
|
61
|
+
status
|
62
|
+
end
|
63
|
+
|
64
|
+
def environment_configs_have_matching_region_and_account_values
|
65
|
+
status = {status: 'pass', error: ''}
|
66
|
+
environments_missmatch_values = []
|
67
|
+
any_missmatches = false
|
68
|
+
@configs['environment_configs'].keys.each do |environment|
|
69
|
+
unless @configs['environments'].include?(@configs['environment_configs'][environment]['region']) && @configs['accounts'].include?(@configs['environment_configs'][environment]['account'])
|
70
|
+
environments_missmatch_values << environment
|
71
|
+
any_missmatches = true
|
72
|
+
end
|
73
|
+
if any_missmatches
|
74
|
+
status[:status] = 'fail'
|
75
|
+
status[:error] = "Environments: #{environments_missmatch_values} in environment_configs have a region or account value not listed in top level."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
status
|
79
|
+
end
|
80
|
+
|
81
|
+
def environment_configs_have_well_formatted_interpolations
|
82
|
+
status = {status: 'pass', error: ''}
|
83
|
+
environments_with_bad_interpolations = []
|
84
|
+
any_mistakes = false
|
85
|
+
@configs['environment_configs'].keys.each do |environment|
|
86
|
+
if @configs['environment_configs'][environment]['interpolations'].class == Hash
|
87
|
+
@configs['environment_configs'][environment]['interpolations'].each do |interpolation, value|
|
88
|
+
if value.class != String && value.class != Integer && value.class != Float && value.class != Fixnum
|
89
|
+
environments_with_bad_interpolations << {environment => interpolation}
|
90
|
+
any_mistakes = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
else
|
94
|
+
environments_with_bad_interpolations << environment
|
95
|
+
any_mistakes = true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
if any_mistakes
|
99
|
+
status[:status] = 'fail'
|
100
|
+
status[:error] = "Incorrectly formatted interpolations in Environments: #{environments_with_bad_interpolations}"
|
101
|
+
end
|
102
|
+
status
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module PropertyGenerator
|
2
|
+
require 'yaml'
|
3
|
+
class GlobalsLinter
|
4
|
+
|
5
|
+
def initialize(path, configs)
|
6
|
+
@configs = configs
|
7
|
+
@globals = {}
|
8
|
+
valid_paths = PropertyGenerator.valid_paths(path)
|
9
|
+
valid_paths.each do |file_path|
|
10
|
+
@globals[file_path] = YAML.load_file(file_path)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_globals_tests
|
15
|
+
tests = ['globals_load_as_hashes',
|
16
|
+
'globals_have_no_hashes_as_values',
|
17
|
+
'globals_are_defined_for_valid_environemnts',
|
18
|
+
]
|
19
|
+
results = PropertyGenerator.test_runner(self, tests)
|
20
|
+
results
|
21
|
+
end
|
22
|
+
|
23
|
+
def globals_load_as_hashes
|
24
|
+
status = {status: 'pass', error: ''}
|
25
|
+
non_hash_globals = []
|
26
|
+
@globals.each do |path, loaded|
|
27
|
+
if loaded.class != Hash
|
28
|
+
non_hash_globals << path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
if non_hash_globals != []
|
32
|
+
status[:status] = 'fail'
|
33
|
+
status[:error] = "Global files #{non_hash_globals} are not being loaded as hashes."
|
34
|
+
end
|
35
|
+
status
|
36
|
+
end
|
37
|
+
|
38
|
+
def globals_have_no_hashes_as_values
|
39
|
+
status = {status: 'pass', error: ''}
|
40
|
+
globals_with_hash_props = []
|
41
|
+
@globals.each do |path, loaded|
|
42
|
+
if loaded.class == Hash
|
43
|
+
loaded.each do |key, value|
|
44
|
+
if value.class == Hash
|
45
|
+
globals_with_hash_props << {path => key}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if globals_with_hash_props != []
|
51
|
+
status[:status] = 'fail'
|
52
|
+
status[:error] = "Globals #{globals_with_hash_props} have values that are hashes."
|
53
|
+
end
|
54
|
+
status
|
55
|
+
end
|
56
|
+
|
57
|
+
def globals_are_defined_for_valid_environemnts
|
58
|
+
status = {status: 'pass', error: ''}
|
59
|
+
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
|
76
|
+
status[:status] = 'warn'
|
77
|
+
status[:error] = "Accounts list in config file is missing."
|
78
|
+
end
|
79
|
+
status
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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'
|
6
|
+
class Linter
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
ignore_list = ['README.md']
|
10
|
+
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)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_tests
|
18
|
+
config_report = @config_linter.run_config_tests
|
19
|
+
globals_report = @globals_linter.run_globals_tests
|
20
|
+
service_linter = @services_linter.run_services_tests
|
21
|
+
@report.add_report(config_report)
|
22
|
+
@report.add_report(globals_report)
|
23
|
+
@report.add_report(service_linter)
|
24
|
+
end
|
25
|
+
|
26
|
+
def fail_check
|
27
|
+
@report.has_a_test_failed
|
28
|
+
end
|
29
|
+
|
30
|
+
def display_report
|
31
|
+
@report.display_report
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module PropertyGenerator
|
2
|
+
require 'terminal-table'
|
3
|
+
|
4
|
+
class Report
|
5
|
+
def initialize(files_failing_load)
|
6
|
+
@files_failing_load = files_failing_load
|
7
|
+
@full_report = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_report(report)
|
11
|
+
@full_report = @full_report.merge(report)
|
12
|
+
end
|
13
|
+
|
14
|
+
def display_report
|
15
|
+
if @files_failing_load != []
|
16
|
+
make_failing_to_load_table
|
17
|
+
end
|
18
|
+
make_pass_table
|
19
|
+
make_warn_table
|
20
|
+
make_fail_table
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_a_test_failed
|
24
|
+
@full_report.each do |test, status|
|
25
|
+
if status[:status] == 'fail' || @files_failing_load != []
|
26
|
+
return true
|
27
|
+
else
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def make_failing_to_load_table
|
34
|
+
rows = []
|
35
|
+
@files_failing_load.each do |failed|
|
36
|
+
rows << [failed]
|
37
|
+
end
|
38
|
+
table = Terminal::Table.new :headings => ['Files'], :title => 'Files Failing to Load', :rows => rows, :style => {:width => 200}
|
39
|
+
puts table
|
40
|
+
end
|
41
|
+
|
42
|
+
def make_pass_table
|
43
|
+
rows = []
|
44
|
+
@full_report.each do |test,status|
|
45
|
+
if status[:status] == 'pass'
|
46
|
+
rows << [test.gsub('_', ' ')]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
table = Terminal::Table.new :headings => ['Test'], :title => 'Passing Tests', :rows => rows, :style => {:width => 200}
|
50
|
+
puts table
|
51
|
+
end
|
52
|
+
|
53
|
+
def make_warn_table
|
54
|
+
rows = []
|
55
|
+
@full_report.each do |test,status|
|
56
|
+
if status[:status] == 'warn'
|
57
|
+
rows << [test.gsub('_', ' '), status[:error].scan(/.{1,90}/).join("\n")]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
table = Terminal::Table.new :headings => ['Test', 'Error'], :title => 'Warning Tests', :rows => rows, :style => {:width => 200}
|
61
|
+
puts table
|
62
|
+
end
|
63
|
+
|
64
|
+
def make_fail_table
|
65
|
+
rows = []
|
66
|
+
@full_report.each do |test,status|
|
67
|
+
if status[:status] == 'fail'
|
68
|
+
rows << [test.gsub('_', ' '), status[:error].scan(/.{1,90}/).join("\n")]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
table = Terminal::Table.new :headings => ['Test', 'Error'], :title => 'Failing Tests', :rows => rows, :style => {:width => 200}
|
72
|
+
puts table
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
module PropertyGenerator
|
2
|
+
require 'yaml'
|
3
|
+
class ServicesLinter
|
4
|
+
|
5
|
+
def initialize(path, configs)
|
6
|
+
@configs = configs
|
7
|
+
@services = {}
|
8
|
+
valid_paths = PropertyGenerator.valid_paths(path)
|
9
|
+
valid_paths.each do |file_path|
|
10
|
+
@services[file_path] = YAML.load_file(file_path)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_services_tests
|
15
|
+
tests = ['services_have_accepted_keys',
|
16
|
+
'service_defaults_have_no_hashes_as_values',
|
17
|
+
'service_environments_match_config_environments',
|
18
|
+
'service_environments_have_no_hashes_as_values',
|
19
|
+
'service_encrypted_environments_match_config_environments',
|
20
|
+
'service_encrypted_fields_are_correct',
|
21
|
+
'service_encrypted_region_field_is_accepted']
|
22
|
+
results = PropertyGenerator.test_runner(self, tests)
|
23
|
+
results
|
24
|
+
end
|
25
|
+
|
26
|
+
def services_have_accepted_keys
|
27
|
+
status = {status: 'pass', error: ''}
|
28
|
+
accepted_keys = ['default', 'environments', 'encrypted']
|
29
|
+
services_with_unacceptable_keys = []
|
30
|
+
@services.each do |path, loaded|
|
31
|
+
loaded.keys.each do |service_key|
|
32
|
+
unless accepted_keys.include?(service_key)
|
33
|
+
services_with_unacceptable_keys << {path => service_key}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
if services_with_unacceptable_keys != []
|
38
|
+
status[:status] = 'fail'
|
39
|
+
status[:error] = "Service files: #{services_with_unacceptable_keys} have keys other than 'default', 'environments', or 'encrypted'."
|
40
|
+
end
|
41
|
+
status
|
42
|
+
end
|
43
|
+
|
44
|
+
def service_defaults_have_no_hashes_as_values
|
45
|
+
status = {status: 'pass', error: ''}
|
46
|
+
services_with_hashes_in_defaults = []
|
47
|
+
@services.each do |path, loaded|
|
48
|
+
unless loaded['default'] == nil
|
49
|
+
loaded['default'].each do |defaultkey, defaultvalue|
|
50
|
+
if defaultvalue.class == Hash
|
51
|
+
services_with_hashes_in_defaults << {path => defaultkey}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
if services_with_hashes_in_defaults != []
|
57
|
+
status[:status] = 'fail'
|
58
|
+
status[:error] = "Service files: #{services_with_hashes_in_defaults} have default properties with values as hashes."
|
59
|
+
end
|
60
|
+
status
|
61
|
+
end
|
62
|
+
|
63
|
+
def service_environments_match_config_environments
|
64
|
+
status = {status: 'pass', error: ''}
|
65
|
+
missmatched_environments = []
|
66
|
+
@services.each do |path, loaded|
|
67
|
+
if loaded['environments'] != nil
|
68
|
+
loaded['environments'].keys.each do |environment|
|
69
|
+
if @configs['environments'] != nil
|
70
|
+
unless @configs['environments'].include?(environment)
|
71
|
+
missmatched_environments << {path => environment}
|
72
|
+
end
|
73
|
+
else
|
74
|
+
status[:status] = 'warn'
|
75
|
+
status[:error] = "Environments list in config file is missing."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
if missmatched_environments != []
|
81
|
+
status[:status] = 'warn'
|
82
|
+
status[:error] = "Service files: #{missmatched_environments} have environments not matching config list."
|
83
|
+
end
|
84
|
+
status
|
85
|
+
end
|
86
|
+
|
87
|
+
def service_environments_have_no_hashes_as_values
|
88
|
+
status = {status: 'pass', error: ''}
|
89
|
+
services_with_hashes_in_environments = []
|
90
|
+
@services.each do |path, loaded|
|
91
|
+
unless loaded['environments'] == nil
|
92
|
+
loaded['environments'].each do |environments, properties|
|
93
|
+
properties.each do |key, value|
|
94
|
+
if value.class == Hash
|
95
|
+
services_with_hashes_in_environments << {path => {environments => key}}
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
if services_with_hashes_in_environments != []
|
102
|
+
status[:status] = 'fail'
|
103
|
+
status[:error] = "Service files #{services_with_hashes_in_environments} have environment properties with values as hashes."
|
104
|
+
end
|
105
|
+
status
|
106
|
+
end
|
107
|
+
|
108
|
+
def service_encrypted_environments_match_config_environments
|
109
|
+
status = {status: 'pass', error: ''}
|
110
|
+
missmatched_environments = []
|
111
|
+
@services.each do |path, loaded|
|
112
|
+
if loaded['encrypted'] != nil
|
113
|
+
loaded['encrypted'].keys.each do |environment|
|
114
|
+
if @configs['environments'] != nil
|
115
|
+
unless @configs['environments'].include?(environment)
|
116
|
+
missmatched_environments << {path => environment}
|
117
|
+
end
|
118
|
+
else
|
119
|
+
status[:status] = 'warn'
|
120
|
+
status[:error] = "Environments list in config file is missing."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
if missmatched_environments != []
|
126
|
+
status[:status] = 'warn'
|
127
|
+
status[:error] = "Service files: #{missmatched_environments} have encrypted environments not matching config list."
|
128
|
+
end
|
129
|
+
status
|
130
|
+
end
|
131
|
+
|
132
|
+
def service_encrypted_fields_are_correct
|
133
|
+
status = {status: 'pass', error: ''}
|
134
|
+
accepted_keys = ['region', 'encrypted']
|
135
|
+
services_with_unacceptable_keys = []
|
136
|
+
@services.each do |path, loaded|
|
137
|
+
if loaded['encrypted'] != nil
|
138
|
+
loaded['encrypted'].each do |environment, property|
|
139
|
+
if loaded['encrypted'][environment][property] != nil
|
140
|
+
loaded['encrypted'][environment][property].each do |ssm, keys|
|
141
|
+
unless loaded['encrypted'][environment][property]['$ssm'][keys].keys == accepted_keys
|
142
|
+
services_with_unacceptable_keys << {path => {environment => property}}
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
if services_with_unacceptable_keys != []
|
150
|
+
status[:status] = 'fail'
|
151
|
+
status[:error] = "Service files: #{services_with_unacceptable_keys} have encrypted properties with keys other than 'region' and 'encrypted'."
|
152
|
+
end
|
153
|
+
status
|
154
|
+
end
|
155
|
+
|
156
|
+
def service_encrypted_region_field_is_accepted
|
157
|
+
status = {status: 'pass', error: ''}
|
158
|
+
services_with_unacceptable_keys = []
|
159
|
+
@services.each do |path, loaded|
|
160
|
+
if loaded['encrypted'] != nil
|
161
|
+
loaded['encrypted'].each do |environment, property|
|
162
|
+
if loaded['encrypted'][environment][property] != nil
|
163
|
+
loaded['encrypted'][environment][property].each do |ssm, keys|
|
164
|
+
if @configs['environments'] != nil
|
165
|
+
unless @configs['environments'].include?(loaded['encrypted'][environment][property]['$ssm'][keys]['region'])
|
166
|
+
services_with_unacceptable_keys << {path => {environment => property}}
|
167
|
+
end
|
168
|
+
else
|
169
|
+
status[:status] = 'warn'
|
170
|
+
status[:error] = "Environments list in config file is missing."
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
if services_with_unacceptable_keys != []
|
178
|
+
status[:status] = 'warn'
|
179
|
+
status[:error] = "Service files: #{services_with_unacceptable_keys} have encrypted properties a region field not matching a declared environment in the configs."
|
180
|
+
end
|
181
|
+
status
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
end
|
186
|
+
end
|