class Utils::XCCDFScore

Perform scoring calculations for the different types that is used in a TestResult score.

Public Class Methods

new(groups, rule_results) click to toggle source

@param groups [Array] @param rule_results [Array]

# File lib/utilities/xccdf/xccdf_score.rb, line 6
def initialize(groups, rule_results)
  @groups = groups
  @rule_results = rule_results
end

Public Instance Methods

absolute_score() click to toggle source

urn:xccdf:scoring:absolute @return ScoreType

# File lib/utilities/xccdf/xccdf_score.rb, line 33
def absolute_score
  results = score_benchmark_with_weights(true)
  HappyMapperTools::Benchmark::ScoreType.new('urn:xccdf:scoring:absolute', 1, (results[:max] == results[:score] && results[:max].positive? ? 1 : 0))
end
default_score() click to toggle source

Calculate and return the urn:xccdf:scoring:default score for the entire benchmark. @return ScoreType

# File lib/utilities/xccdf/xccdf_score.rb, line 13
def default_score
  HappyMapperTools::Benchmark::ScoreType.new('urn:xccdf:scoring:default', 100, score_benchmark_default)
end
flat_score() click to toggle source

urn:xccdf:scoring:flat @return ScoreType

# File lib/utilities/xccdf/xccdf_score.rb, line 19
def flat_score
  results = score_benchmark_with_weights(true)
  HappyMapperTools::Benchmark::ScoreType.new('urn:xccdf:scoring:flat', results[:max], results[:score])
end
flat_unweighted_score() click to toggle source

urn:xccdf:scoring:flat-unweighted @return ScoreType

# File lib/utilities/xccdf/xccdf_score.rb, line 26
def flat_unweighted_score
  results = score_benchmark_with_weights(false)
  HappyMapperTools::Benchmark::ScoreType.new('urn:xccdf:scoring:flat-unweighted', results[:max], results[:score])
end

Private Instance Methods

rule_counts_and_score(results) click to toggle source

Perform basic summation of rule results and passing tests

# File lib/utilities/xccdf/xccdf_score.rb, line 100
def rule_counts_and_score(results)
  excluded_results = %w{notapplicable notchecked informational notselected}
  rule_count = results.count { |r| !excluded_results.include?(r.result) }
  rule_score = results.count { |r| r.result == 'pass' }

  { rule_count: rule_count, rule_score: rule_score }
end
score_benchmark_default() click to toggle source

Return the overall score for the default model

# File lib/utilities/xccdf/xccdf_score.rb, line 41
def score_benchmark_default
  return 0.0 unless @groups

  count = 0
  cumulative_score = 0.0

  @groups.each do |group|
    # Default weighted scoring only provides value when more than one rule exists per group. This implementation
    # is not currently supporting more than one rule per group so weight need not apply.
    rule_score = score_default_rule(test_results(group.rule.id))

    if rule_score[:rule_count].positive?
      count += 1
      cumulative_score += rule_score[:rule_score]
    end
  end

  return 0.0 unless count.positive?

  (cumulative_score / count).round(2)
end
score_benchmark_with_weights(weighted) click to toggle source

@param weighted [Boolean] Indicate to apply with weights.

# File lib/utilities/xccdf/xccdf_score.rb, line 64
def score_benchmark_with_weights(weighted)
  score = 0.0
  max_score = 0.0

  return { score: score, max: max_score } unless @groups

  @groups.each do |group|
    # Default weighted scoring only provides value when more than one rule exists per group. This implementation
    # is not currently supporting more than one rule per group so weight need not apply.
    rule_score = rule_counts_and_score(test_results(group.rule.id))

    next unless rule_score[:rule_count].positive?

    weight =
      if weighted
        group.rule.weight.nil? ? 1.0 : group.rule.weight.to_f
      else
        group.rule.weight.nil? || group.rule.weight.to_f != 0.0 ? 1.0 : 0.0
      end

    max_score += weight
    score += (weight * rule_score[:rule_score]) / rule_score[:rule_count]
  end

  { score: score.round(2), max: max_score }
end
score_default_rule(results) click to toggle source
# File lib/utilities/xccdf/xccdf_score.rb, line 91
def score_default_rule(results)
  sum = rule_counts_and_score(results)
  return sum if sum[:rule_count].zero?

  sum[:rule_score] = (100 * sum[:rule_score]) / sum[:rule_count]
  sum
end
test_results(id) click to toggle source

Get all test results with the matching rule id @return [Array]

# File lib/utilities/xccdf/xccdf_score.rb, line 110
def test_results(id)
  return [] unless @rule_results

  @rule_results.select { |r| r.idref == id }
end