Module: OllamaAgent::PatchRisk

Defined in:
lib/ollama_agent/patch_risk.rb

Overview

Classifies a proposed unified diff for semi-automatic patch approval (obvious vs risky).

Constant Summary collapse

FORBIDDEN_PATTERNS =
[
  /\beval\s*\(/,
  /`rm\s+-rf/,
  /system\s*\(\s*["']sudo/,
  /\bFile\.delete\b/,
  /\bKernel\.exec\b/
].freeze
LARGE_DIFF_LINES =
80

Class Method Summary collapse

Class Method Details

.assess(path, diff) ⇒ Object

Returns :auto_approve (no prompt) or :require_confirmation (prompt when confirm_patches is on).



32
33
34
35
36
37
38
39
40
41
# File 'lib/ollama_agent/patch_risk.rb', line 32

def assess(path, diff)
  relative = path.to_s.tr("\\", "/")

  return :require_confirmation if risky?(relative, diff)

  return :auto_approve if obvious_path?(relative)
  return :auto_approve if safe_spec_change?(relative, diff)

  :require_confirmation
end

.critical_lib_file?(relative) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
66
67
68
69
70
# File 'lib/ollama_agent/patch_risk.rb', line 63

def critical_lib_file?(relative)
  return false unless relative.start_with?("lib/")

  relative.include?("sandboxed_tools") ||
    relative.include?("patch_support") ||
    relative.end_with?("ollama_agent/agent.rb") ||
    relative.end_with?("ollama_agent/tools_schema.rb")
end

.critical_path?(relative) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
75
76
77
78
79
# File 'lib/ollama_agent/patch_risk.rb', line 72

def critical_path?(relative)
  return true if relative.match?(/\A(Gemfile|Gemfile\.lock)\z/)
  return true if relative.end_with?(".gemspec")
  return true if relative == "lib/ollama_agent/version.rb"
  return true if relative.start_with?("exe/")

  false
end

.forbidden?(diff) ⇒ Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/ollama_agent/patch_risk.rb', line 27

def forbidden?(diff)
  FORBIDDEN_PATTERNS.any? { |pattern| diff.match?(pattern) }
end

.large_diff?(diff, limit: nil) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
53
# File 'lib/ollama_agent/patch_risk.rb', line 50

def large_diff?(diff, limit: nil)
  max = limit.nil? ? large_diff_line_limit : limit
  diff.scan(/^[-+][^-+]/).size > max
end

.large_diff_line_limitObject



18
19
20
21
22
23
24
25
# File 'lib/ollama_agent/patch_risk.rb', line 18

def large_diff_line_limit
  v = ENV.fetch("OLLAMA_AGENT_PATCH_RISK_MAX_DIFF_LINES", nil)
  return LARGE_DIFF_LINES if v.nil? || v.to_s.strip.empty?

  Integer(v)
rescue ArgumentError, TypeError
  LARGE_DIFF_LINES
end

.obvious_path?(relative) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/ollama_agent/patch_risk.rb', line 55

def obvious_path?(relative)
  relative.end_with?(".md") || relative.start_with?("docs/")
end

.risky?(relative, diff) ⇒ Boolean

Returns:

  • (Boolean)


43
44
45
46
47
48
# File 'lib/ollama_agent/patch_risk.rb', line 43

def risky?(relative, diff)
  forbidden?(diff) ||
    critical_path?(relative) ||
    large_diff?(diff) ||
    critical_lib_file?(relative)
end

.safe_spec_change?(relative, diff) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/ollama_agent/patch_risk.rb', line 59

def safe_spec_change?(relative, diff)
  relative.start_with?("spec/") && !large_diff?(diff, limit: 40)
end