summaryrefslogtreecommitdiff
path: root/lib/api/conan_packages.rb
blob: 1d941e422a71583077a03446d99b225364f166d0 (plain)
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# frozen_string_literal: true

# Conan Package Manager Client API
#
# These API endpoints are not consumed directly by users, so there is no documentation for the
# individual endpoints. They are called by the Conan package manager client when users run commands
# like `conan install` or `conan upload`. The usage of the GitLab Conan repository is documented here:
# https://docs.gitlab.com/ee/user/packages/conan_repository/#installing-a-package
#
# Technical debt: https://gitlab.com/gitlab-org/gitlab/issues/35798
module API
  class ConanPackages < Grape::API::Instance
    helpers ::API::Helpers::PackagesManagerClientsHelpers

    PACKAGE_REQUIREMENTS = {
      package_name: API::NO_SLASH_URL_PART_REGEX,
      package_version: API::NO_SLASH_URL_PART_REGEX,
      package_username: API::NO_SLASH_URL_PART_REGEX,
      package_channel: API::NO_SLASH_URL_PART_REGEX
    }.freeze

    FILE_NAME_REQUIREMENTS = {
      file_name: API::NO_SLASH_URL_PART_REGEX
    }.freeze

    PACKAGE_COMPONENT_REGEX = Gitlab::Regex.conan_recipe_component_regex
    CONAN_REVISION_REGEX = Gitlab::Regex.conan_revision_regex

    before do
      require_packages_enabled!

      # Personal access token will be extracted from Bearer or Basic authorization
      # in the overridden find_personal_access_token or find_user_from_job_token helpers
      authenticate!
    end

    namespace 'packages/conan/v1' do
      desc 'Ping the Conan API' do
        detail 'This feature was introduced in GitLab 12.2'
      end
      route_setting :authentication, job_token_allowed: true
      get 'ping' do
        header 'X-Conan-Server-Capabilities', [].join(',')
      end

      desc 'Search for packages' do
        detail 'This feature was introduced in GitLab 12.4'
      end
      params do
        requires :q, type: String, desc: 'Search query'
      end
      route_setting :authentication, job_token_allowed: true
      get 'conans/search' do
        service = ::Packages::Conan::SearchService.new(current_user, query: params[:q]).execute
        service.payload
      end

      namespace 'users' do
        format :txt

        desc 'Authenticate user against conan CLI' do
          detail 'This feature was introduced in GitLab 12.2'
        end
        route_setting :authentication, job_token_allowed: true
        get 'authenticate' do
          unauthorized! unless token

          token.to_jwt
        end

        desc 'Check for valid user credentials per conan CLI' do
          detail 'This feature was introduced in GitLab 12.4'
        end
        route_setting :authentication, job_token_allowed: true
        get 'check_credentials' do
          authenticate!
          :ok
        end
      end

      params do
        requires :package_name, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package name'
        requires :package_version, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package version'
        requires :package_username, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package username'
        requires :package_channel, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package channel'
      end
      namespace 'conans/:package_name/:package_version/:package_username/:package_channel', requirements: PACKAGE_REQUIREMENTS do
        # Get the snapshot
        #
        # the snapshot is a hash of { filename: md5 hash }
        # md5 hash is the has of that file. This hash is used to diff the files existing on the client
        # to determine which client files need to be uploaded if no recipe exists the snapshot is empty
        desc 'Package Snapshot' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        params do
          requires :conan_package_reference, type: String, desc: 'Conan package ID'
        end
        route_setting :authentication, job_token_allowed: true
        get 'packages/:conan_package_reference' do
          authorize!(:read_package, project)

          presenter = ::Packages::Conan::PackagePresenter.new(
            recipe,
            current_user,
            project,
            conan_package_reference: params[:conan_package_reference]
          )

          present presenter, with: ::API::Entities::ConanPackage::ConanPackageSnapshot
        end

        desc 'Recipe Snapshot' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        route_setting :authentication, job_token_allowed: true
        get do
          authorize!(:read_package, project)

          presenter = ::Packages::Conan::PackagePresenter.new(recipe, current_user, project)

          present presenter, with: ::API::Entities::ConanPackage::ConanRecipeSnapshot
        end

        # Get the manifest
        # returns the download urls for the existing recipe in the registry
        #
        # the manifest is a hash of { filename: url }
        # where the url is the download url for the file
        desc 'Package Digest' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        params do
          requires :conan_package_reference, type: String, desc: 'Conan package ID'
        end
        route_setting :authentication, job_token_allowed: true
        get 'packages/:conan_package_reference/digest' do
          present_package_download_urls
        end

        desc 'Recipe Digest' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        route_setting :authentication, job_token_allowed: true
        get 'digest' do
          present_recipe_download_urls
        end

        # Get the download urls
        #
        # returns the download urls for the existing recipe or package in the registry
        #
        # the manifest is a hash of { filename: url }
        # where the url is the download url for the file
        desc 'Package Download Urls' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        params do
          requires :conan_package_reference, type: String, desc: 'Conan package ID'
        end
        route_setting :authentication, job_token_allowed: true
        get 'packages/:conan_package_reference/download_urls' do
          present_package_download_urls
        end

        desc 'Recipe Download Urls' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        route_setting :authentication, job_token_allowed: true
        get 'download_urls' do
          present_recipe_download_urls
        end

        # Get the upload urls
        #
        # request body contains { filename: filesize } where the filename is the
        # name of the file the conan client is requesting to upload
        #
        # returns { filename: url }
        # where the url is the upload url for the file that the conan client will use
        desc 'Package Upload Urls' do
          detail 'This feature was introduced in GitLab 12.4'
        end
        params do
          requires :conan_package_reference, type: String, desc: 'Conan package ID'
        end
        route_setting :authentication, job_token_allowed: true
        post 'packages/:conan_package_reference/upload_urls' do
          authorize!(:read_package, project)

          status 200
          upload_urls = package_upload_urls(::Packages::Conan::FileMetadatum::PACKAGE_FILES)

          present upload_urls, with: ::API::Entities::ConanPackage::ConanUploadUrls
        end

        desc 'Recipe Upload Urls' do
          detail 'This feature was introduced in GitLab 12.4'
        end
        route_setting :authentication, job_token_allowed: true
        post 'upload_urls' do
          authorize!(:read_package, project)

          status 200
          upload_urls = recipe_upload_urls(::Packages::Conan::FileMetadatum::RECIPE_FILES)

          present upload_urls, with: ::API::Entities::ConanPackage::ConanUploadUrls
        end

        desc 'Delete Package' do
          detail 'This feature was introduced in GitLab 12.5'
        end
        route_setting :authentication, job_token_allowed: true
        delete do
          authorize!(:destroy_package, project)

          track_event('delete_package')

          package.destroy
        end
      end

      params do
        requires :package_name, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package name'
        requires :package_version, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package version'
        requires :package_username, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package username'
        requires :package_channel, type: String, regexp: PACKAGE_COMPONENT_REGEX, desc: 'Package channel'
        requires :recipe_revision, type: String, regexp: CONAN_REVISION_REGEX, desc: 'Conan Recipe Revision'
      end
      namespace 'files/:package_name/:package_version/:package_username/:package_channel/:recipe_revision', requirements: PACKAGE_REQUIREMENTS do
        before do
          authenticate_non_get!
        end

        params do
          requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.conan_file_name_regex
        end
        namespace 'export/:file_name', requirements: FILE_NAME_REQUIREMENTS do
          desc 'Download recipe files' do
            detail 'This feature was introduced in GitLab 12.6'
          end
          route_setting :authentication, job_token_allowed: true
          get do
            download_package_file(:recipe_file)
          end

          desc 'Upload recipe package files' do
            detail 'This feature was introduced in GitLab 12.6'
          end
          params do
            use :workhorse_upload_params
          end
          route_setting :authentication, job_token_allowed: true
          put do
            upload_package_file(:recipe_file)
          end

          desc 'Workhorse authorize the conan recipe file' do
            detail 'This feature was introduced in GitLab 12.6'
          end
          route_setting :authentication, job_token_allowed: true
          put 'authorize' do
            authorize_workhorse!(subject: project)
          end
        end

        params do
          requires :conan_package_reference, type: String, desc: 'Conan Package ID'
          requires :package_revision, type: String, desc: 'Conan Package Revision'
          requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.conan_file_name_regex
        end
        namespace 'package/:conan_package_reference/:package_revision/:file_name', requirements: FILE_NAME_REQUIREMENTS do
          desc 'Download package files' do
            detail 'This feature was introduced in GitLab 12.5'
          end
          route_setting :authentication, job_token_allowed: true
          get do
            download_package_file(:package_file)
          end

          desc 'Workhorse authorize the conan package file' do
            detail 'This feature was introduced in GitLab 12.6'
          end
          route_setting :authentication, job_token_allowed: true
          put 'authorize' do
            authorize_workhorse!(subject: project)
          end

          desc 'Upload package files' do
            detail 'This feature was introduced in GitLab 12.6'
          end
          params do
            use :workhorse_upload_params
          end
          route_setting :authentication, job_token_allowed: true
          put do
            upload_package_file(:package_file)
          end
        end
      end
    end

    helpers do
      include Gitlab::Utils::StrongMemoize
      include ::API::Helpers::RelatedResourcesHelpers
      include ::API::Helpers::Packages::Conan::ApiHelpers
    end
  end
end