spec/lib/release_tools/security/issue_crawler_spec.rb (249 lines of code) (raw):
# frozen_string_literal: true
require 'spec_helper'
describe ReleaseTools::Security::IssueCrawler do
let(:tracking_issue1) do
create(
:issue,
project_id: 1,
iid: 1,
due_date: '2020-01-04',
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/1'
)
end
let(:issue1) do
create(
:issue,
project_id: 1,
iid: 2,
due_date: '2020-01-01',
labels: [],
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/2'
)
end
let(:issue2) do
create(
:issue,
project_id: 1,
iid: 3,
due_date: nil,
labels: [],
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/2'
)
end
let(:issue3) do
create(
:issue,
project_id: 2,
iid: 1,
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/1'
)
end
let(:page) { Gitlab::PaginatedResponse.new([tracking_issue1, issue1, issue2]) }
subject(:crawler) { described_class.new }
describe '#upcoming_security_issues_and_merge_requests' do
context 'when there are no security issues' do
it 'returns an empty Array' do
allow(ReleaseTools::GitlabClient).to receive(:next_security_tracking_issue).and_return(nil)
expect(crawler.upcoming_security_issues_and_merge_requests).to eq([])
end
end
context 'when there are security issues' do
it 'returns all security issues and merge requests for the most recent issue' do
allow(ReleaseTools::GitlabClient)
.to receive(:next_security_tracking_issue)
.and_return(issue3)
expect(crawler)
.to receive(:related_security_issues)
.and_return([tracking_issue1, issue1])
crawler.upcoming_security_issues_and_merge_requests
end
end
end
describe '#related_security_issues' do
it 'returns issues related to the given release issue iid' do
implementation_issue1 = create(:security_implementation_issue, issue: tracking_issue1)
allow(crawler).to receive(:security_tracking_issue).and_return(tracking_issue1)
expect(crawler).to receive(:security_issues_for).with(tracking_issue1.iid).and_return([tracking_issue1])
expect(crawler).to receive(:security_issues_and_merge_requests_for).with([tracking_issue1])
.and_return([implementation_issue1])
expect(crawler.related_security_issues).to eq([implementation_issue1])
end
end
describe '#security_issues_for' do
it 'returns only the security issues related to the tracking release issue' do
page = Gitlab::PaginatedResponse.new([issue1, issue2, issue3])
allow(ReleaseTools::GitlabClient.client)
.to receive(:issue_links)
.with(described_class::PUBLIC_PROJECT, tracking_issue1.iid)
.and_return(page)
issues = crawler.security_issues_for(tracking_issue1.iid)
expect(issues.length).to eq(2)
issues.each do |issue|
expect(issue.web_url).to include('gitlab-org/security')
end
end
it 'filters out closed issues' do
issue4 = create(
:issue,
project_id: 1,
iid: 2,
state: 'closed',
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/issues/2'
)
page = Gitlab::PaginatedResponse.new([issue1, issue2, issue3, issue4])
allow(ReleaseTools::GitlabClient.client)
.to receive(:issue_links)
.with(described_class::PUBLIC_PROJECT, tracking_issue1.iid)
.and_return(page)
issues = crawler.security_issues_for(tracking_issue1.iid)
expect(issues).not_to include(issue4)
end
end
describe '#evaluable_security_issues' do
let(:issue4) { create(:issue, project_id: 2, iid: 1) }
let(:project1_issue_page) { Gitlab::PaginatedResponse.new([tracking_issue1, issue1, issue3]) }
let(:project2_issue_page) { Gitlab::PaginatedResponse.new([issue4]) }
it 'returns the security issues with the specified label' do
stub_const('ReleaseTools::ManagedVersioning::PROJECTS', [ReleaseTools::Project::GitlabEe, ReleaseTools::Project::Gitaly, ReleaseTools::Project::GitlabPages])
implementation_issue1 = create(:security_implementation_issue, issue: tracking_issue1)
implementation_issue2 = create(:security_implementation_issue, issue: issue1)
implementation_issue3 = create(:security_implementation_issue, issue: issue3)
implementation_issue4 = create(:security_implementation_issue, issue: issue4)
results = [implementation_issue1, implementation_issue2, implementation_issue3, implementation_issue4]
allow(ReleaseTools::GitlabClient)
.to receive(:issues)
.with(ReleaseTools::Project::GitlabEe.security_path, labels: [described_class::SECURITY_TARGET_LABEL], state: described_class::OPENED)
.and_return(project1_issue_page)
allow(ReleaseTools::GitlabClient)
.to receive(:issues)
.with(ReleaseTools::Project::Gitaly.security_path, labels: [described_class::SECURITY_TARGET_LABEL], state: described_class::OPENED)
.and_return(project2_issue_page)
allow(ReleaseTools::GitlabClient)
.to receive(:issues)
.with(ReleaseTools::Project::GitlabPages.security_path, labels: [described_class::SECURITY_TARGET_LABEL], state: described_class::OPENED)
.and_return(nil)
expect(crawler)
.to receive(:security_issues_and_merge_requests_for)
.with([tracking_issue1, issue1, issue3, issue4]).and_return(results)
issues = crawler.evaluable_security_issues
expect(issues).to eq(results)
end
end
describe '#notifiable_security_issues_for' do
let(:issue1) { build(:issue, project_id: 1) }
let(:issue2) { build(:issue, project_id: 1) }
let(:issue3) { build(:issue, project_id: 1) }
let(:issue4) { build(:issue, project_id: 2) }
let(:project1_issue_page) { Gitlab::PaginatedResponse.new([issue1, issue2, issue3]) }
let(:project2_issue_page) { Gitlab::PaginatedResponse.new([issue4]) }
before do
allow(ReleaseTools::GitlabClient)
.to receive(:issues)
.with(
ReleaseTools::Project::GitlabEe.security_path,
labels: [described_class::SECURITY_NOTIFICATIONS_LABEL],
state: described_class::OPENED
)
.and_return(project1_issue_page)
allow(ReleaseTools::GitlabClient)
.to receive(:issues)
.with(
ReleaseTools::Project::Gitaly.security_path,
labels: [described_class::SECURITY_NOTIFICATIONS_LABEL],
state: described_class::OPENED
)
.and_return(project2_issue_page)
allow(ReleaseTools::GitlabClient)
.to receive(:issues)
.with(
ReleaseTools::Project::GitlabPages.security_path,
labels: [described_class::SECURITY_NOTIFICATIONS_LABEL],
state: described_class::OPENED
)
.and_return([])
allow(ReleaseTools::GitlabClient)
.to receive(:related_merge_requests)
.and_return(Gitlab::PaginatedResponse.new([]))
end
it 'returns the security issues with the specified label' do
gitlab_issues = crawler.notifiable_security_issues_for(ReleaseTools::Project::GitlabEe)
gitaly_issues = crawler.notifiable_security_issues_for(ReleaseTools::Project::Gitaly)
gitlab_pages_issues = crawler.notifiable_security_issues_for(ReleaseTools::Project::GitlabPages)
expect(gitlab_issues.map(&:issue)).to eq([issue1, issue2, issue3])
expect(gitaly_issues.map(&:issue)).to eq([issue4])
expect(gitlab_pages_issues).to eq([])
end
end
describe '#security_issues_and_merge_requests_for' do
it 'returns the security issues and merge requests related to the given issues' do
mr1 = create(
:merge_request,
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1'
)
mr2 = create(
:merge_request,
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1'
)
mr3 = create(
:merge_request,
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1'
)
issue_page = Gitlab::PaginatedResponse.new([issue1, issue3])
mr_page = Gitlab::PaginatedResponse.new([mr1, mr2, mr3])
allow(ReleaseTools::GitlabClient.client)
.to receive(:issue_links)
.with(described_class::PUBLIC_PROJECT, tracking_issue1.iid)
.and_return(issue_page)
allow(ReleaseTools::GitlabClient)
.to receive(:related_merge_requests)
.with(1, 1)
.and_return(mr_page)
allow(ReleaseTools::GitlabClient)
.to receive(:related_merge_requests)
.with(1, 2)
.and_return(mr_page)
allow(ReleaseTools::GitlabClient)
.to receive(:related_merge_requests)
.with(2, 1)
.and_return(mr_page)
issues = crawler.security_issues_and_merge_requests_for(issue_page)
expect(issues.length).to eq(2)
expect(issues[0].project_id).to eq(1)
expect(issues[0].iid).to eq(issue1.iid)
expect(issues[0].merge_requests).to eq([mr1, mr2])
end
it 'filters out closed merge requests' do
mr1 = create(
:merge_request,
state: described_class::OPENED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/1'
)
mr2 = create(
:merge_request,
state: described_class::CLOSED,
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/2'
)
mr3 = create(
:merge_request,
state: 'merged',
web_url: 'https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/3'
)
issue_page = Gitlab::PaginatedResponse.new([tracking_issue1])
mr_page = Gitlab::PaginatedResponse.new([mr1, mr2, mr3])
allow(ReleaseTools::GitlabClient)
.to receive(:related_merge_requests)
.with(tracking_issue1.project_id, tracking_issue1.iid)
.and_return(mr_page)
issues = crawler.security_issues_and_merge_requests_for(issue_page)
expect(issues[0].merge_requests.length).to eq(2)
expect(issues[0].merge_requests).to contain_exactly(mr1, mr3)
expect(issues[0].merge_requests).not_to include(mr2)
end
end
end