Module: StillActive::ConfigFile

Extended by:
ConfigFile
Included in:
ConfigFile
Defined in:
lib/still_active/config_file.rb

Overview

Loads a committed .still_active.yml and applies it to the config as the layer below env vars and CLI flags (CLI flag > env var > config file > default). Mirrors the policy flags (gates, thresholds, output, alternatives, scope) and the granular suppression list; deliberately NOT secrets (tokens) or invocation-specific paths (–gemfile/–gems/–baseline/output paths), which stay CLI/env-only so a committed file never carries a credential.

Constant Summary collapse

FILENAME =
".still_active.yml"
BUNDLER_AUDIT_FILE =
".bundler-audit.yml"

Instance Method Summary collapse

Instance Method Details

#apply(config, data, base_dir: Dir.pwd) ⇒ Object

Applies data to config and returns an array of warning strings (unknown keys, invalid values, suppression/import problems). Booleans/numbers are passed through as the gate expects them.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/still_active/config_file.rb', line 43

def apply(config, data, base_dir: Dir.pwd)
  warnings = []
  ignore_entries = Array(data["ignore"])

  data.each do |key, value|
    case key
    when "fail_if_critical" then set_boolean(config, :fail_if_critical=, value, key, warnings)
    when "fail_if_warning" then set_boolean(config, :fail_if_warning=, value, key, warnings)
    when "alternatives" then set_boolean(config, :alternatives=, value, key, warnings)
    when "unreleased_commits" then set_boolean(config, :unreleased_commits=, value, key, warnings)
    when "direct_only" then set_boolean(config, :direct_only=, value, key, warnings)
    when "safe_range_end" then set_number(config, :no_warning_range_end=, value, key, warnings)
    when "warning_range_end" then set_number(config, :warning_range_end=, value, key, warnings)
    when "fail_if_outdated" then apply_fail_if_outdated(config, value, warnings)
    when "parallelism" then apply_parallelism(config, value, warnings)
    when "fail_if_vulnerable" then apply_fail_if_vulnerable(config, value, warnings)
    when "output" then apply_output(config, value, warnings)
    when "ignore" then nil # handled below, after imports are gathered
    when "import" then ignore_entries.concat(import_advisories(value, base_dir, warnings))
    else warnings << "#{FILENAME}: unknown setting #{key.inspect}, ignoring it"
    end
  end

  suppressions = Suppressions.from(ignore_entries)
  warnings.concat(suppressions.warnings)
  config.suppressions = suppressions
  warnings
end

#import_hint(data, config: StillActive.config, dir: Dir.pwd) ⇒ Object

Suggests honouring an existing bundler-audit ignore list rather than silently inheriting it. Auto-importing another tool’s suppressions would hide vulnerabilities the user only accepted in bundler-audit’s context, with no reason/expiry and no explicit opt-in here, the exact over-broad muting this feature exists to replace. So nudge, don’t absorb, and only when the vulnerability gate is on (suppression is otherwise moot) and the file isn’t already imported. Returns the hint string or nil.



79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/still_active/config_file.rb', line 79

def import_hint(data, config: StillActive.config, dir: Dir.pwd)
  return unless config.fail_if_vulnerable
  return if Array(data["import"]).include?(BUNDLER_AUDIT_FILE)

  path = File.join(dir, BUNDLER_AUDIT_FILE)
  return unless File.file?(path)

  count = bundler_audit_ignore_count(path)
  return unless count.positive?

  noun = count == 1 ? "advisory" : "advisories"
  "#{BUNDLER_AUDIT_FILE} lists #{count} accepted #{noun}; add `import: [#{BUNDLER_AUDIT_FILE}]` to #{FILENAME} to honour them in still_active's --fail-if-vulnerable gate too"
end

#load(dir: Dir.pwd) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/still_active/config_file.rb', line 20

def load(dir: Dir.pwd)
  path = File.join(dir, FILENAME)
  return {} unless File.file?(path)

  data = YAML.safe_load_file(path, permitted_classes: [Date, Time])
  return {} if data.nil?

  unless data.is_a?(Hash)
    $stderr.puts("warning: #{FILENAME} must be a mapping of settings; ignoring it")
    return {}
  end

  data
rescue Psych::Exception => e
  # Covers a syntax error and a disallowed tag (e.g. !ruby/object); either
  # way the committed file must never take the audit down with it.
  $stderr.puts("warning: #{FILENAME} could not be loaded (#{e.message}); ignoring it")
  {}
end