Class: Bootprint::Policy

Inherits:
Object
  • Object
show all
Defined in:
lib/bootprint/policy.rb

Constant Summary collapse

MODES =
%w[permissive strict].freeze
SEVERITIES =
%w[info warning error critical].freeze
TOP_LEVEL_KEYS =
%w[version minimum_severity fail_on ignore allow rules redaction mode expected_platforms plugins].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path = nil, data = {}) ⇒ Policy

Returns a new instance of Policy.



27
28
29
30
31
# File 'lib/bootprint/policy.rb', line 27

def initialize(path = nil, data = {})
  @path = path
  @data = Schema.stringify(data)
  validate!
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



11
12
13
# File 'lib/bootprint/policy.rb', line 11

def data
  @data
end

#pathObject (readonly)

Returns the value of attribute path.



11
12
13
# File 'lib/bootprint/policy.rb', line 11

def path
  @path
end

Class Method Details

.load(path = nil) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/bootprint/policy.rb', line 13

def self.load(path = nil)
  return new(nil, {}) unless path

  absolute = File.expand_path(path)
  raise ConfigurationError, "#{absolute}: file not found" unless File.file?(absolute)

  parsed = YAML.safe_load_file(absolute, permitted_classes: [], aliases: false) || {}
  new(absolute, parsed)
rescue Psych::SyntaxError => error
  raise ConfigurationError, "#{absolute}:#{error.line}:#{error.column}: #{error.problem}"
rescue Psych::Exception => error
  raise ConfigurationError, "#{absolute}: #{error.message}"
end

Instance Method Details

#allowed_pathsObject



56
57
58
59
60
61
62
63
# File 'lib/bootprint/policy.rb', line 56

def allowed_paths
  allow = data["allow"]
  if allow.is_a?(Array)
    allow.map(&:to_s)
  else
    Array(allow.is_a?(Hash) ? allow["paths"] : nil).map(&:to_s)
  end
end

#apply!Object



98
99
100
101
102
103
104
105
# File 'lib/bootprint/policy.rb', line 98

def apply!
  Bootprint.configuration.optional_environment_names |= optional_environment_variables
  Bootprint.configuration.expected_platforms = expected_platforms
  Bootprint.configuration.redaction_patterns |= redaction_patterns
  Bootprint.configuration.redaction_safe_list |= redaction_safe_list
  Bootprint.configuration.plugin_strict = plugin_strict?
  self
end

#disabled?(rule_id) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/bootprint/policy.rb', line 83

def disabled?(rule_id)
  data.dig("rules", rule_id.to_s, "enabled") == false
end

#expected_platformsObject



41
42
43
# File 'lib/bootprint/policy.rb', line 41

def expected_platforms
  Array(data["expected_platforms"]).map(&:to_s)
end

#explainObject



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/bootprint/policy.rb', line 107

def explain
  lines = []
  lines << "Policy: #{path || '(built-in defaults)'}"
  lines << "Mode: #{strict? ? 'strict' : 'permissive'}"
  lines << "Minimum reported severity: #{minimum_severity}"
  lines << "Blocking severities: #{fail_on.join(', ')}"
  lines << "Ignored rules: #{Array(data['ignore']).join(', ')}" unless Array(data["ignore"]).empty?
  lines << "Optional environment variables: #{optional_environment_variables.join(', ')}" unless optional_environment_variables.empty?
  lines << "Expected platforms: #{expected_platforms.join(', ')}" unless expected_platforms.empty?
  lines << "Rule overrides: #{Array(data['rules']&.keys).join(', ')}" if data["rules"].is_a?(Hash)
  "#{lines.join("\n")}\n"
end

#fail_onObject



37
38
39
# File 'lib/bootprint/policy.rb', line 37

def fail_on
  Array(data["fail_on"] || (strict? ? %w[warning error critical] : %w[error critical])).map(&:to_s)
end

#ignored?(rule_id) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/bootprint/policy.rb', line 79

def ignored?(rule_id)
  Array(data["ignore"]).map(&:to_s).include?(rule_id.to_s)
end

#minimum_severityObject



33
34
35
# File 'lib/bootprint/policy.rb', line 33

def minimum_severity
  (data["minimum_severity"] || (strict? ? "warning" : "info")).to_sym
end

#optional_environment_variable?(name) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/bootprint/policy.rb', line 52

def optional_environment_variable?(name)
  optional_environment_variables.include?(name.to_s)
end

#optional_environment_variablesObject



45
46
47
48
49
50
# File 'lib/bootprint/policy.rb', line 45

def optional_environment_variables
  allow = data["allow"]
  return [] unless allow.is_a?(Hash)

  Array(allow["environment_variables"]).map(&:to_s)
end

#plugin_strict?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/bootprint/policy.rb', line 73

def plugin_strict?
  strict? || data.dig("plugins", "strict") == true
end

#redaction_patternsObject



65
66
67
# File 'lib/bootprint/policy.rb', line 65

def redaction_patterns
  Array(data.dig("redaction", "patterns")).map(&:to_s)
end

#redaction_safe_listObject



69
70
71
# File 'lib/bootprint/policy.rb', line 69

def redaction_safe_list
  Array(data.dig("redaction", "safe_list")).map(&:to_s)
end

#severity_for(rule_id, default) ⇒ Object



87
88
89
# File 'lib/bootprint/policy.rb', line 87

def severity_for(rule_id, default)
  (data.dig("rules", rule_id.to_s, "severity") || default).to_sym
end

#strict?Boolean

Returns:

  • (Boolean)


77
# File 'lib/bootprint/policy.rb', line 77

def strict? = data.fetch("mode", "permissive") == "strict"

#suppression_reason(rule_id) ⇒ Object



91
92
93
94
95
96
# File 'lib/bootprint/policy.rb', line 91

def suppression_reason(rule_id)
  return "ignored by policy" if ignored?(rule_id)
  return "disabled by policy" if disabled?(rule_id)

  nil
end