cfn-nag 0.4.7 → 0.4.8

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: dde33b49425ca0e1a6934b7e12dc42f0c5cd1e31eb3acd68d68855bf9b14eb1b
4
- data.tar.gz: 32aada5f010677e26eb6f9eb78d248bd6c775e3507a1026cc088ec934042dc2f
3
+ metadata.gz: 6d85a44eca7647f151c4cdc8824e7ce8664eeafda1739cbdabeae094ba1a0831
4
+ data.tar.gz: 92375694b6b968bdc588229e7c4d50ae6feba4aeb05b4e7d450d1060444aa938
5
5
  SHA512:
6
- metadata.gz: 0b92f6565787554d80446906103ede76aaa37bc3bdf89b612d6be2c3fa80304b618b7eef8b49f22da7f95648321103b27ce1622b031c3101ce086859d92aa851
7
- data.tar.gz: aaecb9016668eb6193e7bab33df27be0285d35b02b641e54a364d252e9d10aba7fd02ff59df86c8cc31201f2483e296d7ecea64f35be910a36314030c66531c5
6
+ metadata.gz: a95e5fb81745dc369c348acbc0cf2a605e9638bf74a8586c20da8fbc0a1ad24a8d9734226f5cbc805a02edb2bf2b701453649cadad267047ada5ba935407eec4
7
+ data.tar.gz: 121fc4bdc07e51b00cf8fb7b33598a47af5b58b14f5f0f7056b122005b4ebd851feb5831750de0f29ac01187239e395d6cdf0d4460bd7fc7f636bedc351b96f1
@@ -1,110 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'trollop'
5
4
  require 'cfn-nag'
6
5
  require 'logging'
7
6
  require 'json'
8
7
  require 'rubygems/specification'
9
8
 
10
- # rubocop:disable Metrics/BlockLength
11
- opts = Trollop.options do
12
- options_message = '[options] <cloudformation template path ...>|' \
13
- '<cloudformation template in STDIN>'
14
- custom_rule_exceptions_message = 'Isolate custom rule exceptions - ' \
15
- 'just emit the exception without stack ' \
16
- ' trace and keep chugging'
17
- usage options_message
18
- version Gem::Specification.find_by_name('cfn-nag').version
9
+ exec = CfnNagExecutor.new
19
10
 
20
- opt :debug,
21
- 'Enable debug output',
22
- type: :boolean,
23
- required: false,
24
- default: false
25
- opt :allow_suppression,
26
- 'Allow using Metadata to suppress violations',
27
- type: :boolean,
28
- required: false,
29
- default: true
30
- opt :print_suppression,
31
- 'Emit suppressions to stderr',
32
- type: :boolean,
33
- required: false,
34
- default: false
35
- opt :rule_directory,
36
- 'Extra rule directory',
37
- type: :io,
38
- required: false,
39
- default: nil
40
- opt :profile_path,
41
- 'Path to a profile file',
42
- type: :io,
43
- required: false,
44
- default: nil
45
- opt :blacklist_path,
46
- 'Path to a blacklist file',
47
- type: :io,
48
- required: false,
49
- default: nil
50
- opt :parameter_values_path,
51
- 'Path to a JSON file to pull Parameter values from',
52
- type: :io,
53
- required: false,
54
- default: nil
55
- opt :isolate_custom_rule_exceptions,
56
- custom_rule_exceptions_message,
57
- type: :boolean,
58
- required: false,
59
- default: false
60
- opt :fail_on_warnings,
61
- 'Treat warnings as failing violations',
62
- type: :boolean,
63
- required: false,
64
- default: false
65
- end
66
- # rubocop:enable Metrics/BlockLength
67
-
68
- CfnNagLogging.configure_logging(opts)
69
-
70
- profile_definition = nil
71
- unless opts[:profile_path].nil?
72
- profile_definition = IO.read(opts[:profile_path])
73
- end
74
-
75
- blacklist_definition = nil
76
- unless opts[:blacklist_path].nil?
77
- blacklist_definition = IO.read(opts[:blacklist_path])
78
- end
79
-
80
- parameter_values_string = nil
81
- unless opts[:parameter_values_path].nil?
82
- parameter_values_string = IO.read(opts[:parameter_values_path])
83
- end
84
-
85
- cfn_nag = CfnNag.new(
86
- profile_definition: profile_definition,
87
- blacklist_definition: blacklist_definition,
88
- rule_directory: opts[:rule_directory],
89
- allow_suppression: opts[:allow_suppression],
90
- print_suppression: opts[:print_suppression],
91
- isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions]
92
- )
93
-
94
- total_failure_count = 0
95
- until ARGF.closed? || ARGF.eof?
96
- results = cfn_nag.audit(cloudformation_string: ARGF.file.read,
97
- parameter_values_string: parameter_values_string)
98
- ARGF.close
99
-
100
- total_failure_count += if opts[:fail_on_warnings]
101
- results[:violations].length
102
- else
103
- results[:failure_count]
104
- end
105
-
106
- results[:violations] = results[:violations].map(&:to_h)
107
- puts JSON.pretty_generate(results)
108
- end
109
-
110
- exit total_failure_count
11
+ exit exec.scan(options_type: 'file')
@@ -1,113 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'trollop'
5
4
  require 'cfn-nag'
6
5
  require 'logging'
7
6
  require 'json'
8
7
  require 'rubygems/specification'
9
8
 
10
- # rubocop:disable Metrics/BlockLength
11
- opts = Trollop.options do
12
- version Gem::Specification.find_by_name('cfn-nag').version
9
+ exec = CfnNagExecutor.new
13
10
 
14
- input_path_message = 'CloudFormation template to nag on or directory of ' \
15
- 'templates. Default is all *.json, *.yaml, *.yml ' \
16
- 'and *.template recursively, but can be constrained ' \
17
- 'by --template-pattern'
18
-
19
- custom_rule_exceptions_message = 'Isolate custom rule exceptions - just ' \
20
- 'emit the exception without stack trace ' \
21
- 'and keep chugging'
22
-
23
- template_pattern_message = 'Within the --input-path, match files to scan ' \
24
- 'against this regular expression'
25
-
26
- opt :input_path,
27
- input_path_message,
28
- type: :io,
29
- required: true
30
- opt :output_format,
31
- 'Format of results: [txt, json]',
32
- type: :string,
33
- default: 'txt'
34
- opt :debug,
35
- 'Enable debug output',
36
- type: :boolean,
37
- required: false,
38
- default: false
39
- opt :rule_directory,
40
- 'Extra rule directory',
41
- type: :io,
42
- required: false,
43
- default: nil
44
- opt :profile_path,
45
- 'Path to a profile file',
46
- type: :io,
47
- required: false,
48
- default: nil
49
- opt :blacklist_path,
50
- 'Path to a blacklist file',
51
- type: :io,
52
- required: false,
53
- default: nil
54
- opt :parameter_values_path,
55
- 'Path to a JSON file to pull Parameter values from',
56
- type: :io,
57
- required: false,
58
- default: nil
59
- opt :allow_suppression,
60
- 'Allow using Metadata to suppress violations',
61
- type: :boolean,
62
- required: false,
63
- default: true
64
- opt :print_suppression,
65
- 'Emit suppressions to stderr',
66
- type: :boolean,
67
- required: false,
68
- default: false
69
- opt :isolate_custom_rule_exceptions,
70
- custom_rule_exceptions_message,
71
- type: :boolean,
72
- required: false,
73
- default: false
74
- opt :template_pattern,
75
- template_pattern_message,
76
- type: :string,
77
- required: false,
78
- default: '..*\.json|..*\.yaml|..*\.yml|..*\.template'
79
- end
80
- # rubocop:enable Metrics/BlockLength
81
-
82
- unless %w[txt json].include?(opts[:output_format])
83
- Trollop.die(:output_format,
84
- 'Must be txt or json')
85
- end
86
-
87
- CfnNagLogging.configure_logging(opts)
88
-
89
- profile_definition = nil
90
- unless opts[:profile_path].nil?
91
- profile_definition = IO.read(opts[:profile_path])
92
- end
93
-
94
- blacklist_definition = nil
95
- unless opts[:blacklist_path].nil?
96
- blacklist_definition = IO.read(opts[:blacklist_path])
97
- end
98
-
99
- cfn_nag = CfnNag.new(
100
- profile_definition: profile_definition,
101
- blacklist_definition: blacklist_definition,
102
- rule_directory: opts[:rule_directory],
103
- allow_suppression: opts[:allow_suppression],
104
- print_suppression: opts[:print_suppression],
105
- isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions]
106
- )
107
-
108
- exit cfn_nag.audit_aggregate_across_files_and_render_results(
109
- input_path: opts[:input_path],
110
- output_format: opts[:output_format],
111
- parameter_values_path: opts[:parameter_values_path],
112
- template_pattern: opts[:template_pattern]
11
+ exit exec.scan(
12
+ options_type: 'scan'
113
13
  )
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'cfn-nag/cfn_nag'
4
+ require 'cfn-nag/cfn_nag_executor'
4
5
  require 'cfn-nag/cfn_nag_logging'
5
6
  require 'cfn-nag/violation'
6
7
  require 'cfn-nag/rule_dumper'
@@ -12,24 +12,9 @@ require 'cfn-model'
12
12
  class CfnNag
13
13
  include ViolationFiltering
14
14
 
15
- # rubocop:disable Metrics/ParameterLists
16
- def initialize(profile_definition: nil,
17
- blacklist_definition: nil,
18
- rule_directory: nil,
19
- allow_suppression: true,
20
- print_suppression: false,
21
- isolate_custom_rule_exceptions: false)
22
- @rule_directory = rule_directory
23
- @custom_rule_loader = CustomRuleLoader.new(
24
- rule_directory: rule_directory,
25
- allow_suppression: allow_suppression,
26
- print_suppression: print_suppression,
27
- isolate_custom_rule_exceptions: isolate_custom_rule_exceptions
28
- )
29
- @profile_definition = profile_definition
30
- @blacklist_definition = blacklist_definition
15
+ def initialize(config:)
16
+ @config = config
31
17
  end
32
- # rubocop:enable Metrics/ParameterLists
33
18
 
34
19
  ##
35
20
  # Given a file or directory path, emit aggregate results to stdout
@@ -48,7 +33,11 @@ class CfnNag
48
33
  output_format: output_format)
49
34
 
50
35
  aggregate_results.inject(0) do |total_failure_count, results|
51
- total_failure_count + results[:file_results][:failure_count]
36
+ if @config.fail_on_warnings
37
+ total_failure_count + results[:file_results][:violations].length
38
+ else
39
+ total_failure_count + results[:file_results][:failure_count]
40
+ end
52
41
  end
53
42
  end
54
43
 
@@ -87,7 +76,7 @@ class CfnNag
87
76
  cfn_model = CfnParser.new.parse cloudformation_string,
88
77
  parameter_values_string,
89
78
  true
90
- violations += @custom_rule_loader.execute_custom_rules(cfn_model)
79
+ violations += @config.custom_rule_loader.execute_custom_rules(cfn_model)
91
80
 
92
81
  violations = filter_violations_by_blacklist_and_profile(violations)
93
82
  violations = mark_line_numbers(violations, cfn_model)
@@ -115,15 +104,15 @@ class CfnNag
115
104
 
116
105
  def filter_violations_by_blacklist_and_profile(violations)
117
106
  violations = filter_violations_by_profile(
118
- profile_definition: @profile_definition,
119
- rule_definitions: @custom_rule_loader.rule_definitions,
107
+ profile_definition: @config.profile_definition,
108
+ rule_definitions: @config.custom_rule_loader.rule_definitions,
120
109
  violations: violations
121
110
  )
122
111
 
123
112
  # this must come after - blacklist should always win
124
113
  violations = filter_violations_by_blacklist(
125
- blacklist_definition: @blacklist_definition,
126
- rule_definitions: @custom_rule_loader.rule_definitions,
114
+ blacklist_definition: @config.blacklist_definition,
115
+ rule_definitions: @config.custom_rule_loader.rule_definitions,
127
116
  violations: violations
128
117
  )
129
118
  violations
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CfnNagConfig
4
+ # rubocop:disable Metrics/ParameterLists
5
+ def initialize(profile_definition: nil,
6
+ blacklist_definition: nil,
7
+ rule_directory: nil,
8
+ allow_suppression: true,
9
+ print_suppression: false,
10
+ isolate_custom_rule_exceptions: false,
11
+ fail_on_warnings: false)
12
+ @rule_directory = rule_directory
13
+ @custom_rule_loader = CustomRuleLoader.new(
14
+ rule_directory: rule_directory,
15
+ allow_suppression: allow_suppression,
16
+ print_suppression: print_suppression,
17
+ isolate_custom_rule_exceptions: isolate_custom_rule_exceptions
18
+ )
19
+ @profile_definition = profile_definition
20
+ @blacklist_definition = blacklist_definition
21
+ @fail_on_warnings = fail_on_warnings
22
+ end
23
+ # rubocop:enable Metrics/ParameterLists
24
+
25
+ attr_reader :rule_directory
26
+ attr_reader :custom_rule_loader
27
+ attr_reader :profile_definition
28
+ attr_reader :blacklist_definition
29
+ attr_reader :fail_on_warnings
30
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'trollop'
4
+ require 'cfn-nag/cli_options'
5
+ require 'cfn-nag/cfn_nag_config'
6
+
7
+ class CfnNagExecutor
8
+ def initialize
9
+ @profile_definition = nil
10
+ @blacklist_definition = nil
11
+ @parameter_values_string = nil
12
+ end
13
+
14
+ def scan(options_type:)
15
+ options = Options.for(options_type)
16
+ validate_options(options)
17
+ execute_io_options(options)
18
+
19
+ CfnNagLogging.configure_logging(options)
20
+
21
+ cfn_nag = CfnNag.new(
22
+ config: cfn_nag_config(options)
23
+ )
24
+
25
+ options_type == 'scan' ? execute_aggregate_scan(cfn_nag, options) : execute_file_or_piped_scan(cfn_nag, options)
26
+ end
27
+
28
+ private
29
+
30
+ def execute_file_or_piped_scan(cfn_nag, opts)
31
+ total_failure_count = 0
32
+ until argf_finished?
33
+ results = cfn_nag.audit(cloudformation_string: argf_read,
34
+ parameter_values_string: @parameter_values_string)
35
+ argf_close
36
+
37
+ total_failure_count += if opts[:fail_on_warnings]
38
+ results[:violations].length
39
+ else
40
+ results[:failure_count]
41
+ end
42
+
43
+ results[:violations] = results[:violations].map(&:to_h)
44
+ puts JSON.pretty_generate(results)
45
+ end
46
+ total_failure_count
47
+ end
48
+
49
+ def execute_aggregate_scan(cfn_nag, opts)
50
+ cfn_nag.audit_aggregate_across_files_and_render_results(
51
+ input_path: opts[:input_path],
52
+ output_format: opts[:output_format],
53
+ parameter_values_path: opts[:parameter_values_path],
54
+ template_pattern: opts[:template_pattern]
55
+ )
56
+ end
57
+
58
+ def validate_options(opts)
59
+ unless opts[:output_format].nil? || %w[txt json].include?(opts[:output_format])
60
+ Trollop.die(:output_format,
61
+ 'Must be txt or json')
62
+ end
63
+ end
64
+
65
+ def execute_io_options(opts)
66
+ unless opts[:profile_path].nil?
67
+ @profile_definition = IO.read(opts[:profile_path])
68
+ end
69
+
70
+ unless opts[:blacklist_path].nil?
71
+ @blacklist_definition = IO.read(opts[:blacklist_path])
72
+ end
73
+
74
+ unless opts[:parameter_values_path].nil?
75
+ @parameter_values_string = IO.read(opts[:parameter_values_path])
76
+ end
77
+ end
78
+
79
+ def cfn_nag_config(opts)
80
+ CfnNagConfig.new(
81
+ profile_definition: @profile_definition,
82
+ blacklist_definition: @blacklist_definition,
83
+ rule_directory: opts[:rule_directory],
84
+ allow_suppression: opts[:allow_suppression],
85
+ print_suppression: opts[:print_suppression],
86
+ isolate_custom_rule_exceptions: opts[:isolate_custom_rule_exceptions],
87
+ fail_on_warnings: opts[:fail_on_warnings]
88
+ )
89
+ end
90
+
91
+ def argf_finished?
92
+ ARGF.closed? || ARGF.eof?
93
+ end
94
+
95
+ def argf_close
96
+ ARGF.close
97
+ end
98
+
99
+ def argf_read
100
+ ARGF.file.read
101
+ end
102
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'trollop'
4
+
5
+ # rubocop:disable Metrics/ClassLength
6
+ class Options
7
+ @custom_rule_exceptions_message = 'Isolate custom rule exceptions - just ' \
8
+ 'emit the exception without stack trace ' \
9
+ 'and keep chugging'
10
+
11
+ @version = Gem::Specification.find_by_name('cfn-nag').version
12
+
13
+ def self.for(type)
14
+ case type
15
+ when 'file'
16
+ file_options
17
+ when 'scan'
18
+ scan_options
19
+ else
20
+ raise "Unsupported Options type #{type}; use 'file' or 'scan'"
21
+ end
22
+ end
23
+
24
+ # rubocop:disable Metrics/BlockLength
25
+ # rubocop:disable Metrics/MethodLength
26
+ def self.file_options
27
+ options_message = '[options] <cloudformation template path ...>|' \
28
+ '<cloudformation template in STDIN>'
29
+ custom_rule_exceptions_message = @custom_rule_exceptions_message
30
+ version = @version
31
+
32
+ Trollop.options do
33
+ usage options_message
34
+ version version
35
+
36
+ opt :debug,
37
+ 'Enable debug output',
38
+ type: :boolean,
39
+ required: false,
40
+ default: false
41
+ opt :allow_suppression,
42
+ 'Allow using Metadata to suppress violations',
43
+ type: :boolean,
44
+ required: false,
45
+ default: true
46
+ opt :print_suppression,
47
+ 'Emit suppressions to stderr',
48
+ type: :boolean,
49
+ required: false,
50
+ default: false
51
+ opt :rule_directory,
52
+ 'Extra rule directory',
53
+ type: :io,
54
+ required: false,
55
+ default: nil
56
+ opt :profile_path,
57
+ 'Path to a profile file',
58
+ type: :io,
59
+ required: false,
60
+ default: nil
61
+ opt :blacklist_path,
62
+ 'Path to a blacklist file',
63
+ type: :io,
64
+ required: false,
65
+ default: nil
66
+ opt :parameter_values_path,
67
+ 'Path to a JSON file to pull Parameter values from',
68
+ type: :io,
69
+ required: false,
70
+ default: nil
71
+ opt :isolate_custom_rule_exceptions,
72
+ custom_rule_exceptions_message,
73
+ type: :boolean,
74
+ required: false,
75
+ default: false
76
+ opt :fail_on_warnings,
77
+ 'Treat warnings as failing violations',
78
+ type: :boolean,
79
+ required: false,
80
+ default: false
81
+ opt :output_format,
82
+ 'Format of results: [txt, json]',
83
+ type: :string,
84
+ default: 'txt'
85
+ end
86
+ end
87
+
88
+ def self.scan_options
89
+ input_path_message = 'CloudFormation template to nag on or directory of ' \
90
+ 'templates. Default is all *.json, *.yaml, *.yml ' \
91
+ 'and *.template recursively, but can be constrained ' \
92
+ 'by --template-pattern'
93
+
94
+ template_pattern_message = 'Within the --input-path, match files to scan ' \
95
+ 'against this regular expression'
96
+
97
+ custom_rule_exceptions_message = @custom_rule_exceptions_message
98
+ version = @version
99
+
100
+ Trollop.options do
101
+ version version
102
+ opt :input_path,
103
+ input_path_message,
104
+ type: :io,
105
+ required: true
106
+ opt :output_format,
107
+ 'Format of results: [txt, json]',
108
+ type: :string,
109
+ default: 'txt'
110
+ opt :debug,
111
+ 'Enable debug output',
112
+ type: :boolean,
113
+ required: false,
114
+ default: false
115
+ opt :rule_directory,
116
+ 'Extra rule directory',
117
+ type: :io,
118
+ required: false,
119
+ default: nil
120
+ opt :profile_path,
121
+ 'Path to a profile file',
122
+ type: :io,
123
+ required: false,
124
+ default: nil
125
+ opt :blacklist_path,
126
+ 'Path to a blacklist file',
127
+ type: :io,
128
+ required: false,
129
+ default: nil
130
+ opt :parameter_values_path,
131
+ 'Path to a JSON file to pull Parameter values from',
132
+ type: :io,
133
+ required: false,
134
+ default: nil
135
+ opt :allow_suppression,
136
+ 'Allow using Metadata to suppress violations',
137
+ type: :boolean,
138
+ required: false,
139
+ default: true
140
+ opt :print_suppression,
141
+ 'Emit suppressions to stderr',
142
+ type: :boolean,
143
+ required: false,
144
+ default: false
145
+ opt :isolate_custom_rule_exceptions,
146
+ custom_rule_exceptions_message,
147
+ type: :boolean,
148
+ required: false,
149
+ default: false
150
+ opt :template_pattern,
151
+ template_pattern_message,
152
+ type: :string,
153
+ required: false,
154
+ default: '..*\.json|..*\.yaml|..*\.yml|..*\.template'
155
+ opt :fail_on_warnings,
156
+ 'Treat warnings as failing violations',
157
+ type: :boolean,
158
+ required: false,
159
+ default: false
160
+ end
161
+ end
162
+ # rubocop:enable Metrics/BlockLength
163
+ # rubocop:enable Metrics/MethodLength
164
+ end
165
+ # rubocop:enable Metrics/ClassLength
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cfn-nag
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kascic
@@ -151,7 +151,10 @@ files:
151
151
  - lib/cfn-nag.rb
152
152
  - lib/cfn-nag/blacklist_loader.rb
153
153
  - lib/cfn-nag/cfn_nag.rb
154
+ - lib/cfn-nag/cfn_nag_config.rb
155
+ - lib/cfn-nag/cfn_nag_executor.rb
154
156
  - lib/cfn-nag/cfn_nag_logging.rb
157
+ - lib/cfn-nag/cli_options.rb
155
158
  - lib/cfn-nag/custom_rule_loader.rb
156
159
  - lib/cfn-nag/custom_rules/BatchJobDefinitionContainerPropertiesPrivilegedRule.rb
157
160
  - lib/cfn-nag/custom_rules/CloudFormationAuthenticationRule.rb