debian-mirror-gitlab/spec/lib/gitlab/ci/jwt_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

186 lines
5.8 KiB
Ruby
Raw Normal View History

2020-04-22 19:07:51 +05:30
# frozen_string_literal: true
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec.describe Gitlab::Ci::Jwt do
2020-04-22 19:07:51 +05:30
let(:namespace) { build_stubbed(:namespace) }
let(:project) { build_stubbed(:project, namespace: namespace) }
let(:user) { build_stubbed(:user) }
let(:pipeline) { build_stubbed(:ci_pipeline, ref: 'auto-deploy-2020-03-19') }
let(:build) do
build_stubbed(
:ci_build,
project: project,
user: user,
pipeline: pipeline
)
end
describe '#payload' do
subject(:payload) { described_class.new(build, ttl: 30).payload }
it 'has correct values for the standard JWT attributes' do
2020-11-24 15:15:51 +05:30
freeze_time do
2020-04-22 19:07:51 +05:30
now = Time.now.to_i
aggregate_failures do
expect(payload[:iss]).to eq(Settings.gitlab.host)
expect(payload[:iat]).to eq(now)
expect(payload[:exp]).to eq(now + 30)
expect(payload[:sub]).to eq("job_#{build.id}")
end
end
end
it 'has correct values for the custom attributes' do
aggregate_failures do
expect(payload[:namespace_id]).to eq(namespace.id.to_s)
expect(payload[:namespace_path]).to eq(namespace.full_path)
expect(payload[:project_id]).to eq(project.id.to_s)
expect(payload[:project_path]).to eq(project.full_path)
expect(payload[:user_id]).to eq(user.id.to_s)
expect(payload[:user_email]).to eq(user.email)
expect(payload[:user_login]).to eq(user.username)
expect(payload[:pipeline_id]).to eq(pipeline.id.to_s)
2021-09-04 01:27:46 +05:30
expect(payload[:pipeline_source]).to eq(pipeline.source.to_s)
2020-04-22 19:07:51 +05:30
expect(payload[:job_id]).to eq(build.id.to_s)
expect(payload[:ref]).to eq(pipeline.source_ref)
2021-03-11 19:13:27 +05:30
expect(payload[:ref_protected]).to eq(build.protected.to_s)
expect(payload[:environment]).to be_nil
expect(payload[:environment_protected]).to be_nil
2022-08-13 15:12:31 +05:30
expect(payload[:deployment_tier]).to be_nil
2020-04-22 19:07:51 +05:30
end
end
it 'skips user related custom attributes if build has no user assigned' do
allow(build).to receive(:user).and_return(nil)
expect { payload }.not_to raise_error
end
describe 'ref type' do
context 'branches' do
it 'is "branch"' do
expect(payload[:ref_type]).to eq('branch')
end
end
context 'tags' do
let(:build) { build_stubbed(:ci_build, :on_tag, project: project) }
it 'is "tag"' do
expect(payload[:ref_type]).to eq('tag')
end
end
context 'merge requests' do
let(:pipeline) { build_stubbed(:ci_pipeline, :detached_merge_request_pipeline) }
it 'is "branch"' do
expect(payload[:ref_type]).to eq('branch')
end
end
end
describe 'ref_protected' do
it 'is false when ref is not protected' do
expect(build).to receive(:protected).and_return(false)
expect(payload[:ref_protected]).to eq('false')
end
it 'is true when ref is protected' do
expect(build).to receive(:protected).and_return(true)
expect(payload[:ref_protected]).to eq('true')
end
end
2021-03-11 19:13:27 +05:30
describe 'environment' do
2022-08-13 15:12:31 +05:30
let(:environment) { build_stubbed(:environment, project: project, name: 'production', tier: 'production') }
2021-03-11 19:13:27 +05:30
let(:build) do
build_stubbed(
:ci_build,
project: project,
user: user,
pipeline: pipeline,
environment: environment.name
)
end
before do
allow(build).to receive(:persisted_environment).and_return(environment)
end
it 'has correct values for environment attributes' do
expect(payload[:environment]).to eq('production')
expect(payload[:environment_protected]).to eq('false')
2022-08-13 15:12:31 +05:30
expect(payload[:deployment_tier]).to eq('production')
end
describe 'deployment_tier' do
context 'when build options specifies a different deployment_tier' do
before do
build.options[:environment] = { name: environment.name, deployment_tier: 'development' }
end
it 'uses deployment_tier from build options' do
expect(payload[:deployment_tier]).to eq('development')
end
end
2021-03-11 19:13:27 +05:30
end
end
2020-04-22 19:07:51 +05:30
end
describe '.for_build' do
2021-01-29 00:20:46 +05:30
shared_examples 'generating JWT for build' do
context 'when signing key is present' do
2022-08-13 15:12:31 +05:30
let_it_be(:rsa_key) { OpenSSL::PKey::RSA.generate(3072) }
let_it_be(:rsa_key_data) { rsa_key.to_s }
2020-04-22 19:07:51 +05:30
2021-01-29 00:20:46 +05:30
it 'generates JWT with key id' do
_payload, headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
expect(headers['kid']).to eq(rsa_key.public_key.to_jwk['kid'])
end
it 'generates JWT for the given job with ttl equal to build timeout' do
expect(build).to receive(:metadata_timeout).and_return(3_600)
payload, _headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
ttl = payload["exp"] - payload["iat"]
expect(ttl).to eq(3_600)
end
it 'generates JWT for the given job with default ttl if build timeout is not set' do
expect(build).to receive(:metadata_timeout).and_return(nil)
payload, _headers = JWT.decode(jwt, rsa_key.public_key, true, { algorithm: 'RS256' })
ttl = payload["exp"] - payload["iat"]
2020-04-22 19:07:51 +05:30
2021-01-29 00:20:46 +05:30
expect(ttl).to eq(5.minutes.to_i)
end
end
context 'when signing key is missing' do
let(:rsa_key_data) { nil }
2020-04-22 19:07:51 +05:30
2021-01-29 00:20:46 +05:30
it 'raises NoSigningKeyError' do
expect { jwt }.to raise_error described_class::NoSigningKeyError
end
end
2020-04-22 19:07:51 +05:30
end
2021-01-29 00:20:46 +05:30
subject(:jwt) { described_class.for_build(build) }
2022-07-23 23:45:48 +05:30
context 'when ci_jwt_signing_key is present' do
2021-01-29 00:20:46 +05:30
before do
stub_application_setting(ci_jwt_signing_key: rsa_key_data)
end
2020-04-22 19:07:51 +05:30
2021-01-29 00:20:46 +05:30
it_behaves_like 'generating JWT for build'
2020-04-22 19:07:51 +05:30
end
end
end