summaryrefslogtreecommitdiff
path: root/lib/api/ci/secure_files.rb
blob: ee39bdfd90cabe80652f100c4ce0647ab0ad1db3 (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
# frozen_string_literal: true

module API
  module Ci
    class SecureFiles < ::API::Base
      include PaginationParams

      before do
        authenticate!
        feature_flag_enabled?
        authorize! :read_secure_files, user_project
      end

      feature_category :pipeline_authoring

      default_format :json

      params do
        requires :id, type: String, desc: 'The ID of a project'
      end

      resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
        desc 'List all Secure Files for a Project'
        params do
          use :pagination
        end
        route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
        get ':id/secure_files' do
          secure_files = user_project.secure_files
          present paginate(secure_files), with: Entities::Ci::SecureFile
        end

        desc 'Get an individual Secure File'
        params do
          requires :id, type: Integer, desc: 'The Secure File ID'
        end

        route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
        get ':id/secure_files/:secure_file_id' do
          secure_file = user_project.secure_files.find(params[:secure_file_id])
          present secure_file, with: Entities::Ci::SecureFile
        end

        desc 'Download a Secure File'
        route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
        get ':id/secure_files/:secure_file_id/download' do
          secure_file = user_project.secure_files.find(params[:secure_file_id])

          content_type 'application/octet-stream'
          env['api.format'] = :binary
          header['Content-Disposition'] = "attachment; filename=#{secure_file.name}"
          body secure_file.file.read
        end

        resource do
          before do
            read_only_feature_flag_enabled?
            authorize! :admin_secure_files, user_project
          end

          desc 'Upload a Secure File'
          params do
            requires :name, type: String, desc: 'The name of the file'
            requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded'
            optional :permissions, type: String, desc: 'The file permissions', default: 'read_only', values: %w[read_only read_write execute]
          end
          route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
          post ':id/secure_files' do
            secure_file = user_project.secure_files.new(
              name: params[:name],
              permissions: params[:permissions] || :read_only
            )

            secure_file.file = params[:file]

            file_too_large! unless secure_file.file.size < ::Ci::SecureFile::FILE_SIZE_LIMIT.to_i

            if secure_file.save
              present secure_file, with: Entities::Ci::SecureFile
            else
              render_validation_error!(secure_file)
            end
          end

          desc 'Delete an individual Secure File'
          route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
          delete ':id/secure_files/:secure_file_id' do
            secure_file = user_project.secure_files.find(params[:secure_file_id])

            ::Ci::DestroySecureFileService.new(user_project, current_user).execute(secure_file)

            no_content!
          end
        end
      end

      helpers do
        def feature_flag_enabled?
          service_unavailable! unless Feature.enabled?(:ci_secure_files, user_project, default_enabled: :yaml)
        end

        def read_only_feature_flag_enabled?
          service_unavailable! if Feature.enabled?(:ci_secure_files_read_only, user_project, type: :ops, default_enabled: :yaml)
        end
      end
    end
  end
end