gitlab-org--gitlab-foss/spec/services/pages_domains/obtain_lets_encrypt_certifi...

193 lines
5.1 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService do
include LetsEncryptHelpers
let(:pages_domain) { create(:pages_domain, :without_certificate, :without_key) }
let(:service) { described_class.new(pages_domain) }
before do
stub_lets_encrypt_settings
end
around do |example|
Sidekiq::Testing.fake! do
example.run
end
end
def expect_to_create_acme_challenge
expect(::PagesDomains::CreateAcmeOrderService).to receive(:new).with(pages_domain)
.and_wrap_original do |m, *args|
create_service = m.call(*args)
expect(create_service).to receive(:execute)
create_service
end
end
def stub_lets_encrypt_order(url, status)
order = ::Gitlab::LetsEncrypt::Order.new(acme_order_double(status: status))
allow_next_instance_of(::Gitlab::LetsEncrypt::Client) do |instance|
allow(instance).to receive(:load_order).with(url).and_return(order)
end
order
end
context 'when there is no acme order' do
it 'creates acme order and schedules next step' do
expect_to_create_acme_challenge
expect(PagesDomainSslRenewalWorker).to(
receive(:perform_in).with(described_class::CHALLENGE_PROCESSING_DELAY, pages_domain.id)
.and_return(nil).once
)
service.execute
end
end
context 'when there is expired acme order' do
let!(:existing_order) do
create(:pages_domain_acme_order, :expired, pages_domain: pages_domain)
end
it 'removes acme order and creates new one' do
expect_to_create_acme_challenge
service.execute
expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil
end
end
%w(pending processing).each do |status|
context "there is an order in '#{status}' status" do
let(:existing_order) do
create(:pages_domain_acme_order, pages_domain: pages_domain)
end
before do
stub_lets_encrypt_order(existing_order.url, status)
end
it 'does not raise errors' do
expect do
service.execute
end.not_to raise_error
end
end
end
context 'when order is ready' do
let(:existing_order) do
create(:pages_domain_acme_order, pages_domain: pages_domain)
end
let!(:api_order) do
stub_lets_encrypt_order(existing_order.url, 'ready')
end
it 'request certificate and schedules next step' do
expect(api_order).to receive(:request_certificate).and_call_original
expect(PagesDomainSslRenewalWorker).to(
receive(:perform_in).with(described_class::CERTIFICATE_PROCESSING_DELAY, pages_domain.id)
.and_return(nil).once
)
service.execute
end
end
context 'when order is valid' do
let(:existing_order) do
create(:pages_domain_acme_order, pages_domain: pages_domain)
end
let!(:api_order) do
stub_lets_encrypt_order(existing_order.url, 'valid')
end
let(:certificate) do
key = OpenSSL::PKey.read(existing_order.private_key)
subject = "/C=BE/O=Test/OU=Test/CN=#{pages_domain.domain}"
cert = OpenSSL::X509::Certificate.new
cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject)
cert.not_before = Time.current
cert.not_after = 1.year.from_now
cert.public_key = key.public_key
cert.serial = 0x0
cert.version = 2
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = cert
ef.issuer_certificate = cert
cert.extensions = [
ef.create_extension("basicConstraints", "CA:TRUE", true),
ef.create_extension("subjectKeyIdentifier", "hash")
]
cert.add_extension ef.create_extension("authorityKeyIdentifier",
"keyid:always,issuer:always")
cert.sign key, OpenSSL::Digest.new('SHA256')
cert.to_pem
end
before do
expect(api_order).to receive(:certificate) { certificate }
end
it 'saves private_key and certificate for domain' do
service.execute
expect(pages_domain.key).to be_present
expect(pages_domain.certificate).to eq(certificate)
end
it 'marks certificate as gitlab_provided' do
service.execute
expect(pages_domain.certificate_source).to eq("gitlab_provided")
end
it 'removes order from database' do
service.execute
expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil
end
end
context 'when order is invalid' do
let(:existing_order) do
create(:pages_domain_acme_order, pages_domain: pages_domain)
end
let!(:api_order) do
stub_lets_encrypt_order(existing_order.url, 'invalid')
end
it 'saves error to domain and deletes acme order' do
expect do
service.execute
end.to change { pages_domain.reload.auto_ssl_failed }.from(false).to(true)
expect(PagesDomainAcmeOrder.find_by_id(existing_order.id)).to be_nil
end
it 'sends notification' do
expect_next_instance_of(NotificationService) do |notification_service|
expect(notification_service).to receive(:pages_domain_auto_ssl_failed).with(pages_domain)
end
service.execute
end
end
end