Module: AIGit::Secrets

Defined in:
lib/ai_git/secrets.rb

Constant Summary collapse

RISKY_PATHS =
{
  "an environment file" => %r{(\A|/)\.env(\.[^/]+)?\z},
  "an SSH private key" => %r{(\A|/)id_(rsa|dsa|ecdsa|ed25519)\z},
  "a private key file" => /\.(pem|key|p12|pfx|jks|keystore)\z/i,
  "a credentials file" => %r{(\A|/)(credentials|\.netrc|\.npmrc|\.pypirc|\.htpasswd)\z},
  "a secrets file" => %r{(\A|/)secrets?\.(ya?ml|json|toml)\z}i
}.freeze
RISKY_CONTENT =
{
  "a private key block" => /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
  "an AWS access key id" => /\bAKIA[0-9A-Z]{16}\b/,
  "a GitHub token" => /\b(gh[posur]_[A-Za-z0-9]{16,}|github_pat_[A-Za-z0-9_]{20,})\b/,
  "an OpenAI-style API key" => /\bsk-[A-Za-z0-9_-]{20,}\b/,
  "a Slack token" => /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/,
  "a Google API key" => /\bAIza[0-9A-Za-z_-]{35}\b/
}.freeze
SUSPICIOUS_ASSIGNMENT =
/
  \b(api[_-]?key|secret|password|passwd|token|access[_-]?key)\b
  \s*[:=]\s*["'][^"']{8,}["']
/ix.freeze

Class Method Summary collapse

Class Method Details

.added_lines(diff) ⇒ Object



62
63
64
# File 'lib/ai_git/secrets.rb', line 62

def added_lines(diff)
  diff.to_s.lines.select { |line| line.start_with?("+") && !line.start_with?("+++") }.join
end

.blocking_findings(staged_files, diff) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ai_git/secrets.rb', line 43

def blocking_findings(staged_files, diff)
  paths = staged_files.to_s.lines.map(&:strip).reject(&:empty?)
  added = added_lines(diff)

  findings = paths.flat_map do |path|
    RISKY_PATHS.filter_map { |label, pattern| "#{path} looks like #{label}" if path.match?(pattern) }
  end

  findings + RISKY_CONTENT.filter_map do |label, pattern|
    "added lines contain what looks like #{label}" if added.match?(pattern)
  end
end

.scan(staged_files, diff) ⇒ Object



39
40
41
# File 'lib/ai_git/secrets.rb', line 39

def scan(staged_files, diff)
  { blocking: blocking_findings(staged_files, diff), warnings: warning_findings(diff) }
end

.warning_findings(diff) ⇒ Object



56
57
58
59
60
# File 'lib/ai_git/secrets.rb', line 56

def warning_findings(diff)
  return [] unless added_lines(diff).match?(SUSPICIOUS_ASSIGNMENT)

  ["added lines assign a value to a key/secret/password/token name"]
end