From 6dd5d1a7006e5948a4a20f16cc64a4e8e8e53456 Mon Sep 17 00:00:00 2001 From: Sam Figueroa Date: Thu, 17 Aug 2023 17:59:31 +0200 Subject: [PATCH 1/3] Audit CI artifact download - Create a streamed audit event when a user downloads a job's artifcat. - Refs: https://gitlab.com/gitlab-org/gitlab/-/issues/250663 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1581228664 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1581228680 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1581228683 https://gitlab.com/gitlab-org/gitlab/-/jobs/5381000292 https://gitlab.com/gitlab-org/gitlab/-/jobs/5384247349 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1631594158 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1631596913 Changelog: added EE: true --- .../projects/artifacts_controller.rb | 8 +++ .../audit_event_types.md | 6 ++ .../ee/projects/artifacts_controller.rb | 23 ++++++ .../types/job_artifact_downloaded.yml | 9 +++ ee/lib/audit/ci/artifact_download_auditor.rb | 70 +++++++++++++++++++ ee/lib/ee/api/ci/helpers/runner.rb | 11 +++ ee/lib/ee/api/ci/job_artifacts.rb | 11 +++ .../user_downloads_artifacts_spec.rb | 59 ++++++++++++++++ .../ci/artifact_download_auditor_spec.rb | 55 +++++++++++++++ ee/spec/lib/ee/api/helpers_spec.rb | 2 +- ee/spec/requests/api/ci/job_artifacts_spec.rb | 50 +++++++++++++ ee/spec/requests/api/ci/runner_spec.rb | 16 ++++- lib/api/ci/helpers/runner.rb | 4 ++ lib/api/ci/job_artifacts.rb | 6 +- lib/api/ci/runner.rb | 1 + .../projects/artifacts_controller_spec.rb | 1 - spec/lib/api/ci/helpers/runner_spec.rb | 2 +- 17 files changed, 328 insertions(+), 6 deletions(-) create mode 100644 ee/app/controllers/ee/projects/artifacts_controller.rb create mode 100644 ee/config/audit_events/types/job_artifact_downloaded.yml create mode 100644 ee/lib/audit/ci/artifact_download_auditor.rb create mode 100644 ee/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb create mode 100644 ee/spec/lib/audit/ci/artifact_download_auditor_spec.rb create mode 100644 ee/spec/requests/api/ci/job_artifacts_spec.rb diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb index 85bdeb07b00b8c..c675e4bb61c7ab 100644 --- a/app/controllers/projects/artifacts_controller.rb +++ b/app/controllers/projects/artifacts_controller.rb @@ -39,6 +39,8 @@ def download return render_404 unless artifact_file log_artifacts_filesize(artifact_file.model) + audit_download(build, artifact_file.filename) + send_upload(artifact_file, attachment: artifact_file.filename, proxy: params[:proxy]) end @@ -106,6 +108,10 @@ def latest_succeeded private + def audit_download(build, filename) + # overridden in EE + end + def extract_ref_name_and_path return unless params[:ref_name_and_path] @@ -184,3 +190,5 @@ def authorize_read_job_artifacts! return access_denied! unless can?(current_user, :read_job_artifacts, job_artifact) end end + +Projects::ArtifactsController.prepend_mod diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md index ae6d042b89fa9e..f200de07de17a6 100644 --- a/doc/administration/audit_event_streaming/audit_event_types.md +++ b/doc/administration/audit_event_streaming/audit_event_types.md @@ -70,6 +70,12 @@ Audit event types belong to the following product categories. |:-----|:------------|:------------------|:---------|:--------------| | [`member_role_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137087) | Event triggered when a custom role is created.| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.7](https://gitlab.com/gitlab-org/gitlab/-/issues/388934) | +### Build artifacts + +| Name | Description | Saved to database | Streamed | Introduced in | +|:-----|:------------|:------------------|:---------|:--------------| +| [`job_artifact_downloaded`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608) | Triggered when a user download a job artifact from a project| **{dotted-circle}** No | **{check-circle}** Yes | GitLab [16.8](https://gitlab.com/gitlab-org/gitlab/-/issues/250663) | + ### Code review | Name | Description | Saved to database | Streamed | Introduced in | diff --git a/ee/app/controllers/ee/projects/artifacts_controller.rb b/ee/app/controllers/ee/projects/artifacts_controller.rb new file mode 100644 index 00000000000000..b9ed2812655c20 --- /dev/null +++ b/ee/app/controllers/ee/projects/artifacts_controller.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module EE + module Projects + module ArtifactsController + extend ::Gitlab::Utils::Override + + private + + override :audit_download + def audit_download(build, filename) + super + + Audit::Ci::ArtifactDownloadAuditor.new( + current_user: current_user, + build: build, + artifact: job_artifact, + filename: filename + ).execute + end + end + end +end diff --git a/ee/config/audit_events/types/job_artifact_downloaded.yml b/ee/config/audit_events/types/job_artifact_downloaded.yml new file mode 100644 index 00000000000000..e38728ab085fae --- /dev/null +++ b/ee/config/audit_events/types/job_artifact_downloaded.yml @@ -0,0 +1,9 @@ +--- +name: job_artifact_downloaded +description: Triggered when a user download a job artifact from a project +introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/issues/250663 +introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608 +feature_category: build_artifacts +milestone: '16.8' +saved_to_database: false +streamed: true diff --git a/ee/lib/audit/ci/artifact_download_auditor.rb b/ee/lib/audit/ci/artifact_download_auditor.rb new file mode 100644 index 00000000000000..effabe09d9207c --- /dev/null +++ b/ee/lib/audit/ci/artifact_download_auditor.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +module Audit + module Ci + class ArtifactDownloadAuditor + NAME = 'job_artifact_downloaded' + UNKNOWN_FILENAME = 'unknown' + NEVER = 'never' + + attr_reader :current_user, :build + + def initialize(build:, filename:, artifact: nil, current_user: nil) + @current_user = current_user + @build = build + @filename = filename + @artifact = artifact + end + + def execute + return unless job_artifact + + ::Gitlab::Audit::Auditor.audit( + name: NAME, + author: author, + scope: build.project, + target: target, + message: message, + additional_details: { + expire_at: expiry, + filename: filename, + artifact_id: job_artifact.id, + artifact_type: job_artifact.class.name + } + ) + end + + private + + def author + return Gitlab::Audit::UnauthenticatedAuthor.new if current_user.nil? + + current_user + end + + def filename + @filename.presence || UNKNOWN_FILENAME + end + + def message + "Downloaded artifact #{filename} (expiration: #{expiry})" + end + + def job_artifact + @artifact || build.job_artifacts_archive + end + + def expiry + expire_at = job_artifact&.expire_at.presence + + return NEVER unless expire_at + + expire_at.iso8601 + end + + def target + build.pipeline || build + end + end + end +end diff --git a/ee/lib/ee/api/ci/helpers/runner.rb b/ee/lib/ee/api/ci/helpers/runner.rb index bcea232dd497e3..c029a0858a9a04 100644 --- a/ee/lib/ee/api/ci/helpers/runner.rb +++ b/ee/lib/ee/api/ci/helpers/runner.rb @@ -11,6 +11,17 @@ module Runner def track_ci_minutes_usage!(build, runner) ::Ci::Minutes::TrackLiveConsumptionService.new(build).execute end + + override :audit_download + def audit_download(build, filename) + super + + Audit::Ci::ArtifactDownloadAuditor.new( + current_user: current_user, + build: build, + filename: filename + ).execute + end end end end diff --git a/ee/lib/ee/api/ci/job_artifacts.rb b/ee/lib/ee/api/ci/job_artifacts.rb index c4752f2a6bfd5c..a49ad9d50d3ccd 100644 --- a/ee/lib/ee/api/ci/job_artifacts.rb +++ b/ee/lib/ee/api/ci/job_artifacts.rb @@ -8,8 +8,19 @@ module JobArtifacts prepended do helpers do + def audit_download(build, filename) + super + + Audit::Ci::ArtifactDownloadAuditor.new( + current_user: current_user, + build: build, + filename: filename + ).execute + end + def authorize_download_artifacts! super + check_cross_project_pipelines_feature! end diff --git a/ee/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb b/ee/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb new file mode 100644 index 00000000000000..9a98aeddcaaa04 --- /dev/null +++ b/ee/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "User downloads artifacts", feature_category: :build_artifacts do + let_it_be(:project) { create(:project, :repository, :public) } + let_it_be(:pipeline) { create(:ci_empty_pipeline, status: :success, sha: project.commit.id, project: project) } + let_it_be(:job) { create(:ci_build, :artifacts, :success, pipeline: pipeline) } + + shared_examples "downloading" do + it "audits the download" do + expect(::Gitlab::Audit::Auditor).to receive(:audit).with(hash_including(name: 'job_artifact_downloaded')) + + visit(url) + end + end + + context "when downloading" do + before do + stub_licensed_features( + admin_audit_log: true, + audit_events: true, + extended_audit_events: true, + external_audit_events: true) + end + + context "with job id" do + let(:url) { download_project_job_artifacts_path(project, job) } + + it_behaves_like "downloading" + end + + context "with branch name and job name" do + let(:url) { latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name) } + + it_behaves_like "downloading" + end + + context "with SHA" do + let(:url) { latest_succeeded_project_artifacts_path(project, "#{pipeline.sha}/download", job: job.name) } + + it_behaves_like "downloading" + end + + context "when unauthorized" do + let(:url) { download_project_job_artifacts_path(project, job) } + + before do + job.job_artifacts.update_all(accessibility: 'private') + end + + it 'does not audit when no-one can download' do + expect(::Gitlab::Audit::Auditor).not_to receive(:audit) + + visit(url) + end + end + end +end diff --git a/ee/spec/lib/audit/ci/artifact_download_auditor_spec.rb b/ee/spec/lib/audit/ci/artifact_download_auditor_spec.rb new file mode 100644 index 00000000000000..b18342597937ee --- /dev/null +++ b/ee/spec/lib/audit/ci/artifact_download_auditor_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Audit::Ci::ArtifactDownloadAuditor, feature_category: :compliance_management do + let_it_be(:build) { create :ci_build, :artifacts } + + describe '#execute' do + context 'with filename' do + it 'includes given filename in additional_details' do + filename = 'ci_build_artifacts.zip' + + expect(Gitlab::Audit::Auditor).to receive(:audit) + .with(hash_including(additional_details: hash_including({ filename: filename }))) + + described_class.new(build: build, filename: build.job_artifacts_archive.filename).execute + end + end + + context 'without filename' do + it 'defaults to UNKNOWN_FILENAME in additional_details' do + expect(Gitlab::Audit::Auditor).to receive(:audit) + .with(hash_including(additional_details: hash_including({ filename: described_class::UNKNOWN_FILENAME }))) + + described_class.new(build: build, filename: nil).execute + end + end + + context 'without expiry' do + it 'includes message with unlimited expiration' do + expect(Gitlab::Audit::Auditor).to receive(:audit) + .with(hash_including(name: described_class::NAME, + message: 'Downloaded artifact ci_build_artifacts.zip (expiration: never)', + additional_details: hash_including(expire_at: 'never') + )).and_call_original + + described_class.new(build: build, filename: build.job_artifacts_archive.filename).execute + end + end + + context 'with expiry', time_travel_to: Time.zone.parse("2022-02-22 00:00:00 UTC+0") do + let(:artifact) { create :ci_job_artifact, :archive, expire_at: Time.zone.now } + let(:build) { artifact.job } + + it 'includes message with unlimited expiration' do + artifact + never_expire_msg = 'Downloaded artifact ci_build_artifacts.zip (expiration: 2022-02-22T00:00:00Z)' + + expect(Gitlab::Audit::Auditor).to receive(:audit).with(hash_including(message: never_expire_msg)) + + described_class.new(build: build, filename: build.job_artifacts_archive.filename).execute + end + end + end +end diff --git a/ee/spec/lib/ee/api/helpers_spec.rb b/ee/spec/lib/ee/api/helpers_spec.rb index f553fe824cd853..1fa7883662ad84 100644 --- a/ee/spec/lib/ee/api/helpers_spec.rb +++ b/ee/spec/lib/ee/api/helpers_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe EE::API::Helpers do +RSpec.describe EE::API::Helpers, feature_category: :shared do include Rack::Test::Methods let(:helper) do diff --git a/ee/spec/requests/api/ci/job_artifacts_spec.rb b/ee/spec/requests/api/ci/job_artifacts_spec.rb new file mode 100644 index 00000000000000..c7ac9a0b84f3c7 --- /dev/null +++ b/ee/spec/requests/api/ci/job_artifacts_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::Ci::JobArtifacts, feature_category: :build_artifacts do + include HttpBasicAuthHelpers + include DependencyProxyHelpers + include Ci::JobTokenScopeHelpers + include HttpIOHelpers + + let_it_be(:project, reload: true) do + create(:project, :repository, :in_group, public_builds: false) + end + + let_it_be(:pipeline, reload: true) do + create(:ci_pipeline, project: project, sha: project.commit.id, ref: project.default_branch) + end + + let(:user) { create(:user) } + let(:api_user) { user } + let(:guest) { create(:project_member, :guest, project: project).user } + let!(:job) { create(:ci_build, :artifacts, pipeline: pipeline, project: project) } + + before do + project.add_developer(user) + end + + describe 'GET /projects/:id/jobs/:job_id/artifacts' do + context 'with job artifacts' do + context 'with audit events enabled', :aggregate_failures do + before do + project.group.root_ancestor.external_audit_event_destinations.create!(destination_url: 'http://example.com') + stub_licensed_features(admin_audit_log: true, extended_audit_events: true, external_audit_events: true) + end + + let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, project: project) } + + subject(:request_artifact) { get api("/projects/#{project.id}/jobs/#{job.id}/artifacts", api_user) } + + it 'audits downloads' do + expect(::Gitlab::Audit::Auditor).to( + receive(:audit).with(hash_including(name: 'job_artifact_downloaded')).and_call_original + ) + + request_artifact + end + end + end + end +end diff --git a/ee/spec/requests/api/ci/runner_spec.rb b/ee/spec/requests/api/ci/runner_spec.rb index 1e1e403e3440f4..48153d7e8c7b2f 100644 --- a/ee/spec/requests/api/ci/runner_spec.rb +++ b/ee/spec/requests/api/ci/runner_spec.rb @@ -5,7 +5,7 @@ RSpec.describe API::Ci::Runner, feature_category: :runner do include Ci::JobTokenScopeHelpers - let_it_be_with_reload(:project) { create(:project, :repository) } + let_it_be_with_reload(:project) { create(:project, :repository, :in_group) } let_it_be(:user) { create(:user) } let_it_be(:ref) { 'master' } @@ -136,7 +136,21 @@ def request_job(token = runner.token, **params) end shared_examples 'successful artifact download' do + before do + project.group.root_ancestor.external_audit_event_destinations.create!(destination_url: 'http://example.com') + stub_licensed_features(admin_audit_log: true, extended_audit_events: true, external_audit_events: true) + end + it 'downloads artifacts' do + expect(::Gitlab::Audit::Auditor).to( + receive(:audit).with(hash_including(name: 'job_artifact_downloaded')).and_call_original + ) + expect(AuditEvents::AuditEventStreamingWorker).to( + receive(:perform_async) + .with('job_artifact_downloaded', nil, a_string_including("Downloaded artifact")) + .and_call_original + ) + download_artifact expect(response).to have_gitlab_http_status(:ok) diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb index 382528c814c411..02a0e6bd722160 100644 --- a/lib/api/ci/helpers/runner.rb +++ b/lib/api/ci/helpers/runner.rb @@ -140,6 +140,10 @@ def track_ci_minutes_usage!(_build, _runner) # noop: overridden in EE end + def audit_download(build, filename) + # noop: overridden in EE + end + def check_if_backoff_required! return unless Gitlab::Database::Migrations::RunnerBackoff::Communicator.backoff_runner? diff --git a/lib/api/ci/job_artifacts.rb b/lib/api/ci/job_artifacts.rb index 3788f5bec410df..20220aae7b794b 100644 --- a/lib/api/ci/job_artifacts.rb +++ b/lib/api/ci/job_artifacts.rb @@ -14,6 +14,8 @@ class JobArtifacts < ::API::Base def authorize_download_artifacts! authorize_read_builds! end + + def audit_download(build, filename); end end params do @@ -44,7 +46,7 @@ def authorize_download_artifacts! latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name]) authorize_read_job_artifacts!(latest_build) - + audit_download(latest_build, latest_build.artifacts_file.filename) present_artifacts_file!(latest_build.artifacts_file) end @@ -104,7 +106,7 @@ def authorize_download_artifacts! build = find_build!(params[:job_id]) authorize_read_job_artifacts!(build) - + audit_download(build, build&.artifacts_file&.filename) if build&.artifacts_file present_artifacts_file!(build.artifacts_file) end diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index 585e9f962a3ff9..351a97596451cd 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -386,6 +386,7 @@ class Runner < ::API::Base get '/:id/artifacts', feature_category: :build_artifacts do authenticate_job_via_dependent_job! + audit_download(current_job, current_job&.artifacts_file&.filename) if current_job.artifacts_file present_artifacts_file!(current_job.artifacts_file, supports_direct_download: params[:direct_download]) end end diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index a0548e847a0f7d..2c893b63cfc907 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -103,7 +103,6 @@ def download_artifact(extra_params = {}) hash_including(disposition: 'attachment', filename: filename)).and_call_original download_artifact - expect(response.headers['Content-Disposition']).to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) end end diff --git a/spec/lib/api/ci/helpers/runner_spec.rb b/spec/lib/api/ci/helpers/runner_spec.rb index ee0a58a4e53082..2e4551f5eb901d 100644 --- a/spec/lib/api/ci/helpers/runner_spec.rb +++ b/spec/lib/api/ci/helpers/runner_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe API::Ci::Helpers::Runner do +RSpec.describe API::Ci::Helpers::Runner, feature_category: :runner do let(:helper) do Class.new do include API::Ci::Helpers::Runner -- GitLab From 38c72c0cde912ff6cbc0adc56408e96a222b19b6 Mon Sep 17 00:00:00 2001 From: Sam Figueroa Date: Thu, 11 Jan 2024 13:03:09 +0100 Subject: [PATCH 2/3] Address review suggestions - Refs: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1720915904 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1720915909 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1720915925 --- .../audit_event_streaming/audit_event_types.md | 1 + lib/api/ci/job_artifacts.rb | 2 +- lib/api/ci/runner.rb | 2 +- .../projects/artifacts_controller_spec.rb | 16 +++++++++++----- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md index f200de07de17a6..3b5c51e657576a 100644 --- a/doc/administration/audit_event_streaming/audit_event_types.md +++ b/doc/administration/audit_event_streaming/audit_event_types.md @@ -44,6 +44,7 @@ Audit event types belong to the following product categories. | [`audit_events_streaming_instance_headers_create`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125870) | Triggered when a streaming header for instance level external audit event destination is created| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/417433) | | [`audit_events_streaming_instance_headers_destroy`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127228) | Triggered when a streaming header for instance level external audit event destination is deleted| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/417433) | | [`audit_events_streaming_instance_headers_update`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127228) | Triggered when a streaming header for instance level external audit event destination is updated| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/417433) | +| [`ci_runner_registered`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123516) | Triggered when a CI runner has been registered| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.8](https://gitlab.com/gitlab-org/gitlab/-/issues/374110) | | [`create_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74632) | Event triggered when an external audit event destination is created| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/344664) | | [`create_http_namespace_filter`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136047) | Event triggered when a namespace filter for an external audit event destination for a top-level group is created.| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.6](https://gitlab.com/gitlab-org/gitlab/-/issues/424176) | | [`create_instance_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123882) | Event triggered when an instance level external audit event destination is created| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.2](https://gitlab.com/gitlab-org/gitlab/-/issues/404730) | diff --git a/lib/api/ci/job_artifacts.rb b/lib/api/ci/job_artifacts.rb index 20220aae7b794b..cdc318894080e1 100644 --- a/lib/api/ci/job_artifacts.rb +++ b/lib/api/ci/job_artifacts.rb @@ -106,7 +106,7 @@ def audit_download(build, filename); end build = find_build!(params[:job_id]) authorize_read_job_artifacts!(build) - audit_download(build, build&.artifacts_file&.filename) if build&.artifacts_file + audit_download(build, build.artifacts_file&.filename) if build.artifacts_file present_artifacts_file!(build.artifacts_file) end diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index 351a97596451cd..1ea62e03fbab69 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -386,7 +386,7 @@ class Runner < ::API::Base get '/:id/artifacts', feature_category: :build_artifacts do authenticate_job_via_dependent_job! - audit_download(current_job, current_job&.artifacts_file&.filename) if current_job.artifacts_file + audit_download(current_job, current_job.artifacts_file&.filename) if current_job.artifacts_file present_artifacts_file!(current_job.artifacts_file, supports_direct_download: params[:direct_download]) end end diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb index 2c893b63cfc907..78cd32de5603b4 100644 --- a/spec/controllers/projects/artifacts_controller_spec.rb +++ b/spec/controllers/projects/artifacts_controller_spec.rb @@ -103,7 +103,9 @@ def download_artifact(extra_params = {}) hash_including(disposition: 'attachment', filename: filename)).and_call_original download_artifact - expect(response.headers['Content-Disposition']).to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) + + expect(response.headers['Content-Disposition']) + .to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) end end @@ -134,7 +136,8 @@ def download_artifact(extra_params = {}) download_artifact(file_type: 'archive') expect(response).to have_gitlab_http_status(:ok) - expect(response.headers['Content-Disposition']).to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) + expect(response.headers['Content-Disposition']) + .to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) end end end @@ -167,7 +170,8 @@ def download_artifact(extra_params = {}) download_artifact(file_type: file_type) - expect(response.headers['Content-Disposition']).to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) + expect(response.headers['Content-Disposition']) + .to eq(%(attachment; filename="#{filename}"; filename*=UTF-8''#{filename})) end end @@ -181,7 +185,8 @@ def download_artifact(extra_params = {}) end it 'sends the codequality report' do - expect(Gitlab::ApplicationContext).to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original + expect(Gitlab::ApplicationContext) + .to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original expect(controller).to receive(:redirect_to).and_call_original @@ -211,7 +216,8 @@ def download_artifact(extra_params = {}) end it 'redirects to a Google CDN request' do - expect(Gitlab::ApplicationContext).to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original + expect(Gitlab::ApplicationContext) + .to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: true).and_call_original download_artifact(file_type: file_type) -- GitLab From 74bdd5e20a452db1abb025eda2d4ec913685be3b Mon Sep 17 00:00:00 2001 From: Sam Figueroa Date: Thu, 11 Jan 2024 15:45:00 +0100 Subject: [PATCH 3/3] Fix audit_event documentation - Refs: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129608#note_1723363615 --- doc/administration/audit_event_streaming/audit_event_types.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md index 3b5c51e657576a..f200de07de17a6 100644 --- a/doc/administration/audit_event_streaming/audit_event_types.md +++ b/doc/administration/audit_event_streaming/audit_event_types.md @@ -44,7 +44,6 @@ Audit event types belong to the following product categories. | [`audit_events_streaming_instance_headers_create`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125870) | Triggered when a streaming header for instance level external audit event destination is created| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/417433) | | [`audit_events_streaming_instance_headers_destroy`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127228) | Triggered when a streaming header for instance level external audit event destination is deleted| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/417433) | | [`audit_events_streaming_instance_headers_update`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/127228) | Triggered when a streaming header for instance level external audit event destination is updated| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/417433) | -| [`ci_runner_registered`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123516) | Triggered when a CI runner has been registered| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.8](https://gitlab.com/gitlab-org/gitlab/-/issues/374110) | | [`create_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74632) | Event triggered when an external audit event destination is created| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [14.6](https://gitlab.com/gitlab-org/gitlab/-/issues/344664) | | [`create_http_namespace_filter`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136047) | Event triggered when a namespace filter for an external audit event destination for a top-level group is created.| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.6](https://gitlab.com/gitlab-org/gitlab/-/issues/424176) | | [`create_instance_event_streaming_destination`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123882) | Event triggered when an instance level external audit event destination is created| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.2](https://gitlab.com/gitlab-org/gitlab/-/issues/404730) | -- GitLab