class CfnNag

Base class all Rules should subclass

Top-level CfnNag class for running profiles

Constants

DEFAULT_TEMPLATE_PATTERN

Public Class Methods

new(config:) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 19
def initialize(config:)
  @config = config
end

Public Instance Methods

audit(cloudformation_string:, parameter_values_string: nil, condition_values_string: nil) click to toggle source

Given cloudformation json/yml, run all the rules against it

Optionally include JSON with Parameters key to substitute into cfn_model.parameters

Return a hash with failure count

# File lib/cfn-nag/cfn_nag.rb, line 83
def audit(cloudformation_string:, parameter_values_string: nil, condition_values_string: nil)
  violations = []
  begin
    cfn_model = CfnParser.new.parse cloudformation_string,
                                    parameter_values_string,
                                    true,
                                    condition_values_string
    CustomRuleLoader.rule_arguments = @config.rule_arguments
    violations += @config.custom_rule_loader.execute_custom_rules(
      cfn_model,
      @config.custom_rule_loader.rule_definitions
    )

    violations = filter_violations_by_blacklist_and_profile(violations)
    violations = mark_line_numbers(violations, cfn_model)
  rescue RuleRepoException, Psych::SyntaxError, ParserError => fatal_error
    violations << fatal_violation(fatal_error.to_s)
  rescue JSON::ParserError => json_parameters_error
    error = "JSON Parameter values parse error: #{json_parameters_error}"
    violations << fatal_violation(error)
  end

  violations = prune_fatal_violations(violations) if @config.ignore_fatal
  audit_result(violations)
end
audit_aggregate_across_files(input_path:, parameter_values_path: nil, condition_values_path: nil, template_pattern: DEFAULT_TEMPLATE_PATTERN) click to toggle source

Given a file or directory path, return aggregate results

# File lib/cfn-nag/cfn_nag.rb, line 54
def audit_aggregate_across_files(input_path:,
                                 parameter_values_path: nil,
                                 condition_values_path: nil,
                                 template_pattern: DEFAULT_TEMPLATE_PATTERN)
  parameter_values_string = parameter_values_path.nil? ? nil : IO.read(parameter_values_path)
  condition_values_string = condition_values_path.nil? ? nil : IO.read(condition_values_path)

  templates = TemplateDiscovery.new.discover_templates(input_json_path: input_path,
                                                       template_pattern: template_pattern)
  aggregate_results = []
  templates.each do |template|
    aggregate_results << {
      filename: template,
      file_results: audit(cloudformation_string: IO.read(template),
                          parameter_values_string: parameter_values_string,
                          condition_values_string: condition_values_string)
    }
  end
  aggregate_results
end
audit_aggregate_across_files_and_render_results(input_path:, output_format: 'txt', parameter_values_path: nil, condition_values_path: nil, template_pattern: DEFAULT_TEMPLATE_PATTERN) click to toggle source

Given a file or directory path, emit aggregate results to stdout

Return an aggregate failure count (for exit code usage)

# File lib/cfn-nag/cfn_nag.rb, line 28
def audit_aggregate_across_files_and_render_results(input_path:,
                                                    output_format: 'txt',
                                                    parameter_values_path: nil,
                                                    condition_values_path: nil,
                                                    template_pattern: DEFAULT_TEMPLATE_PATTERN)

  aggregate_results = audit_aggregate_across_files input_path: input_path,
                                                   parameter_values_path: parameter_values_path,
                                                   condition_values_path: condition_values_path,
                                                   template_pattern: template_pattern

  render_results(aggregate_results: aggregate_results,
                 output_format: output_format)

  aggregate_results.inject(0) do |total_failure_count, results|
    if @config.fail_on_warnings
      total_failure_count + results[:file_results][:violations].length
    else
      total_failure_count + results[:file_results][:failure_count]
    end
  end
end
prune_fatal_violations(violations) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 109
def prune_fatal_violations(violations)
  violations.reject { |violation| violation.id == 'FATAL' }
end
render_results(aggregate_results:, output_format:) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 113
def render_results(aggregate_results:,
                   output_format:)
  results_renderer(output_format).new.render(aggregate_results)
end

Private Instance Methods

audit_result(violations) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 148
def audit_result(violations)
  {
    failure_count: Violation.count_failures(violations),
    violations: violations
  }
end
fatal_violation(message) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 155
def fatal_violation(message)
  Violation.new(id: 'FATAL',
                type: Violation::FAILING_VIOLATION,
                message: message)
end
filter_violations_by_blacklist_and_profile(violations) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 130
def filter_violations_by_blacklist_and_profile(violations)
  violations = filter_violations_by_profile(
    profile_definition: @config.profile_definition,
    rule_definitions: @config.custom_rule_loader.rule_definitions,
    violations: violations
  )

  # this must come after - blacklist should always win
  filter_violations_by_blacklist(
    blacklist_definition: @config.blacklist_definition,
    rule_definitions: @config.custom_rule_loader.rule_definitions,
    violations: violations
  )
rescue StandardError => blacklist_or_profile_parse_error
  violations << fatal_violation(blacklist_or_profile_parse_error.to_s)
  violations
end
mark_line_numbers(violations, cfn_model) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 120
def mark_line_numbers(violations, cfn_model)
  violations.each do |violation|
    violation.logical_resource_ids.each do |logical_resource_id|
      violation.line_numbers << cfn_model.line_numbers[logical_resource_id]
    end
  end

  violations
end
results_renderer(output_format) click to toggle source
# File lib/cfn-nag/cfn_nag.rb, line 161
def results_renderer(output_format)
  registry = {
    'colortxt' => ColoredStdoutResults,
    'txt' => SimpleStdoutResults,
    'json' => JsonResults
  }
  registry[output_format]
end