spec/lib/release_tools/patch_release/security_issue_spec.rb (212 lines of code) (raw):
# frozen_string_literal: true
require 'spec_helper'
describe ReleaseTools::PatchRelease::SecurityIssue do
let(:crawler) do
instance_spy(
ReleaseTools::Security::IssueCrawler,
related_security_issues: [create(:issue)]
)
end
let(:versions) do
[
ReleaseTools::Version.new('12.7.4'),
ReleaseTools::Version.new('12.6.6'),
ReleaseTools::Version.new('12.5.9')
]
end
let(:helm_version_finder) { instance_double(ReleaseTools::Helm::HelmVersionFinder) }
before do
coordinator = instance_double(
ReleaseTools::PatchRelease::Coordinator,
versions: versions
)
allow(ReleaseTools::PatchRelease::Coordinator)
.to receive(:new)
.and_return(coordinator)
allow(ReleaseTools::Security::IssueCrawler)
.to receive(:new)
.and_return(crawler)
allow(ReleaseTools::Helm::HelmVersionFinder)
.to receive(:new)
.and_return(helm_version_finder)
allow(helm_version_finder).to receive(:execute).with('12.7.4').and_return('1.3.4')
allow(helm_version_finder).to receive(:execute).with('12.6.6').and_return('1.4.5')
allow(helm_version_finder).to receive(:execute).with('12.5.9').and_return('1.5.6')
end
subject(:issue) { described_class.new }
it_behaves_like 'issuable #initialize'
describe '#title' do
context 'with a regular patch release' do
it 'includes all the versions' do
expect(issue.title).to eq('Patch release: 12.7.4, 12.6.6, 12.5.9')
end
end
context 'with a critical patch release' do
it 'includes the critical part' do
allow(ReleaseTools::SharedStatus)
.to receive(:critical_patch_release?)
.and_return(true)
expect(issue.title).to eq('Critical patch release: 12.7.4, 12.6.6, 12.5.9')
end
end
end
describe '#confidential?' do
it 'is always confidential' do
expect(issue).to be_confidential
end
end
describe '#labels' do
it 'includes the "security" label' do
expect(issue.labels).to eq 'Monthly Release,security'
end
end
describe '#description' do
let(:tracking_issue) { build(:issue, web_url: 'http://example.com') }
let(:security_release_pipeline) { build(:issue, web_url: 'http://example.com') }
before do
allow(issue).to receive_messages(security_release_tracking_issue: tracking_issue, release_pipeline: security_release_pipeline)
end
it 'includes a step to perform a patch release' do
content = issue.description
expect(content).to include 'Start the `security_release_release_preparation:start` job of the security pipeline'
end
it 'includes a step to publish the packages' do
content = issue.description
expect(content).to include 'Start the `security_release_publish:start` job of the security pipeline'
end
it 'includes the correct instance for packages' do
content = issue.description
expect(content).to include 'release.gitlab.net'
end
it 'returns Helm versions' do
content = issue.description
expect(content).to include 'https://dev.gitlab.org/gitlab/charts/gitlab/-/pipelines/?ref=v1.3.4'
expect(content).to include 'https://dev.gitlab.org/gitlab/charts/gitlab/-/pipelines/?ref=v1.4.5'
expect(content).to include 'https://dev.gitlab.org/gitlab/charts/gitlab/-/pipelines/?ref=v1.5.6'
end
end
describe '#version' do
it 'returns the highest version' do
expect(issue.version).to eq('12.7.4')
end
context 'with unsorted versions' do
let(:versions) do
[
ReleaseTools::Version.new('12.6.6'),
ReleaseTools::Version.new('12.7.4'),
ReleaseTools::Version.new('12.5.9')
]
end
it 'returns the highest version' do
expect(issue.version).to eq('12.7.4')
end
end
end
describe '#critical?' do
context 'with a regular patch release' do
it { is_expected.not_to be_critical }
end
context 'with a critical patch release' do
before do
allow(ReleaseTools::SharedStatus)
.to receive(:critical_patch_release?)
.and_return(true)
end
it { is_expected.to be_critical }
end
end
describe '#regular?' do
context 'with a regular patch release' do
it { is_expected.to be_regular }
end
context 'with a critical patch release' do
before do
allow(ReleaseTools::SharedStatus)
.to receive(:critical_patch_release?)
.and_return(true)
end
it { is_expected.not_to be_regular }
end
end
describe '#create' do
it 'creates a security pipeline' do
expect(issue).to receive(:release_pipeline)
expect(ReleaseTools::GitlabClient).to receive(:create_issue)
.with(issue, issue.project).and_return(true)
issue.create
end
end
describe '#release_pipeline' do
let(:web_url) { "https://gitlab.example.com/pipelines/123" }
let(:dry_run_url) { "https://example.com/foo/bar/-/pipelines/1" }
it "creates a security pipeline on the ops instance" do
expect(ReleaseTools::GitlabOpsClient).to receive(:create_pipeline).with(
ReleaseTools::Project::ReleaseTools,
{
SECURITY_RELEASE_PIPELINE: 'true',
SECURITY: nil
}
).and_return(double(web_url: web_url))
without_dry_run do
expect(issue.release_pipeline.web_url).to eq(web_url)
end
end
context 'critical patch release' do
it "creates a patch release injecting the SECURITY variable" do
expect(ReleaseTools::GitlabOpsClient).to receive(:create_pipeline).with(
ReleaseTools::Project::ReleaseTools,
{
SECURITY_RELEASE_PIPELINE: 'true',
SECURITY: 'critical'
}
).and_return(double(web_url: web_url))
without_dry_run do
ClimateControl.modify('SECURITY' => 'critical') do
expect(issue.release_pipeline.web_url).to eq(web_url)
end
end
expect(issue.release_pipeline.web_url).to eq(web_url)
end
end
context 'in dry run mode' do
it 'imitates the create_pipeline API response' do
expect(ReleaseTools::GitlabOpsClient).not_to receive(:create_pipeline)
expect(issue.release_pipeline.web_url).to eq(dry_run_url)
end
end
end
describe '#unsupported_projects_list' do
it 'returns a comma separated string list of the managed versioning projects' do
expect(issue.unsupported_projects_list).to eq('cng-ee, gitaly, gitlab-pages')
end
end
describe '#security_release_tracking_issue' do
it 'returns the patch release tracking issue' do
tracking_issue = build(:issue)
expect(ReleaseTools::GitlabClient).to receive(:next_security_tracking_issue)
.and_return(tracking_issue)
expect(issue.security_release_tracking_issue).to eq(tracking_issue)
end
end
describe '#version_type' do
it 'returns the patch release type' do
expect(issue.version_type).to eq('Non Critical')
end
context 'on a critical patch release' do
it 'returns the associated patch release type' do
allow(ReleaseTools::SharedStatus)
.to receive(:critical_patch_release?)
.and_return(true)
expect(issue.version_type).to eq('Critical')
end
end
end
describe '#due_date' do
it 'returns the same date as the tracking issue' do
tracking_issue = build(:issue, due_date: '2024-04-01')
allow(ReleaseTools::GitlabClient)
.to receive(:next_security_tracking_issue)
.and_return(tracking_issue)
expect(issue.due_date).to eq('2024-04-01')
end
end
end