cfn-nag 0.8.1 → 0.8.2

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: 8aceb287830823e0d3aa5f6254e14e5d12fd5405c48ec9d41ce1e098023320cf
4
- data.tar.gz: 8137ee2a1a7282e2025d6659229b1a9d1eb6e01a7db51c727dd6d37f0acda745
3
+ metadata.gz: d0dd505f40c9fd504634b10223a8742375032a6fd225febe29460692dae4b5d2
4
+ data.tar.gz: 6e535f22dde6837b2384a94a95f1a115ca0ec89c30450793ae490b092d034622
5
5
  SHA512:
6
- metadata.gz: 9000f354e1fc834f08d6688580f8f79fa0846a4d2ff9c54bdc5995eae0fd3cad8a7f003178565da1209d1067585e1ba6d841f90c6e991891ad0b0a5b8714b98d
7
- data.tar.gz: 8c726d52d37b174b91c3eb0abe6c97cd946ce324ad20bf63d75bc176661aa9af782d8a9e69a589368d4859fbb68bdd73af541e27e9020aba267756cf1de6187f
6
+ metadata.gz: 0d75d174639ebf1056c2add11c6acca90f273d545dd825703a710b1e15c0483c90dee85a161d4c7d4b6261371ac7d3ec1b6df3f80facbec2f59cb0adf683b060
7
+ data.tar.gz: cd3d89960bf8662a99e2a6e180c46ad587413872e30085e77b7db625a46a1e9d0d8d7a742debe3cdd7b8f8f51bc07190696eb9271479cf0ce13ee8b707320e05
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
@@ -96,10 +97,10 @@ class CfnNag
96
97
  violations = filter_violations_by_deny_list_and_profile(violations)
97
98
  violations = mark_line_numbers(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,7 +113,7 @@ 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
@@ -141,7 +142,7 @@ class CfnNag
141
142
  violations: violations
142
143
  )
143
144
  rescue StandardError => deny_list_or_profile_parse_error
144
- violations << fatal_violation(deny_list_or_profile_parse_error.to_s)
145
+ violations << Violation.fatal_violation(deny_list_or_profile_parse_error.to_s)
145
146
  violations
146
147
  end
147
148
 
@@ -152,17 +153,12 @@ class CfnNag
152
153
  }
153
154
  end
154
155
 
155
- def fatal_violation(message)
156
- Violation.new(id: 'FATAL',
157
- type: Violation::FAILING_VIOLATION,
158
- message: message)
159
- end
160
-
161
156
  def results_renderer(output_format)
162
157
  registry = {
163
158
  'colortxt' => ColoredStdoutResults,
164
159
  'txt' => SimpleStdoutResults,
165
- 'json' => JsonResults
160
+ 'json' => JsonResults,
161
+ 'sarif' => SarifResults
166
162
  }
167
163
  registry[output_format]
168
164
  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,15 @@ 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 = [])
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)
26
32
  end
27
33
  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
@@ -24,7 +24,7 @@ class StdoutResults
24
24
  puts "Warnings count: #{Violation.count_warnings(violations)}"
25
25
  end
26
26
 
27
- def render(results)
27
+ def render(results, _rule_definitions)
28
28
  results.each do |result|
29
29
  60.times { print '-' }
30
30
  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.2'
6
+ end
@@ -6,18 +6,22 @@ require_relative 'rule_definition'
6
6
  class Violation < RuleDefinition
7
7
  attr_reader :logical_resource_ids, :line_numbers
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
15
  line_numbers: [])
14
16
  super id: id,
17
+ name: name,
15
18
  type: type,
16
19
  message: message
17
20
 
18
21
  @logical_resource_ids = logical_resource_ids
19
22
  @line_numbers = line_numbers
20
23
  end
24
+ # rubocop:enable Metrics/ParameterLists
21
25
 
22
26
  def to_s
23
27
  "#{super} #{@logical_resource_ids}"
@@ -57,6 +61,13 @@ class Violation < RuleDefinition
57
61
  end
58
62
  end
59
63
 
64
+ def fatal_violation(message)
65
+ Violation.new(id: 'FATAL',
66
+ name: 'system',
67
+ type: Violation::FAILING_VIOLATION,
68
+ message: message)
69
+ end
70
+
60
71
  private
61
72
 
62
73
  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.2
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-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -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