Skip to content

Commit 43bc0e7

Browse files
committed
Add basic tests
1 parent c5d4792 commit 43bc0e7

5 files changed

Lines changed: 79 additions & 2 deletions

File tree

Gemfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
source 'https://rubygems.org'
22

33
gemspec
4+
5+
group :test do
6+
gem 'minitest'
7+
end

Rakefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require "rake/testtask"
2+
3+
Rake::TestTask.new(:test) do |t|
4+
t.libs << "test"
5+
t.libs << "lib"
6+
t.test_files = FileList["test/test_*.rb"]
7+
end
8+
9+
task :default => :test

lib/brakeman-llm.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module Brakeman
2222

2323
# Simple wrapper for RubyLLM
2424
class LLM
25+
attr_accessor :instructions, :model, :prompt, :provider
26+
attr_reader :llm
2527

2628
# Configure RubyLLM
2729
def initialize(model:, provider:, instructions: nil, prompt: nil, **kwargs)
@@ -146,18 +148,20 @@ def run(options)
146148
disclaimer = false
147149
end
148150

149-
llm_opts = options.delete(:llm)
151+
llm_opts = options.delete(:llm) || {}
150152

151153
# Suppress report output until after analysis
152154
output_formats = get_output_formats(options)
153155
output_files = options.delete(:output_files)
154156
options.delete(:output_format)
155157
print_report = options.delete(:print_report)
156158

159+
# Actually run scan
157160
tracker = old_run(options)
158161

162+
# Set up LLM
159163
llm_opts[:log_level] = :debug if @debug
160-
llm = Brakeman::LLM.new(**llm_opts)
164+
llm = llm_opts.delete(:llm) || Brakeman::LLM.new(**llm_opts)
161165

162166
set_analysis = output_formats.include? :to_json
163167

@@ -166,6 +170,7 @@ def run(options)
166170
warnings = tracker.warnings
167171
total = warnings.length
168172

173+
# Update warnings with LLM analysis
169174
warnings.each_with_index do |warning, index|
170175
unless @quiet or options[:report_progress] == false
171176
$stderr.print " #{index}/#{total} warnings processed\r"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class ApplicationController < ActionController::Base
2+
def vulnerable_method
3+
eval(params[:x])
4+
end
5+
end

test/test_basics.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require 'minitest/autorun'
2+
require 'brakeman-llm'
3+
require 'brakeman/commandline'
4+
5+
6+
class BrakemanLLMTest < Minitest::Test
7+
def test_the_basics
8+
bm_llm = Brakeman::LLM.new(model: 'test_model', provider: 'test_provider')
9+
10+
assert_equal 'test_model', bm_llm.model
11+
assert_equal 'test_provider', bm_llm.provider
12+
assert bm_llm.llm
13+
14+
# Defaults
15+
assert_instance_of String, bm_llm.instructions
16+
assert_instance_of String, bm_llm.prompt
17+
end
18+
19+
def test_missing_options
20+
21+
end
22+
23+
def test_end_to_end
24+
bm_llm = Brakeman::LLM.new(model: 'test_model', provider: 'test_provider')
25+
instructions = bm_llm.instructions
26+
analysis = "Extended warning description"
27+
tracker = nil
28+
29+
response_mock = Minitest::Mock.new
30+
response_mock.expect(:content, analysis.dup)
31+
response_mock.expect(:content, analysis.dup)
32+
33+
chat_mock = Minitest::Mock.new
34+
35+
2.times do
36+
chat_mock.expect(:with_instructions, nil, [instructions])
37+
chat_mock.expect(:ask, response_mock, [String])
38+
end
39+
40+
bm_llm.llm.stub(:chat, chat_mock) do
41+
tracker = Brakeman.run(llm: { llm: bm_llm }, app_path: File.join(__dir__, 'fixtures', 'app'), output_format: :json)
42+
end
43+
44+
# Check that the warnings have the analysis attached
45+
tracker.warnings.each do |w|
46+
assert_includes w.llm_analysis, analysis
47+
48+
assert_equal w.llm_analysis, w.to_hash[:llm_analysis]
49+
end
50+
51+
chat_mock.verify
52+
response_mock.verify
53+
end
54+
end

0 commit comments

Comments
 (0)