cps-property-generator 0.1.1

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.
@@ -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