cfn-nag 0.8.1 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8aceb287830823e0d3aa5f6254e14e5d12fd5405c48ec9d41ce1e098023320cf
4
- data.tar.gz: 8137ee2a1a7282e2025d6659229b1a9d1eb6e01a7db51c727dd6d37f0acda745
3
+ metadata.gz: c39c81a107025c553d08bce79ffdf244838c3e26fd1a853814f367a1abf732a7
4
+ data.tar.gz: d000e3ff73010f5796d2821a30d94dd361607384aaafeab64843af3d54913e3b
5
5
  SHA512:
6
- metadata.gz: 9000f354e1fc834f08d6688580f8f79fa0846a4d2ff9c54bdc5995eae0fd3cad8a7f003178565da1209d1067585e1ba6d841f90c6e991891ad0b0a5b8714b98d
7
- data.tar.gz: 8c726d52d37b174b91c3eb0abe6c97cd946ce324ad20bf63d75bc176661aa9af782d8a9e69a589368d4859fbb68bdd73af541e27e9020aba267756cf1de6187f
6
+ metadata.gz: 5d3b5cea49310d56c8735e16b49ca7bbbd605d8d00dd52bb1f243d1a39c52f3b9d01db3089fd248006939c873f33706fef01d014d0b7fc87095683eb62e3c20d
7
+ data.tar.gz: cc016234fbbc9c19c39ff7655667f58961a7abfd236285c4a148b13f846130f6fc007a3eabc8c7f9bd523363d1759749f889d453104a5dc9f165775318cdcd4a
data/bin/cfn_nag_rules CHANGED
@@ -6,7 +6,7 @@ require 'cfn-nag'
6
6
  require 'rubygems/specification'
7
7
 
8
8
  opts = Optimist.options do
9
- version Gem::Specification.find_by_name('cfn-nag').version
9
+ version CfnNagVersion::VERSION
10
10
 
11
11
  opt :rule_directory, 'Extra rule directories', type: :io,
12
12
  required: false,
@@ -20,10 +20,16 @@ class CfnNag
20
20
  logical_resource_ids = audit_impl(cfn_model)
21
21
  return if logical_resource_ids.empty?
22
22
 
23
+ violation(logical_resource_ids)
24
+ end
25
+
26
+ def violation(logical_resource_ids, line_numbers = nil)
23
27
  Violation.new(id: rule_id,
28
+ name: self.class.name,
24
29
  type: rule_type,
25
30
  message: rule_text,
26
- logical_resource_ids: logical_resource_ids)
31
+ logical_resource_ids: logical_resource_ids,
32
+ line_numbers: line_numbers)
27
33
  end
28
34
  end
29
35
  end
@@ -8,6 +8,7 @@ require_relative 'result_view/stdout_results'
8
8
  require_relative 'result_view/simple_stdout_results'
9
9
  require_relative 'result_view/colored_stdout_results'
10
10
  require_relative 'result_view/json_results'
11
+ require_relative 'result_view/sarif_results'
11
12
  require 'cfn-model'
12
13
 
13
14
  # Top-level CfnNag class for running profiles
@@ -94,12 +95,12 @@ class CfnNag
94
95
  )
95
96
 
96
97
  violations = filter_violations_by_deny_list_and_profile(violations)
97
- violations = mark_line_numbers(violations, cfn_model)
98
+ violations = mark_line_numbers_and_element_types(violations, cfn_model)
98
99
  rescue RuleRepoException, Psych::SyntaxError, ParserError => fatal_error
99
- violations << fatal_violation(fatal_error.to_s)
100
+ violations << Violation.fatal_violation(fatal_error.to_s)
100
101
  rescue JSON::ParserError => json_parameters_error
101
102
  error = "JSON Parameter values parse error: #{json_parameters_error}"
102
- violations << fatal_violation(error)
103
+ violations << Violation.fatal_violation(error)
103
104
  end
104
105
 
105
106
  violations = prune_fatal_violations(violations) if @config.ignore_fatal
@@ -112,15 +113,16 @@ class CfnNag
112
113
 
113
114
  def render_results(aggregate_results:,
114
115
  output_format:)
115
- results_renderer(output_format).new.render(aggregate_results)
116
+ results_renderer(output_format).new.render(aggregate_results, @config.custom_rule_loader.rule_definitions)
116
117
  end
117
118
 
118
119
  private
119
120
 
120
- def mark_line_numbers(violations, cfn_model)
121
+ def mark_line_numbers_and_element_types(violations, cfn_model)
121
122
  violations.each do |violation|
122
123
  violation.logical_resource_ids.each do |logical_resource_id|
123
124
  violation.line_numbers << cfn_model.line_numbers[logical_resource_id]
125
+ violation.element_types << cfn_model.element_types[logical_resource_id]
124
126
  end
125
127
  end
126
128
 
@@ -141,7 +143,7 @@ class CfnNag
141
143
  violations: violations
142
144
  )
143
145
  rescue StandardError => deny_list_or_profile_parse_error
144
- violations << fatal_violation(deny_list_or_profile_parse_error.to_s)
146
+ violations << Violation.fatal_violation(deny_list_or_profile_parse_error.to_s)
145
147
  violations
146
148
  end
147
149
 
@@ -152,17 +154,12 @@ class CfnNag
152
154
  }
153
155
  end
154
156
 
155
- def fatal_violation(message)
156
- Violation.new(id: 'FATAL',
157
- type: Violation::FAILING_VIOLATION,
158
- message: message)
159
- end
160
-
161
157
  def results_renderer(output_format)
162
158
  registry = {
163
159
  'colortxt' => ColoredStdoutResults,
164
160
  'txt' => SimpleStdoutResults,
165
- 'json' => JsonResults
161
+ 'json' => JsonResults,
162
+ 'sarif' => SarifResults
166
163
  }
167
164
  registry[output_format]
168
165
  end
@@ -74,9 +74,9 @@ class CfnNagExecutor
74
74
  end
75
75
 
76
76
  def validate_options(opts)
77
- unless opts[:output_format].nil? || %w[colortxt txt json].include?(opts[:output_format])
77
+ unless opts[:output_format].nil? || %w[colortxt txt json sarif].include?(opts[:output_format])
78
78
  Optimist.die(:output_format,
79
- 'Must be colortxt, txt, or json')
79
+ 'Must be colortxt, txt, json or sarif')
80
80
  end
81
81
 
82
82
  opts[:rule_arguments]&.each do |rule_argument|
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optimist'
4
+ require_relative 'version'
4
5
 
5
6
  # rubocop:disable Metrics/ClassLength
6
7
  class Options
@@ -8,7 +9,7 @@ class Options
8
9
  'emit the exception without stack trace ' \
9
10
  'and keep chugging'
10
11
 
11
- @version = Gem::Specification.find_by_name('cfn-nag').version
12
+ @version = CfnNagVersion::VERSION
12
13
 
13
14
  def self.for(type)
14
15
  case type
@@ -89,7 +90,7 @@ class Options
89
90
  required: false,
90
91
  default: false
91
92
  opt :output_format,
92
- 'Format of results: [txt, json, colortxt]',
93
+ 'Format of results: [txt, json, colortxt, sarif]',
93
94
  type: :string,
94
95
  default: 'colortxt'
95
96
  opt :rule_repository,
@@ -132,7 +133,7 @@ class Options
132
133
  type: :string,
133
134
  required: true
134
135
  opt :output_format,
135
- 'Format of results: [txt, json, colortxt]',
136
+ 'Format of results: [txt, json, colortxt, sarif]',
136
137
  type: :string,
137
138
  default: 'colortxt'
138
139
  opt :debug,
@@ -19,9 +19,16 @@ class BaseRule
19
19
  logical_resource_ids = audit_impl(cfn_model)
20
20
  return if logical_resource_ids.empty?
21
21
 
22
+ violation(logical_resource_ids)
23
+ end
24
+
25
+ def violation(logical_resource_ids, line_numbers = [], element_types = [])
22
26
  Violation.new(id: rule_id,
27
+ name: self.class.name,
23
28
  type: rule_type,
24
29
  message: rule_text,
25
- logical_resource_ids: logical_resource_ids)
30
+ logical_resource_ids: logical_resource_ids,
31
+ line_numbers: line_numbers,
32
+ element_types: element_types)
26
33
  end
27
34
  end
@@ -10,7 +10,8 @@ class ColoredStdoutResults < StdoutResults
10
10
  color:,
11
11
  message:,
12
12
  logical_resource_ids: nil,
13
- line_numbers: [])
13
+ line_numbers: [],
14
+ element_types: [])
14
15
 
15
16
  logical_resource_ids = nil if logical_resource_ids == []
16
17
 
@@ -18,7 +19,7 @@ class ColoredStdoutResults < StdoutResults
18
19
  puts
19
20
  puts colorize(color, "| #{message_type.upcase}")
20
21
  puts colorize(color, '|')
21
- puts colorize(color, "| Resources: #{logical_resource_ids}") unless logical_resource_ids.nil?
22
+ puts colorize(color, "| #{element_type(element_types)}: #{logical_resource_ids}") unless logical_resource_ids.nil?
22
23
  puts colorize(color, "| Line Numbers: #{line_numbers}") unless line_numbers.empty?
23
24
  puts colorize(color, '|') unless line_numbers.empty? && logical_resource_ids.nil?
24
25
  puts colorize(color, "| #{message}")
@@ -38,4 +39,12 @@ class ColoredStdoutResults < StdoutResults
38
39
  def colorize(color_symbol, str)
39
40
  "\e[#{color_code(color_symbol)}m#{str}\e[0m"
40
41
  end
42
+
43
+ def element_type(element_types)
44
+ if element_types == [] || element_types.first.nil?
45
+ 'Element'
46
+ elsif !element_types.first.nil?
47
+ element_types.first.capitalize
48
+ end
49
+ end
41
50
  end
@@ -3,7 +3,7 @@
3
3
  require 'json'
4
4
 
5
5
  class JsonResults
6
- def render(results)
6
+ def render(results, _rule_registry)
7
7
  hashified_results = results.each do |result|
8
8
  result[:file_results][:violations] = result[:file_results][:violations].map(&:to_h)
9
9
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'pathname'
5
+
6
+ class SarifResults
7
+ def render(results, rule_registry)
8
+ sarif_results = []
9
+ results.each do |file|
10
+ # For each file in the results, review the violations
11
+ file[:file_results][:violations].each do |violation|
12
+ # For each violation, generate a sarif result for each logical resource id in the violation
13
+ violation.logical_resource_ids.each_with_index do |_logical_resource_id, index|
14
+ sarif_results << sarif_result(file_name: file[:filename], violation: violation, index: index)
15
+ end
16
+ end
17
+ end
18
+
19
+ sarif_report = {
20
+ version: '2.1.0',
21
+ '$schema': 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
22
+ runs: [
23
+ tool: {
24
+ driver: driver(rule_registry.rules)
25
+ },
26
+ results: sarif_results
27
+ ]
28
+ }
29
+
30
+ puts JSON.pretty_generate(sarif_report)
31
+ end
32
+
33
+ # Generates a SARIF driver object, which describes the tool and the rules used
34
+ def driver(rules)
35
+ {
36
+ name: 'cfn_nag',
37
+ informationUri: 'https://github.com/stelligent/cfn_nag',
38
+ semanticVersion: CfnNagVersion::VERSION,
39
+ rules: rules.map do |rule_definition|
40
+ {
41
+ id: "CFN_NAG_#{rule_definition.id}",
42
+ name: rule_definition.name,
43
+ fullDescription: {
44
+ text: rule_definition.message
45
+ }
46
+ }
47
+ end
48
+ }
49
+ end
50
+
51
+ # Given a cfn_nag Violation object, and index, generates a SARIF result object for the finding
52
+ def sarif_result(file_name:, violation:, index:)
53
+ {
54
+ ruleId: "CFN_NAG_#{violation.id}",
55
+ level: sarif_level(violation.type),
56
+ message: {
57
+ text: violation.message
58
+ },
59
+ locations: [
60
+ {
61
+ physicalLocation: {
62
+ artifactLocation: {
63
+ uri: relative_path(file_name),
64
+ uriBaseId: '%SRCROOT%'
65
+ },
66
+ region: {
67
+ startLine: sarif_line_number(violation.line_numbers[index])
68
+ }
69
+ },
70
+ logicalLocations: [
71
+ {
72
+ name: violation.logical_resource_ids[index]
73
+ }
74
+ ]
75
+ }
76
+ ]
77
+ }
78
+ end
79
+
80
+ # Line number defaults to 1 unless provided with valid number
81
+ def sarif_line_number(line_number)
82
+ line_number.nil? || line_number.to_i < 1 ? 1 : line_number.to_i
83
+ end
84
+
85
+ def sarif_level(violation_type)
86
+ case violation_type
87
+ when RuleDefinition::WARNING
88
+ 'warning'
89
+ else
90
+ 'error'
91
+ end
92
+ end
93
+
94
+ def relative_path(file_name)
95
+ file_pathname = Pathname.new(file_name)
96
+
97
+ if file_pathname.relative?
98
+ file_pathname.to_s
99
+ else
100
+ file_pathname.relative_path_from(Pathname.pwd).to_s
101
+ end
102
+ end
103
+ end
@@ -11,7 +11,8 @@ class SimpleStdoutResults < StdoutResults
11
11
  message:,
12
12
  color:,
13
13
  logical_resource_ids: nil,
14
- line_numbers: [])
14
+ line_numbers: [],
15
+ element_types: [])
15
16
 
16
17
  logical_resource_ids = nil if logical_resource_ids == []
17
18
 
@@ -19,10 +20,18 @@ class SimpleStdoutResults < StdoutResults
19
20
  puts
20
21
  puts "| #{message_type.upcase}"
21
22
  puts '|'
22
- puts "| Resources: #{logical_resource_ids}" unless logical_resource_ids.nil?
23
+ puts "| #{element_type(element_types)}: #{logical_resource_ids}" unless logical_resource_ids.nil?
23
24
  puts "| Line Numbers: #{line_numbers}" unless line_numbers.empty?
24
25
  puts '|' unless line_numbers.empty? && logical_resource_ids.nil?
25
26
  puts "| #{message}"
26
27
  end
27
28
  # rubocop:enable Lint/UnusedMethodArgument
29
+
30
+ def element_type(element_types)
31
+ if element_types == [] || element_types.first.nil?
32
+ 'Element'
33
+ elsif !element_types.first.nil?
34
+ element_types.first.capitalize
35
+ end
36
+ end
28
37
  end
@@ -12,7 +12,8 @@ class StdoutResults
12
12
  color: color,
13
13
  message: violation.message,
14
14
  logical_resource_ids: violation.logical_resource_ids,
15
- line_numbers: violation.line_numbers
15
+ line_numbers: violation.line_numbers,
16
+ element_types: violation.element_types
16
17
  end
17
18
  end
18
19
 
@@ -24,7 +25,7 @@ class StdoutResults
24
25
  puts "Warnings count: #{Violation.count_warnings(violations)}"
25
26
  end
26
27
 
27
- def render(results)
28
+ def render(results, _rule_definitions)
28
29
  results.each do |result|
29
30
  60.times { print '-' }
30
31
  puts "\n#{result[:filename]}"
@@ -4,27 +4,30 @@ class RuleDefinition
4
4
  WARNING = 'WARN'
5
5
  FAILING_VIOLATION = 'FAIL'
6
6
 
7
- attr_reader :id, :type, :message
7
+ attr_reader :id, :name, :type, :message
8
8
 
9
9
  def initialize(id:,
10
+ name:,
10
11
  type:,
11
12
  message:)
12
13
  @id = id
14
+ @name = name
13
15
  @type = type
14
16
  @message = message
15
17
 
16
- [@id, @type, @message].each do |required|
18
+ [@id, @type, @name, @message].each do |required|
17
19
  raise 'No parameters to Violation constructor can be nil' if required.nil?
18
20
  end
19
21
  end
20
22
 
21
23
  def to_s
22
- "#{@id} #{@type} #{@message}"
24
+ "#{@id} #{name} #{@type} #{@message}"
23
25
  end
24
26
 
25
27
  def to_h
26
28
  {
27
29
  id: @id,
30
+ name: @name,
28
31
  type: @type,
29
32
  message: @message
30
33
  }
@@ -43,6 +43,7 @@ class RuleRegistry
43
43
  if existing_def.nil?
44
44
  rule_definition = RuleDefinition.new(
45
45
  id: rule.rule_id,
46
+ name: rule_class.name,
46
47
  type: rule.rule_type,
47
48
  message: rule.rule_text
48
49
  )
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CfnNagVersion
4
+ # This is managed at release time via scripts/publish.sh
5
+ VERSION = '0.8.5'
6
+ end
@@ -4,20 +4,26 @@ require_relative 'rule_definition'
4
4
 
5
5
  # Rule definition for violations
6
6
  class Violation < RuleDefinition
7
- attr_reader :logical_resource_ids, :line_numbers
7
+ attr_reader :logical_resource_ids, :line_numbers, :element_types
8
8
 
9
+ # rubocop:disable Metrics/ParameterLists
9
10
  def initialize(id:,
11
+ name:,
10
12
  type:,
11
13
  message:,
12
14
  logical_resource_ids: [],
13
- line_numbers: [])
15
+ line_numbers: [],
16
+ element_types: [])
14
17
  super id: id,
18
+ name: name,
15
19
  type: type,
16
20
  message: message
17
21
 
18
22
  @logical_resource_ids = logical_resource_ids
19
23
  @line_numbers = line_numbers
24
+ @element_types = element_types
20
25
  end
26
+ # rubocop:enable Metrics/ParameterLists
21
27
 
22
28
  def to_s
23
29
  "#{super} #{@logical_resource_ids}"
@@ -26,7 +32,8 @@ class Violation < RuleDefinition
26
32
  def to_h
27
33
  super.to_h.merge(
28
34
  logical_resource_ids: @logical_resource_ids,
29
- line_numbers: @line_numbers
35
+ line_numbers: @line_numbers,
36
+ element_types: @element_types
30
37
  )
31
38
  end
32
39
 
@@ -57,6 +64,13 @@ class Violation < RuleDefinition
57
64
  end
58
65
  end
59
66
 
67
+ def fatal_violation(message)
68
+ Violation.new(id: 'FATAL',
69
+ name: 'system',
70
+ type: Violation::FAILING_VIOLATION,
71
+ message: message)
72
+ end
73
+
60
74
  private
61
75
 
62
76
  def empty?(array)
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.8.1
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-15 00:00:00.000000000 Z
11
+ date: 2021-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.6.4
75
+ version: 0.6.6
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '='
81
81
  - !ruby/object:Gem::Version
82
- version: 0.6.4
82
+ version: 0.6.6
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: logging
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -371,6 +371,7 @@ files:
371
371
  - lib/cfn-nag/result_view/colored_stdout_results.rb
372
372
  - lib/cfn-nag/result_view/json_results.rb
373
373
  - lib/cfn-nag/result_view/rules_view.rb
374
+ - lib/cfn-nag/result_view/sarif_results.rb
374
375
  - lib/cfn-nag/result_view/simple_stdout_results.rb
375
376
  - lib/cfn-nag/result_view/stdout_results.rb
376
377
  - lib/cfn-nag/rule_definition.rb
@@ -388,6 +389,7 @@ files:
388
389
  - lib/cfn-nag/util/enforce_string_or_dynamic_reference.rb
389
390
  - lib/cfn-nag/util/truthy.rb
390
391
  - lib/cfn-nag/util/wildcard_patterns.rb
392
+ - lib/cfn-nag/version.rb
391
393
  - lib/cfn-nag/violation.rb
392
394
  - lib/cfn-nag/violation_filtering.rb
393
395
  homepage: https://github.com/stelligent/cfn_nag