1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
# frozen_string_literal: true
###
# API endpoints for the Helm package registry
module API
class HelmPackages < ::API::Base
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
include ::API::Helpers::Authentication
feature_category :package_registry
urgency :low
PACKAGE_FILENAME = 'package.tgz'
HELM_REQUIREMENTS = {
channel: API::NO_SLASH_URL_PART_REGEX,
file_name: API::NO_SLASH_URL_PART_REGEX
}.freeze
content_type :binary, 'application/octet-stream'
content_type :yaml, 'text/yaml'
formatter :yaml, ->(object, _) { object.serializable_hash.stringify_keys.to_yaml }
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
end
before do
require_packages_enabled!
end
params do
requires :id, types: [Integer, String], desc: 'The ID or full path of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/helm', requirements: HELM_REQUIREMENTS do
desc 'Download a chart index' do
detail 'This feature was introduced in GitLab 14.0'
success code: 200
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' }
]
tags %w[helm_packages]
end
params do
requires :channel, type: String, desc: 'Helm channel', regexp: Gitlab::Regex.helm_channel_regex, documentation: { example: 'stable' }
end
get ":channel/index.yaml" do
project = authorized_user_project(action: :read_package)
authorize_read_package!(project)
packages = Packages::Helm::PackagesFinder.new(project, params[:channel]).execute
env['api.format'] = :yaml
present ::Packages::Helm::IndexPresenter.new(params[:id], params[:channel], packages),
with: ::API::Entities::Helm::Index
end
desc 'Download a chart' do
detail 'This feature was introduced in GitLab 14.0'
success code: 200
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not Found' }
]
tags %w[helm_packages]
end
params do
requires :channel, type: String, desc: 'Helm channel', regexp: Gitlab::Regex.helm_channel_regex, documentation: { example: 'stable' }
requires :file_name, type: String, desc: 'Helm package file name', documentation: { example: 'mychart' }
end
get ":channel/charts/:file_name.tgz" do
not_found!("Format #{params[:format]}") unless params[:format].nil?
project = authorized_user_project(action: :read_package)
authorize_read_package!(project)
package_file = Packages::Helm::PackageFilesFinder.new(project, params[:channel], file_name: "#{params[:file_name]}.tgz").most_recent!
track_package_event('pull_package', :helm, project: project, namespace: project.namespace, property: 'i_package_helm_user')
present_package_file!(package_file)
end
desc 'Authorize a chart upload from workhorse' do
detail 'This feature was introduced in GitLab 14.0'
success code: 200
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not Found' }
]
tags %w[helm_packages]
end
params do
requires :channel, type: String, desc: 'Helm channel', regexp: Gitlab::Regex.helm_channel_regex, documentation: { example: 'stable' }
end
post "api/:channel/charts/authorize" do
authorize_workhorse!(
subject: authorized_user_project,
has_length: false,
maximum_size: authorized_user_project.actual_limits.helm_max_file_size
)
end
desc 'Upload a chart' do
detail 'This feature was introduced in GitLab 14.0'
success code: 201
failure [
{ code: 401, message: 'Unauthorized' },
{ code: 403, message: 'Forbidden' },
{ code: 404, message: 'Not Found' }
]
tags %w[helm_packages]
end
params do
requires :channel, type: String, desc: 'Helm channel', regexp: Gitlab::Regex.helm_channel_regex, documentation: { example: 'stable' }
requires :chart, type: ::API::Validations::Types::WorkhorseFile, desc: 'The chart file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
post "api/:channel/charts" do
authorize_upload!(authorized_user_project)
bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:helm_max_file_size, params[:chart].size)
package = ::Packages::CreateTemporaryPackageService.new(
authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job)
).execute(:helm, name: ::Packages::Helm::TEMPORARY_PACKAGE_NAME)
chart_params = {
file: params[:chart],
file_name: PACKAGE_FILENAME
}
chart_package_file = ::Packages::CreatePackageFileService.new(
package, chart_params.merge(build: current_authenticated_job)
).execute
track_package_event('push_package', :helm, project: authorized_user_project, namespace: authorized_user_project.namespace,
property: 'i_package_helm_user')
::Packages::Helm::ExtractionWorker.perform_async(params[:channel], chart_package_file.id) # rubocop:disable CodeReuse/Worker
created!
rescue ObjectStorage::RemoteStoreError => e
Gitlab::ErrorTracking.track_exception(e, extra: { channel: params[:channel], project_id: authorized_user_project.id })
forbidden!
end
end
end
end
end
|