cfn-nag 0.3.73 → 0.3.74

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f92b4e5025b097a9c43fb1bedd691f61611e8902109f2e6ac1500819ce7a966
4
- data.tar.gz: 5fc445b20109d8b843a1946adf29941f235fff67bc8bd8a5e3bcbdfc2c158ce5
3
+ metadata.gz: df7c2cd400873808f2c86c468bf2b8fe254b4f818629ca85cae8d4249e61e91b
4
+ data.tar.gz: b07f2ab8db5b52656283fb72ed7660abb8d9461323230fca262434e0d9e1f8b6
5
5
  SHA512:
6
- metadata.gz: e184524a035bf8be537b23e52f8718969aa7342e9834fff65931928d5e8f107b9fc6b42bab97a2c451c0d1f502d4d78b9c830a73543bb3dd58c4d6cc6e99fcd8
7
- data.tar.gz: 8c0729ab854708080bef5a2bcc71292c1a51787cd0856877481f1d929c2efe7d4574875bc077a69c237ab22038e11cf3fdef239c187c9a7fb9c35a95447f33e0
6
+ metadata.gz: ad73aa5062aee010cf3a3ebdee335ec54e7e13f1dd366f003d7c9b613c0c91868f65508c8e6e68d883fa2dba5954c08576c1365840612b99214dda3f81655940
7
+ data.tar.gz: 5c72467fe9904e35a3871186b1217890c8662010795d47d950e2980674ce53e7967f4d94b63b515067df7bba7e3f7b4c7b18f909a8ef9afa6ecc99f94423ddf0
data/bin/cfn_nag CHANGED
@@ -42,6 +42,11 @@ opts = Trollop.options do
42
42
  type: :io,
43
43
  required: false,
44
44
  default: nil
45
+ opt :blacklist_path,
46
+ 'Path to a blacklist file',
47
+ type: :io,
48
+ required: false,
49
+ default: nil
45
50
  opt :parameter_values_path,
46
51
  'Path to a JSON file to pull Parameter values from',
47
52
  type: :io,
@@ -55,13 +60,18 @@ opts = Trollop.options do
55
60
  end
56
61
  # rubocop:enable Metrics/BlockLength
57
62
 
58
- CfnNag.configure_logging(opts)
63
+ CfnNagLogging.configure_logging(opts)
59
64
 
60
65
  profile_definition = nil
61
66
  unless opts[:profile_path].nil?
62
67
  profile_definition = IO.read(opts[:profile_path])
63
68
  end
64
69
 
70
+ blacklist_definition = nil
71
+ unless opts[:blacklist_path].nil?
72
+ blacklist_definition = IO.read(opts[:blacklist_path])
73
+ end
74
+
65
75
  parameter_values_string = nil
66
76
  unless opts[:parameter_values_path].nil?
67
77
  parameter_values_string = IO.read(opts[:parameter_values_path])
@@ -69,6 +79,7 @@ end
69
79
 
70
80
  cfn_nag = CfnNag.new(
71
81
  profile_definition: profile_definition,
82
+ blacklist_definition: blacklist_definition,
72
83
  rule_directory: opts[:rule_directory],
73
84
  allow_suppression: opts[:allow_suppression],
74
85
  print_suppression: opts[:print_suppression],
data/bin/cfn_nag_scan CHANGED
@@ -46,6 +46,11 @@ opts = Trollop.options do
46
46
  type: :io,
47
47
  required: false,
48
48
  default: nil
49
+ opt :blacklist_path,
50
+ 'Path to a blacklist file',
51
+ type: :io,
52
+ required: false,
53
+ default: nil
49
54
  opt :parameter_values_path,
50
55
  'Path to a JSON file to pull Parameter values from',
51
56
  type: :io,
@@ -79,15 +84,21 @@ unless %w[txt json].include?(opts[:output_format])
79
84
  'Must be txt or json')
80
85
  end
81
86
 
82
- CfnNag.configure_logging(opts)
87
+ CfnNagLogging.configure_logging(opts)
83
88
 
84
89
  profile_definition = nil
85
90
  unless opts[:profile_path].nil?
86
91
  profile_definition = IO.read(opts[:profile_path])
87
92
  end
88
93
 
94
+ blacklist_definition = nil
95
+ unless opts[:blacklist_path].nil?
96
+ blacklist_definition = IO.read(opts[:blacklist_path])
97
+ end
98
+
89
99
  cfn_nag = CfnNag.new(
90
100
  profile_definition: profile_definition,
101
+ blacklist_definition: blacklist_definition,
91
102
  rule_directory: opts[:rule_directory],
92
103
  allow_suppression: opts[:allow_suppression],
93
104
  print_suppression: opts[:print_suppression],
data/lib/cfn-nag.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cfn-nag/cfn_nag'
4
+ require 'cfn-nag/cfn_nag_logging'
4
5
  require 'cfn-nag/violation'
5
6
  require 'cfn-nag/rule_dumper'
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ class BlackListLoader
6
+ def initialize(rules_registry)
7
+ @rules_registry = rules_registry
8
+ end
9
+
10
+ def load(blacklist_definition:)
11
+ raise 'Empty profile' if blacklist_definition.strip == ''
12
+
13
+ blacklist_ruleset = RuleIdSet.new
14
+
15
+ blacklist_hash = load_blacklist_yaml(blacklist_definition)
16
+ raise 'Blacklist is malformed' unless blacklist_hash.is_a? Hash
17
+
18
+ rules_to_suppress = blacklist_hash.fetch('RulesToSuppress', {})
19
+ raise 'Missing RulesToSuppress key in black list' if rules_to_suppress.empty?
20
+
21
+ rule_ids_to_suppress = rules_to_suppress.map { |rule| rule['id'] }
22
+ rule_ids_to_suppress.each do |rule_id|
23
+ check_valid_rule_id rule_id
24
+ blacklist_ruleset.add_rule rule_id
25
+ end
26
+
27
+ blacklist_ruleset
28
+ end
29
+
30
+ private
31
+
32
+ def load_blacklist_yaml(blacklist_definition)
33
+ YAML.safe_load(blacklist_definition)
34
+ rescue StandardError => yaml_parse_error
35
+ raise "YAML parse of blacklist failed: #{yaml_parse_error}"
36
+ end
37
+
38
+ def check_valid_rule_id(rule_id)
39
+ return true unless @rules_registry.by_id(rule_id).nil?
40
+
41
+ raise "#{rule_id} is not a legal rule identifier from: #{rules_ids}"
42
+ end
43
+ end
@@ -2,28 +2,34 @@
2
2
 
3
3
  require_relative 'custom_rule_loader'
4
4
  require_relative 'rule_registry'
5
- require_relative 'profile_loader'
5
+ require_relative 'violation_filtering'
6
6
  require_relative 'template_discovery'
7
7
  require_relative 'result_view/simple_stdout_results'
8
8
  require_relative 'result_view/json_results'
9
9
  require 'cfn-model'
10
- require 'logging'
11
10
 
12
11
  # Top-level CfnNag class for running profiles
13
12
  class CfnNag
13
+ include ViolationFiltering
14
+
15
+ # rubocop:disable Metrics/ParameterLists
14
16
  def initialize(profile_definition: nil,
17
+ blacklist_definition: nil,
15
18
  rule_directory: nil,
16
19
  allow_suppression: true,
17
20
  print_suppression: false,
18
21
  isolate_custom_rule_exceptions: false)
19
22
  @rule_directory = rule_directory
20
23
  @custom_rule_loader = CustomRuleLoader.new(
21
- rule_directory: rule_directory, allow_suppression: allow_suppression,
24
+ rule_directory: rule_directory,
25
+ allow_suppression: allow_suppression,
22
26
  print_suppression: print_suppression,
23
27
  isolate_custom_rule_exceptions: isolate_custom_rule_exceptions
24
28
  )
25
29
  @profile_definition = profile_definition
30
+ @blacklist_definition = blacklist_definition
26
31
  end
32
+ # rubocop:enable Metrics/ParameterLists
27
33
 
28
34
  ##
29
35
  # Given a file or directory path, emit aggregate results to stdout
@@ -81,7 +87,8 @@ class CfnNag
81
87
  cfn_model = CfnParser.new.parse cloudformation_string,
82
88
  parameter_values_string
83
89
  violations += @custom_rule_loader.execute_custom_rules(cfn_model)
84
- violations = filter_violations_by_profile violations
90
+
91
+ violations = filter_violations_by_blacklist_and_profile(violations)
85
92
  rescue Psych::SyntaxError, ParserError => parser_error
86
93
  violations << fatal_violation(parser_error.to_s)
87
94
  rescue JSON::ParserError => json_parameters_error
@@ -92,18 +99,26 @@ class CfnNag
92
99
  audit_result(violations)
93
100
  end
94
101
 
95
- def self.configure_logging(opts)
96
- logger = Logging.logger['log']
97
- logger.level = if opts[:debug]
98
- :debug
99
- else
100
- :info
101
- end
102
+ private
102
103
 
103
- logger.add_appenders Logging.appenders.stdout
104
- end
104
+ def filter_violations_by_blacklist_and_profile(violations)
105
+ violations = filter_violations_by_profile(
106
+ profile_definition: @profile_definition,
107
+ rule_definitions: @custom_rule_loader.rule_definitions,
108
+ violations: violations
109
+ )
105
110
 
106
- private
111
+ # this must come after - blacklist should always win
112
+ violations = filter_violations_by_blacklist(
113
+ blacklist_definition: @blacklist_definition,
114
+ rule_definitions: @custom_rule_loader.rule_definitions,
115
+ violations: violations
116
+ )
117
+ violations
118
+ rescue StandardError => blacklist_or_profile_parse_error
119
+ violations << fatal_violation(blacklist_or_profile_parse_error.to_s)
120
+ violations
121
+ end
107
122
 
108
123
  def audit_result(violations)
109
124
  {
@@ -118,18 +133,6 @@ class CfnNag
118
133
  message: message)
119
134
  end
120
135
 
121
- def filter_violations_by_profile(violations)
122
- profile = nil
123
- unless @profile_definition.nil?
124
- profile = ProfileLoader.new(@custom_rule_loader.rule_definitions)
125
- .load(profile_definition: @profile_definition)
126
- end
127
-
128
- violations.reject do |violation|
129
- !profile.nil? && !profile.execute_rule?(violation.id)
130
- end
131
- end
132
-
133
136
  def render_results(aggregate_results:,
134
137
  output_format:)
135
138
  results_renderer(output_format).new.render(aggregate_results)
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logging'
4
+
5
+ class CfnNagLogging
6
+ def self.configure_logging(opts)
7
+ logger = Logging.logger['log']
8
+ logger.level = opts[:debug] ? :debug : :info
9
+ logger.add_appenders Logging.appenders.stdout
10
+ end
11
+ end
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'profile'
3
+ require_relative 'rule_id_set'
4
4
 
5
- # Load rule profile
6
5
  class ProfileLoader
7
6
  def initialize(rules_registry)
8
7
  @rules_registry = rules_registry
@@ -15,7 +14,7 @@ class ProfileLoader
15
14
  profile_definition ||= ''
16
15
  raise 'Empty profile' if profile_definition.strip == ''
17
16
 
18
- new_profile = Profile.new
17
+ new_profile = RuleIdSet.new
19
18
 
20
19
  profile_definition.each_line do |line|
21
20
  next unless (rule_id = rule_line_match(line))
@@ -16,7 +16,7 @@ class RulesView
16
16
  warnings.sort { |left, right| sort_id(left, right) }.each do |warning|
17
17
  if profile.nil?
18
18
  puts "#{warning.id} #{warning.message}"
19
- elsif profile.execute_rule?(warning.id)
19
+ elsif profile.contains_rule?(warning.id)
20
20
  puts "#{warning.id} #{warning.message}"
21
21
  end
22
22
  end
@@ -26,7 +26,7 @@ class RulesView
26
26
  failings.sort { |left, right| sort_id(left, right) }.each do |failing|
27
27
  if profile.nil?
28
28
  puts "#{failing.id} #{failing.message}"
29
- elsif profile.execute_rule?(failing.id)
29
+ elsif profile.contains_rule?(failing.id)
30
30
  puts "#{failing.id} #{failing.message}"
31
31
  end
32
32
  end
@@ -3,7 +3,7 @@
3
3
  require 'set'
4
4
 
5
5
  # Container class for profiles
6
- class Profile
6
+ class RuleIdSet
7
7
  attr_reader :rule_ids
8
8
 
9
9
  def initialize
@@ -16,7 +16,7 @@ class Profile
16
16
  end
17
17
 
18
18
  # Does the list of rule ids contain rule_id?
19
- def execute_rule?(rule_id)
19
+ def contains_rule?(rule_id)
20
20
  @rule_ids.include? rule_id
21
21
  end
22
22
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cfn-nag/profile_loader'
4
+ require 'cfn-nag/blacklist_loader'
5
+
6
+ module ViolationFiltering
7
+ def filter_violations_by_profile(profile_definition:, rule_definitions:, violations:)
8
+ profile = nil
9
+ unless profile_definition.nil?
10
+ begin
11
+ profile = ProfileLoader.new(rule_definitions)
12
+ .load(profile_definition: profile_definition)
13
+ rescue StandardError => profile_load_error
14
+ raise "Profile loading error: #{profile_load_error}"
15
+ end
16
+ end
17
+
18
+ violations.reject do |violation|
19
+ !profile.nil? && !profile.contains_rule?(violation.id)
20
+ end
21
+ end
22
+
23
+ def filter_violations_by_blacklist(blacklist_definition:, rule_definitions:, violations:)
24
+ blacklist = nil
25
+ unless blacklist_definition.nil?
26
+ begin
27
+ blacklist = BlackListLoader.new(rule_definitions)
28
+ .load(blacklist_definition: blacklist_definition)
29
+ rescue StandardError => blacklist_load_error
30
+ raise "Blacklist loading error: #{blacklist_load_error}"
31
+ end
32
+ end
33
+
34
+ violations.reject do |violation|
35
+ !blacklist.nil? && blacklist.contains_rule?(violation.id)
36
+ end
37
+ end
38
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-nag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.73
4
+ version: 0.3.74
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-18 00:00:00.000000000 Z
11
+ date: 2019-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -135,7 +135,9 @@ files:
135
135
  - bin/cfn_nag_rules
136
136
  - bin/cfn_nag_scan
137
137
  - lib/cfn-nag.rb
138
+ - lib/cfn-nag/blacklist_loader.rb
138
139
  - lib/cfn-nag/cfn_nag.rb
140
+ - lib/cfn-nag/cfn_nag_logging.rb
139
141
  - lib/cfn-nag/custom_rule_loader.rb
140
142
  - lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb
141
143
  - lib/cfn-nag/custom_rules/CloudFrontDistributionAccessLoggingRule.rb
@@ -196,16 +198,17 @@ files:
196
198
  - lib/cfn-nag/ip_addr.rb
197
199
  - lib/cfn-nag/jmes_path_discovery.rb
198
200
  - lib/cfn-nag/jmes_path_evaluator.rb
199
- - lib/cfn-nag/profile.rb
200
201
  - lib/cfn-nag/profile_loader.rb
201
202
  - lib/cfn-nag/result_view/json_results.rb
202
203
  - lib/cfn-nag/result_view/rules_view.rb
203
204
  - lib/cfn-nag/result_view/simple_stdout_results.rb
204
205
  - lib/cfn-nag/rule_definition.rb
205
206
  - lib/cfn-nag/rule_dumper.rb
207
+ - lib/cfn-nag/rule_id_set.rb
206
208
  - lib/cfn-nag/rule_registry.rb
207
209
  - lib/cfn-nag/template_discovery.rb
208
210
  - lib/cfn-nag/violation.rb
211
+ - lib/cfn-nag/violation_filtering.rb
209
212
  homepage: https://github.com/stelligent/cfn_nag
210
213
  licenses:
211
214
  - MIT