summaryrefslogtreecommitdiff
path: root/app/services/dependency_proxy
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/dependency_proxy')
-rw-r--r--app/services/dependency_proxy/auth_token_service.rb21
-rw-r--r--app/services/dependency_proxy/base_service.rb10
-rw-r--r--app/services/dependency_proxy/download_blob_service.rb10
-rw-r--r--app/services/dependency_proxy/find_or_create_manifest_service.rb52
-rw-r--r--app/services/dependency_proxy/head_manifest_service.rb29
-rw-r--r--app/services/dependency_proxy/pull_manifest_service.rb18
6 files changed, 127 insertions, 13 deletions
diff --git a/app/services/dependency_proxy/auth_token_service.rb b/app/services/dependency_proxy/auth_token_service.rb
new file mode 100644
index 00000000000..16279ed12b0
--- /dev/null
+++ b/app/services/dependency_proxy/auth_token_service.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module DependencyProxy
+ class AuthTokenService < DependencyProxy::BaseService
+ attr_reader :token
+
+ def initialize(token)
+ @token = token
+ end
+
+ def execute
+ JSONWebToken::HMACToken.decode(token, ::Auth::DependencyProxyAuthenticationService.secret).first
+ end
+
+ class << self
+ def decoded_token_payload(token)
+ self.new(token).execute
+ end
+ end
+ end
+end
diff --git a/app/services/dependency_proxy/base_service.rb b/app/services/dependency_proxy/base_service.rb
index 1b2d4b14a27..944877fd5f9 100644
--- a/app/services/dependency_proxy/base_service.rb
+++ b/app/services/dependency_proxy/base_service.rb
@@ -2,6 +2,16 @@
module DependencyProxy
class BaseService < ::BaseService
+ class DownloadError < StandardError
+ attr_reader :http_status
+
+ def initialize(message, http_status)
+ @http_status = http_status
+
+ super(message)
+ end
+ end
+
private
def registry
diff --git a/app/services/dependency_proxy/download_blob_service.rb b/app/services/dependency_proxy/download_blob_service.rb
index 3c690683bf6..b3548c8a126 100644
--- a/app/services/dependency_proxy/download_blob_service.rb
+++ b/app/services/dependency_proxy/download_blob_service.rb
@@ -2,16 +2,6 @@
module DependencyProxy
class DownloadBlobService < DependencyProxy::BaseService
- class DownloadError < StandardError
- attr_reader :http_status
-
- def initialize(message, http_status)
- @http_status = http_status
-
- super(message)
- end
- end
-
def initialize(image, blob_sha, token)
@image = image
@blob_sha = blob_sha
diff --git a/app/services/dependency_proxy/find_or_create_manifest_service.rb b/app/services/dependency_proxy/find_or_create_manifest_service.rb
new file mode 100644
index 00000000000..6b46f5e4c59
--- /dev/null
+++ b/app/services/dependency_proxy/find_or_create_manifest_service.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module DependencyProxy
+ class FindOrCreateManifestService < DependencyProxy::BaseService
+ def initialize(group, image, tag, token)
+ @group = group
+ @image = image
+ @tag = tag
+ @token = token
+ @file_name = "#{@image}:#{@tag}.json"
+ @manifest = nil
+ end
+
+ def execute
+ @manifest = @group.dependency_proxy_manifests
+ .find_or_initialize_by_file_name(@file_name)
+
+ head_result = DependencyProxy::HeadManifestService.new(@image, @tag, @token).execute
+
+ return success(manifest: @manifest) if cached_manifest_matches?(head_result)
+
+ pull_new_manifest
+ respond
+ rescue Timeout::Error, *Gitlab::HTTP::HTTP_ERRORS
+ respond
+ end
+
+ private
+
+ def pull_new_manifest
+ DependencyProxy::PullManifestService.new(@image, @tag, @token).execute_with_manifest do |new_manifest|
+ @manifest.update!(
+ digest: new_manifest[:digest],
+ file: new_manifest[:file],
+ size: new_manifest[:file].size
+ )
+ end
+ end
+
+ def cached_manifest_matches?(head_result)
+ @manifest && @manifest.digest == head_result[:digest]
+ end
+
+ def respond
+ if @manifest.persisted?
+ success(manifest: @manifest)
+ else
+ error('Failed to download the manifest from the external registry', 503)
+ end
+ end
+ end
+end
diff --git a/app/services/dependency_proxy/head_manifest_service.rb b/app/services/dependency_proxy/head_manifest_service.rb
new file mode 100644
index 00000000000..87d9c417c98
--- /dev/null
+++ b/app/services/dependency_proxy/head_manifest_service.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module DependencyProxy
+ class HeadManifestService < DependencyProxy::BaseService
+ def initialize(image, tag, token)
+ @image = image
+ @tag = tag
+ @token = token
+ end
+
+ def execute
+ response = Gitlab::HTTP.head(manifest_url, headers: auth_headers)
+
+ if response.success?
+ success(digest: response.headers['docker-content-digest'])
+ else
+ error(response.body, response.code)
+ end
+ rescue Timeout::Error => exception
+ error(exception.message, 599)
+ end
+
+ private
+
+ def manifest_url
+ registry.manifest_url(@image, @tag)
+ end
+ end
+end
diff --git a/app/services/dependency_proxy/pull_manifest_service.rb b/app/services/dependency_proxy/pull_manifest_service.rb
index fc54ef85c96..5c804489fd1 100644
--- a/app/services/dependency_proxy/pull_manifest_service.rb
+++ b/app/services/dependency_proxy/pull_manifest_service.rb
@@ -8,13 +8,25 @@ module DependencyProxy
@token = token
end
- def execute
+ def execute_with_manifest
+ raise ArgumentError, 'Block must be provided' unless block_given?
+
response = Gitlab::HTTP.get(manifest_url, headers: auth_headers)
if response.success?
- success(manifest: response.body)
+ file = Tempfile.new
+
+ begin
+ file.write(response)
+ file.flush
+
+ yield(success(file: file, digest: response.headers['docker-content-digest']))
+ ensure
+ file.close
+ file.unlink
+ end
else
- error(response.body, response.code)
+ yield(error(response.body, response.code))
end
rescue Timeout::Error => exception
error(exception.message, 599)