cps-property-generator 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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