Class: SecureKeys::Validation::Scanner

Inherits:
Object
  • Object
show all
Defined in:
lib/validation/scanner.rb

Overview

Scans files and git diffs for exposed secrets using the known PATTERNS set

Instance Method Summary collapse

Constructor Details

#initialize(options: {}) ⇒ Scanner

Initialize a new scanner

Parameters:

  • options (Hash) (defaults to: {})

    Override specific default scanning options

Options Hash (options:):

  • :extensions (Array<String>)

    File extensions to include in the scan

  • :excludes (Array<String>)

    Directory and file names to exclude

  • :max_depth (Integer)

    Maximum directory traversal depth

  • :follow_symlinks (Boolean)

    Whether to follow symbolic links



26
27
28
29
# File 'lib/validation/scanner.rb', line 26

def initialize(options: {})
  self.options = default_options.merge(options)
  self.findings = []
end

Instance Method Details

#scan_directory(path: '.', options: {}) ⇒ ScanResult

Scan a directory recursively for exposed secrets

Parameters:

  • path (String) (defaults to: '.')

    The root directory path to scan (default: current directory)

  • options (Hash) (defaults to: {})

    Additional options to merge for this scan only

Returns:



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/validation/scanner.rb', line 35

def scan_directory(path: '.', options: {})
  self.findings = []
  self.options = self.options.merge(options)

  Core::Console::Logger.verbose(message: "Scanning directory: #{path}")
  Core::Console::Logger.verbose(message: "Extensions: #{file_extensions.join(', ')}")
  Core::Console::Logger.verbose(message: "Excludes: #{exclude_patterns.join(', ')}")

  files = find_files(path:)

  Core::Console::Logger.verbose(message: "Found #{files.length} files to scan")

  files.each { |file| scan_file(file_path: file) }

  ScanResult.new(findings:, files_count: files.length)
end

#scan_git_diff(staged_only: true) ⇒ ScanResult

Scan staged or unstaged git changes for exposed secrets

Parameters:

  • staged_only (Boolean) (defaults to: true)

    When true, scans only staged changes (default: true)

Returns:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/validation/scanner.rb', line 55

def scan_git_diff(staged_only: true)
  self.findings = []

  command = staged_only ? 'git diff --cached' : 'git diff'
  diff_output, = Core::Console::Shell.sh(command:)

  return ScanResult.new(findings: [], files_count: 0) if diff_output.strip.empty?

  current_file = nil
  line_number = 0

  diff_output.each_line do |line|
    if line.start_with?('+++')
      current_file = line.sub(%r{^\+\+\+ b/}, '').strip
      line_number = 0
    elsif line.start_with?('@@') && current_file
      hunk_match = line.match(/\+(\d+)/)
      line_number = hunk_match ? hunk_match[1].to_i - 1 : 0
    elsif line.start_with?('+') && current_file && !line.start_with?('+++')
      line_number += 1
      check_line(
        file_path: current_file,
        line_number:,
        line: line[1..],
        is_addition: true
      )
    end
  end

  ScanResult.new(findings:, files_count: diff_output.lines.count)
end