diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb index fdd889f54162ab6ff4ef2a1cec2a0e2591edbce2..118eb8e2d7ca5f695c3cf942469442d9e6a2423d 100644 --- a/lib/container_registry/client.rb +++ b/lib/container_registry/client.rb @@ -13,6 +13,8 @@ class Client DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE = 'application/vnd.docker.distribution.manifest.v2+json' OCI_MANIFEST_V1_TYPE = 'application/vnd.oci.image.manifest.v1+json' CONTAINER_IMAGE_V1_TYPE = 'application/vnd.docker.container.image.v1+json' + REGISTRY_VERSION_HEADER = 'gitlab-container-registry-version' + REGISTRY_FEATURES_HEADER = 'gitlab-container-registry-features' ACCEPTED_TYPES = [DOCKER_DISTRIBUTION_MANIFEST_V2_TYPE, OCI_MANIFEST_V1_TYPE].freeze @@ -24,6 +26,21 @@ def initialize(base_uri, options = {}) @options = options end + def registry_info + response = faraday.get("/v2/") + + return {} unless response&.success? + + version = response.headers[REGISTRY_VERSION_HEADER] + features = response.headers.fetch(REGISTRY_FEATURES_HEADER, '') + + { + version: version, + features: features.split(',').map(&:strip), + vendor: version ? 'gitlab' : 'other' + } + end + def repository_tags(name) response_body faraday.get("/v2/#{name}/tags/list") end diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb index 0aad6568793b3a8cd1a9415116f3898d3bc05347..18bcff65f4102fb39bc3b5355f0f971162f9a20c 100644 --- a/spec/lib/container_registry/client_spec.rb +++ b/spec/lib/container_registry/client_spec.rb @@ -85,7 +85,7 @@ it 'follows 307 redirect for GET /v2/:name/blobs/:digest' do stub_request(:get, "http://container-registry/v2/group/test/blobs/sha256:0123456789012345") .with(headers: blob_headers) - .to_return(status: 307, body: "", headers: { Location: 'http://redirected' }) + .to_return(status: 307, body: '', headers: { Location: 'http://redirected' }) # We should probably use hash_excluding here, but that requires an update to WebMock: # https://github.com/bblimke/webmock/blob/master/lib/webmock/matchers/hash_excluding_matcher.rb stub_request(:get, "http://redirected/") @@ -238,4 +238,54 @@ def stub_upload(path, content, digest, status = 200) it { is_expected.to be_falsey } end end + + def stub_registry_info(headers: {}, status: 200) + stub_request(:get, 'http://container-registry/v2/') + .to_return(status: status, body: "", headers: headers) + end + + describe '#registry_info' do + subject { client.registry_info } + + context 'when the check is successful' do + context 'when using the GitLab container registry' do + before do + stub_registry_info(headers: { + 'GitLab-Container-Registry-Version' => '2.9.1-gitlab', + 'GitLab-Container-Registry-Features' => 'a,b,c' + }) + end + + it 'identifies the vendor as "gitlab"' do + expect(subject).to include(vendor: 'gitlab') + end + + it 'identifies version and features' do + expect(subject).to include(version: '2.9.1-gitlab', features: %w[a b c]) + end + end + + context 'when using a third-party container registry' do + before do + stub_registry_info + end + + it 'identifies the vendor as "other"' do + expect(subject).to include(vendor: 'other') + end + + it 'does not identify version or features' do + expect(subject).to include(version: nil, features: []) + end + end + end + + context 'when the check is not successful' do + it 'does not identify vendor, version or features' do + stub_registry_info(status: 500) + + expect(subject).to eq({}) + end + end + end end