169 lines
5.6 KiB
Ruby
169 lines
5.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'fast_spec_helper'
|
|
require 'webmock/rspec'
|
|
require_relative '../../scripts/semgrep_result_processor'
|
|
|
|
RSpec.describe SemgrepResultProcessor, feature_category: :tooling do
|
|
let(:report_file) { 'spec/fixtures/scripts/gl-sast-report.json' }
|
|
let(:path_line_message_dict) do
|
|
{ "bug.rb" => [
|
|
{ line: 5,
|
|
message: "Deserializing user-controlled objects can cause vulnerabilities." },
|
|
{ line: 10, message: "Deserializing user-controlled objects can cause vulnerabilities." },
|
|
{ line: 15, message: "Deserializing user-controlled objects can cause vulnerabilities." },
|
|
{ line: 17, message: "Deserializing user-controlled objects can cause vulnerabilities." }
|
|
] }
|
|
end
|
|
|
|
let(:processor) { described_class.new(report_file) }
|
|
|
|
before do
|
|
stub_env('CI_PROJECT_DIR', '/tmp/project_dir')
|
|
stub_env('CI_API_V4_URL', 'https://gitlab.com/api/v4')
|
|
stub_env('CI_MERGE_REQUEST_PROJECT_ID', '1234')
|
|
stub_env('CI_MERGE_REQUEST_IID', '1234')
|
|
stub_env('CUSTOM_SAST_RULES_BOT_PAT', 'gl-pat-123')
|
|
stub_env('BOT_USER_ID', '21564538')
|
|
stub_request(:any, /gitlab.com/).to_return(status: 400)
|
|
end
|
|
|
|
describe '#execute' do
|
|
around do |example|
|
|
example.run
|
|
rescue SystemExit
|
|
end
|
|
|
|
it 'raises an error and prints the error message' do
|
|
allow(processor).to receive(:perform_allowlist_check).and_raise(StandardError, 'Error message here')
|
|
|
|
expect { processor.execute }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
describe '#perform_allowlist_check' do
|
|
let(:original_env) { ENV.to_hash }
|
|
|
|
around do |example|
|
|
example.run
|
|
rescue SystemExit
|
|
end
|
|
|
|
before do
|
|
stub_env('CI_PROJECT_DIR', '/tmp/not_allowlisted')
|
|
end
|
|
|
|
it 'exits on non allowlisted project dir' do
|
|
expect(processor.perform_allowlist_check).to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
describe '#get_sast_results' do
|
|
it 'returns hash of findings' do
|
|
expect(processor.get_sast_results).to eq(path_line_message_dict)
|
|
end
|
|
end
|
|
|
|
describe '#remove_duplicate_findings' do
|
|
# rubocop:disable Layout/LineLength -- we need the entire message + footer
|
|
let(:existing_comments_response) do
|
|
[
|
|
{
|
|
"id" => 1933334610,
|
|
"type" => "DiffNote",
|
|
"body" => "Deserializing user-controlled objects can cause vulnerabilities.\n\n\n\u003csmall\u003e\nThis AppSec automation is currently under testing.\nUse ~\"appsec-sast::helpful\" or ~\"appsec-sast::unhelpful\" for quick feedback.\nFor any detailed feedback, [add a comment here](https://gitlab.com/gitlab-com/gl-security/product-security/appsec/sast-custom-rules/-/issues/38).\n\u003c/small\u003e\n\n",
|
|
"author" => {
|
|
"id" => 21564538
|
|
},
|
|
"position" => {
|
|
"base_sha" => "6135e8352307d2bbd94aee1f335483835efd8b65",
|
|
"start_sha" => "e82e15e57ce4e0f67dd8eeadf38e4b115f0ae487",
|
|
"head_sha" => "ee82e8feb0af93b24b5443c7af4440599756bc1f",
|
|
"old_path" => "bug.rb",
|
|
"new_path" => "bug.rb",
|
|
"position_type" => "text",
|
|
"old_line" => nil,
|
|
"new_line" => 17,
|
|
"line_range" => nil
|
|
}
|
|
}
|
|
]
|
|
end
|
|
# rubocop:enable Layout/LineLength
|
|
|
|
let(:expected_path_line_message_dict) do
|
|
{ "bug.rb" => [
|
|
{ line: 5, message: "Deserializing user-controlled objects can cause vulnerabilities." },
|
|
{ line: 10, message: "Deserializing user-controlled objects can cause vulnerabilities." },
|
|
{ line: 15, message: "Deserializing user-controlled objects can cause vulnerabilities." }
|
|
] }
|
|
end
|
|
|
|
it 'deletes already posted finding from hash' do
|
|
allow(processor).to receive(:get_existing_comments).and_return(existing_comments_response)
|
|
result = processor.remove_duplicate_findings(path_line_message_dict)
|
|
|
|
expect(result).to eq(expected_path_line_message_dict)
|
|
end
|
|
end
|
|
|
|
describe '#create_inline_comments' do
|
|
around do |example|
|
|
example.run
|
|
rescue SystemExit
|
|
end
|
|
|
|
it 'handles failed comment post' do
|
|
allow(Net::HTTP).to receive(:post).and_return(Net::HTTPBadRequest.new(nil, 400, 'Bad Request'))
|
|
|
|
path_line_message_dict = {
|
|
'file1.rb' => [{ line: 10, message: 'Error message 1' }],
|
|
'file2.rb' => [{ line: 20, message: 'Error message 2' }]
|
|
}
|
|
|
|
expect { processor.create_inline_comments(path_line_message_dict) }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
describe '#get_existing_comments' do
|
|
around do |example|
|
|
example.run
|
|
rescue SystemExit
|
|
end
|
|
|
|
it 'handles error response' do
|
|
http_double = instance_double(Net::HTTP)
|
|
allow(http_double).to receive(:start).and_return(Net::HTTPBadRequest.new(nil, 400, 'Bad Request'))
|
|
|
|
expect { processor.send(:get_existing_comments) }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
describe '#populate_commits_from_versions' do
|
|
around do |example|
|
|
example.run
|
|
rescue SystemExit
|
|
end
|
|
|
|
it 'handles error response' do
|
|
http_double = instance_double(Net::HTTP)
|
|
allow(http_double).to receive(:start).and_return(Net::HTTPBadRequest.new(nil, 400, 'Bad Request'))
|
|
|
|
expect { processor.send(:populate_commits_from_versions) }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
|
|
describe '#post_comment' do
|
|
around do |example|
|
|
example.run
|
|
rescue SystemExit
|
|
end
|
|
|
|
it 'handles error response' do
|
|
allow(Net::HTTP).to receive(:post).and_return(Net::HTTPBadRequest.new(nil, 400, 'Bad Request'))
|
|
|
|
expect { processor.send(:post_comment, 'Example comment') }.to raise_error(SystemExit)
|
|
end
|
|
end
|
|
end
|