diff options
-rw-r--r-- | Gemfile | 8 | ||||
-rw-r--r-- | Gemfile.checksum | 26 | ||||
-rw-r--r-- | Gemfile.lock | 21 | ||||
-rw-r--r-- | app/controllers/passwords_controller.rb | 4 | ||||
-rw-r--r-- | app/policies/ci/pipeline_policy.rb | 8 | ||||
-rw-r--r-- | doc/administration/audit_event_streaming/audit_event_types.md | 1 | ||||
-rw-r--r-- | doc/administration/gitaly/reference.md | 36 | ||||
-rw-r--r-- | doc/install/requirements.md | 12 | ||||
-rw-r--r-- | doc/update/versions/gitlab_16_changes.md | 6 | ||||
-rw-r--r-- | lib/api/entities/feature.rb | 6 | ||||
-rw-r--r-- | lib/api/helpers.rb | 24 | ||||
-rw-r--r-- | locale/gitlab.pot | 12 | ||||
-rw-r--r-- | spec/lib/api/helpers_spec.rb | 159 | ||||
-rw-r--r-- | spec/policies/ci/pipeline_policy_spec.rb | 25 |
14 files changed, 302 insertions, 46 deletions
@@ -536,14 +536,14 @@ gem 'kas-grpc', '~> 0.2.0' gem 'grpc', '~> 1.55.0' -gem 'google-protobuf', '~> 3.24', '>= 3.24.2' +gem 'google-protobuf', '~> 3.24', '>= 3.24.3' gem 'toml-rb', '~> 2.2.0' # Feature toggles -gem 'flipper', '~> 0.25.0' -gem 'flipper-active_record', '~> 0.25.0' -gem 'flipper-active_support_cache_store', '~> 0.25.0' +gem 'flipper', '~> 0.26.2' +gem 'flipper-active_record', '~> 0.26.2' +gem 'flipper-active_support_cache_store', '~> 0.26.2' gem 'unleash', '~> 3.2.2' gem 'gitlab-experiment', '~> 0.7.1' diff --git a/Gemfile.checksum b/Gemfile.checksum index 920b5cb24b6..583a2a26ec6 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -184,9 +184,9 @@ {"name":"ffi-yajl","version":"2.6.0","platform":"universal-java","checksum":"1159a093c51d75d67578e31d2ed429f2481ef7e73021c5d667ebf6ab481a0d21"}, {"name":"filelock","version":"1.1.1","platform":"ruby","checksum":"5207258374370a75d5927b2eaf9b831732d224e48ce56c318e8308c7cdcabb20"}, {"name":"find_a_port","version":"1.0.1","platform":"ruby","checksum":"605d6a84b5e6f138da2b06c87c5a4a0231e4fdc9b9a92022d9caa361f77d5ceb"}, -{"name":"flipper","version":"0.25.0","platform":"ruby","checksum":"ccb2776752b8378bc994c9d873ccde290c090341940761b873494695ee697add"}, -{"name":"flipper-active_record","version":"0.25.0","platform":"ruby","checksum":"85a5c99465e2cc6a09e91931a9998b0dbd463cd6c80dd513129377132e3eb67f"}, -{"name":"flipper-active_support_cache_store","version":"0.25.0","platform":"ruby","checksum":"7282bf994b08d1a076b65c6f3b51e3dc04fcb00fa6e7b20089e60db25c7b531b"}, +{"name":"flipper","version":"0.26.2","platform":"ruby","checksum":"6d577208d971b2d53b7c090ef19765685c31bb43c3cc345d4ee11c1052f6f988"}, +{"name":"flipper-active_record","version":"0.26.2","platform":"ruby","checksum":"61deaeef8ce2f775e67d7095f40fd95fc2d07241e143dd4436e78c7b26a320bc"}, +{"name":"flipper-active_support_cache_store","version":"0.26.2","platform":"ruby","checksum":"c2d3883ad1e5c7de827c37df455ffe6e175bc0be93f2a260c54efdabb313d2b0"}, {"name":"fog-aliyun","version":"0.4.0","platform":"ruby","checksum":"8f2334604beb781eafbb9cd5f50141fbb2c7eb77c7f2b01f45c2e04db0e5cc38"}, {"name":"fog-aws","version":"3.18.0","platform":"ruby","checksum":"f4c5880ecfbc4edbf711dfd41140f9f17dfc68b519546d121448d2d3a5584704"}, {"name":"fog-core","version":"2.1.0","platform":"ruby","checksum":"53e5d793554d7080d015ef13cd44b54027e421d924d9dba4ce3d83f95f37eda9"}, @@ -242,16 +242,16 @@ {"name":"google-cloud-errors","version":"1.3.0","platform":"ruby","checksum":"450b681e24c089a20721a01acc4408bb4a7b0df28c175aaab488da917480d64b"}, {"name":"google-cloud-profiler-v2","version":"0.4.0","platform":"ruby","checksum":"53fc2ab175d08f54233c644310d47798feac996220916815c4fb44c937b5d3e3"}, {"name":"google-cloud-storage","version":"1.44.0","platform":"ruby","checksum":"299a1e055c9277c8120f7c10d21d37e4d8c17c7b963350c0e0bff7e9d9a570ea"}, -{"name":"google-protobuf","version":"3.24.2","platform":"aarch64-linux","checksum":"acd4be32962a648bc76cd44131bb8fd0ed18116e3774a8eb55d4cb8d3b7c3ce2"}, -{"name":"google-protobuf","version":"3.24.2","platform":"arm64-darwin","checksum":"743d50a21e3f1dc3152d38733948b2b680afb5b6095b0853e091deeb899fcf5a"}, -{"name":"google-protobuf","version":"3.24.2","platform":"java","checksum":"a2981147d7ef8a4fb751f6f53872159800f7e2db296ba1495f18905820785c3a"}, -{"name":"google-protobuf","version":"3.24.2","platform":"ruby","checksum":"0e5cbb7ff14d2fceedb69a7f5912f521fe6f0c7337e04a80b516a19fb70ec338"}, -{"name":"google-protobuf","version":"3.24.2","platform":"x64-mingw-ucrt","checksum":"88a5cae186ebd211243365e60d302f14b59394afd2913aa8e3b329b19b928477"}, -{"name":"google-protobuf","version":"3.24.2","platform":"x64-mingw32","checksum":"80787c24e244a0186efafbf3e17f5d6d02de7c3ebd63dc0129bc7d42aacf0022"}, -{"name":"google-protobuf","version":"3.24.2","platform":"x86-linux","checksum":"4e853ac257336e1cbbdef0bd3d8590e9f2e744e6dbdef4e3105d012f56a279b0"}, -{"name":"google-protobuf","version":"3.24.2","platform":"x86-mingw32","checksum":"7143a8ffcb831624c5d368bde73d2449737c89c9947d289495f887b4ce62a122"}, -{"name":"google-protobuf","version":"3.24.2","platform":"x86_64-darwin","checksum":"3dae4616b312e733cd32d4d63cd4bd96d5d1aed6d4e69917f073c45bfe037c96"}, -{"name":"google-protobuf","version":"3.24.2","platform":"x86_64-linux","checksum":"915d37758f7aaea497db7087d7cf92709529370a37fc4b77d14ddaa3f900c21d"}, +{"name":"google-protobuf","version":"3.24.3","platform":"aarch64-linux","checksum":"02591f0bb6a7b34da7f4451b3e9b684787eae6fab5c9283ff09be993830683cd"}, +{"name":"google-protobuf","version":"3.24.3","platform":"arm64-darwin","checksum":"34919ce25e3260954a509a7fb4ff4767e438c1d09cffe0998fa97aa7f547c50c"}, +{"name":"google-protobuf","version":"3.24.3","platform":"java","checksum":"f1582bd2665df61a363501b2a51bea61e2c8466bd1f8823a22b53cbea5aa7401"}, +{"name":"google-protobuf","version":"3.24.3","platform":"ruby","checksum":"63f3cceb398b5f3258760da95037d26ef65405aa3425fd7ba1560fce4827945d"}, +{"name":"google-protobuf","version":"3.24.3","platform":"x64-mingw-ucrt","checksum":"381f16aeda20d23465b9d9efffaa660367cda951299df0d5fd5662e9a119a36c"}, +{"name":"google-protobuf","version":"3.24.3","platform":"x64-mingw32","checksum":"5a687545a4a9deb93375107600aee43edfc495979ec8b88fff39d8c139e49330"}, +{"name":"google-protobuf","version":"3.24.3","platform":"x86-linux","checksum":"d7f556d618b83629a49f831a9358122a22c3a3ebd65f59c10f690c4ec95ad321"}, +{"name":"google-protobuf","version":"3.24.3","platform":"x86-mingw32","checksum":"05711b1c8cdf77fdbe8eabbe477b2b792758b6e2c5a72add222ac6f4c5626119"}, +{"name":"google-protobuf","version":"3.24.3","platform":"x86_64-darwin","checksum":"10d9645ebe89758fd81fcbcd678aaaa30c34ca2b2a2182e8dfc90e29df9cafb4"}, +{"name":"google-protobuf","version":"3.24.3","platform":"x86_64-linux","checksum":"e081a8345680b7883b48823a4123acdf45ebd169e3d5a3c2e0cb9ac47fc896eb"}, {"name":"googleapis-common-protos","version":"1.4.0","platform":"ruby","checksum":"da2380fb5ab1563580816c74e8d684ac17512c3654c829a3ee84f6d6139de382"}, {"name":"googleapis-common-protos-types","version":"1.5.0","platform":"ruby","checksum":"5769cf7376abc86ef7f5897a4aaca1d5c5a3c49ddabeddd2c251fcf8155f858b"}, {"name":"googleauth","version":"1.3.0","platform":"ruby","checksum":"51dd7362353cf1e90a2d01e1fb94321ae3926c776d4dc4a79db65230217ffcc2"}, diff --git a/Gemfile.lock b/Gemfile.lock index c3115e0b0cc..795baf146d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -561,13 +561,14 @@ GEM libyajl2 (>= 1.2) filelock (1.1.1) find_a_port (1.0.1) - flipper (0.25.0) - flipper-active_record (0.25.0) + flipper (0.26.2) + concurrent-ruby (< 2) + flipper-active_record (0.26.2) activerecord (>= 4.2, < 8) - flipper (~> 0.25.0) - flipper-active_support_cache_store (0.25.0) + flipper (~> 0.26.2) + flipper-active_support_cache_store (0.26.2) activesupport (>= 4.2, < 8) - flipper (~> 0.25.0) + flipper (~> 0.26.2) fog-aliyun (0.4.0) addressable (~> 2.8.0) aliyun-sdk (~> 0.8.0) @@ -753,7 +754,7 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - google-protobuf (3.24.2) + google-protobuf (3.24.3) googleapis-common-protos (1.4.0) google-protobuf (~> 3.14) googleapis-common-protos-types (~> 1.2) @@ -1803,9 +1804,9 @@ DEPENDENCIES faraday_middleware-aws-sigv4 (~> 0.3.0) fast_blank (~> 1.0.1) ffaker (~> 2.10) - flipper (~> 0.25.0) - flipper-active_record (~> 0.25.0) - flipper-active_support_cache_store (~> 0.25.0) + flipper (~> 0.26.2) + flipper-active_record (~> 0.26.2) + flipper-active_support_cache_store (~> 0.26.2) fog-aliyun (~> 0.4) fog-aws (~> 3.18) fog-core (= 2.1.0) @@ -1847,7 +1848,7 @@ DEPENDENCIES google-apis-serviceusage_v1 (~> 0.28.0) google-apis-sqladmin_v1beta4 (~> 0.41.0) google-cloud-storage (~> 1.44.0) - google-protobuf (~> 3.24, >= 3.24.2) + google-protobuf (~> 3.24, >= 3.24.3) gpgme (~> 2.0.22) grape (~> 1.7.1) grape-entity (~> 0.10.0) diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index 38839497fb6..d1ca16bd8fb 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -43,6 +43,7 @@ class PasswordsController < Devise::PasswordsController resource.password_expires_at = nil resource.save(validate: false) if resource.changed? else + log_audit_reset_failure(@user) track_weak_password_error(@user, self.class.name, 'create') end end @@ -50,6 +51,9 @@ class PasswordsController < Devise::PasswordsController protected + # overriden in EE + def log_audit_reset_failure(_user); end + def resource_from_email email = resource_params[:email] self.resource = resource_class.find_by_email(email) diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index 4d21da0226b..1d60b1e79de 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -18,6 +18,10 @@ module Ci @subject.triggered_by?(@user) end + condition(:project_allows_read_dependency) do + can?(:read_dependency, @subject.project) + end + # Disallow users without permissions from accessing internal pipelines rule { ~can?(:read_build) & ~external_pipeline }.policy do prevent :read_pipeline @@ -41,6 +45,10 @@ module Ci enable :read_pipeline_variable end + rule { project_allows_read_dependency }.policy do + enable :read_dependency + end + def ref_protected?(user, project, tag, ref) access = ::Gitlab::UserAccess.new(user, container: project) diff --git a/doc/administration/audit_event_streaming/audit_event_types.md b/doc/administration/audit_event_streaming/audit_event_types.md index 2a7c3367f6a..331e991aeb3 100644 --- a/doc/administration/audit_event_streaming/audit_event_types.md +++ b/doc/administration/audit_event_streaming/audit_event_types.md @@ -170,6 +170,7 @@ Every audit event is associated with an event type. The association with the eve | [`merged_merge_request_deleted`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118793) | Audit event triggered when a merged merge request is deleted | **{dotted-circle}** No | **{check-circle}** Yes | `source_code_management` | GitLab [16.0](https://gitlab.com/gitlab-org/gitlab/-/issues/408288) | | [`merged_merge_request_deletion_started`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118793) | Audit event triggered when a merged merge request's deletion is started | **{dotted-circle}** No | **{check-circle}** Yes | `source_code_management` | GitLab [16.1](https://gitlab.com/gitlab-org/gitlab/-/issues/408288) | | [`omniauth_login_failed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123080) | Event triggered when an OmniAuth login fails | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [16.3](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) | +| [`password_reset_failed`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129079) | Event triggered when a password reset fails for a user | **{dotted-circle}** No | **{check-circle}** Yes | `user_management` | GitLab [16.4](https://gitlab.com/gitlab-org/gitlab/-/issues/377762) | | [`password_reset_requested`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114548) | Event triggered when a user requests a password reset using a registered email address | **{check-circle}** Yes | **{dotted-circle}** No | `compliance_management` | GitLab [15.11](https://gitlab.com/gitlab-org/gitlab/-/issues/374107) | | [`personal_access_token_created`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108952) | Event triggered when a user creates a personal access token | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374113) | | [`personal_access_token_revoked`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/108952) | Event triggered when a personal access token is revoked | **{check-circle}** Yes | **{check-circle}** Yes | `compliance_management` | GitLab [15.9](https://gitlab.com/gitlab-org/gitlab/-/issues/374113) | diff --git a/doc/administration/gitaly/reference.md b/doc/administration/gitaly/reference.md index aa04c9a92c4..5b26c93cea8 100644 --- a/doc/administration/gitaly/reference.md +++ b/doc/administration/gitaly/reference.md @@ -155,25 +155,43 @@ Prometheus query to see the hit rate: sum(rate(gitaly_catfile_cache_total{type="hit"}[5m])) / sum(rate(gitaly_catfile_cache_total{type=~"(hit)|(miss)"}[5m])) ``` -### GitLab Shell +#### Custom Hooks -For historical reasons -[GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell) contains -the Git hooks that allow GitLab to validate and react to Git pushes. -Because Gitaly "owns" Git pushes, GitLab Shell must therefore be -installed alongside Gitaly. +> Method of configuring custom hooks directory documented here is preferred from GitLab 16.4. `[gitlab-shell] dir` configuration is no longer required. + +Gitaly supports [custom Git hooks](../server_hooks.md) that are +used to perform tasks based on changes performed in any repository. The custom +hooks directory is configured in the `[hooks]` section: | Name | Type | Required | Description | | ---- | ---- | -------- | ----------- | -| `dir` | string | yes | The directory where GitLab Shell is installed.| +| `custom_hooks_dir` | string | no | The directory where custom Git hooks are installed. | Example: ```toml -[gitlab-shell] -dir = "/home/git/gitlab-shell" +[hooks] +custom_hooks_dir = "/home/git/custom-hooks" ``` +If left unset, no custom hooks are used. + +### GitLab + +> Method of configuring custom hooks directory documented here is preferred from GitLab 16.4. `[gitlab-shell] dir` configuration is no longer required. + +Gitaly must connect to the GitLab application to perform access +checks when a user performs a change. The parameters to connect to GitLab must +be configured in the `[gitlab]` section. + +| Name | Type | Required | Description | +| ---- | ---- | -------- | ----------- | +| `url` | string | yes | The URL of the GitLab server. +| `secret` | string | no | The secret token used to authenticate with GitLab. | +| `secret_file` | string | no | The path of the file containing the secret token used to authenticate with GitLab. | + +Only one of `secret` or `secret_file` can be configured. + ### Prometheus You can optionally configure Gitaly to record histogram latencies on GRPC method diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 5289cba10c1..81244594a59 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -50,11 +50,13 @@ The following is the recommended minimum Memory hardware guidance for a handful - 8 GB RAM supports up to 1000 users - More users? Consult the [reference architectures page](../administration/reference_architectures/index.md) -In addition to the above, we generally recommend having at least 2 GB of swap on your server, -even if you currently have enough available RAM. Having swap helps to reduce the chance of errors occurring -if your available memory changes. We also recommend configuring the kernel's swappiness setting -to a low value like `10` to make the most of your RAM while still having the swap -available when needed. +For smaller installations, you should: + +- Have at least 2 GB of swap on your server, even if you have enough available RAM. Having swap helps to reduce the chance of + errors occurring if your available memory changes. +- Configure the kernel's swappiness setting to a low value like `10` to make the most of your RAM while still having the swap available when needed. + +For larger installations that follow our reference architectures, you [shouldn't configure swap](../administration/reference_architectures/index.md#no-swap). NOTE: Although excessive swapping is undesired and degrades performance, it is an diff --git a/doc/update/versions/gitlab_16_changes.md b/doc/update/versions/gitlab_16_changes.md index 4415602364a..1d03f431629 100644 --- a/doc/update/versions/gitlab_16_changes.md +++ b/doc/update/versions/gitlab_16_changes.md @@ -30,6 +30,12 @@ For more information about upgrading GitLab Helm Chart, see [the release notes f If you upgrade to 16.4 from a version lower than 16.3, you must execute `ANALYZE packages_packages;` in the database before you use it. +- A new method of configuring paths for the GitLab secret and custom hooks is preferred in GitLab 16.4 and later: + 1. Update your configuration `[gitlab] secret_file` to [configure the path](../../administration/gitaly/reference.md#gitlab) to the GitLab secret token. + 1. If you have custom hooks, update your configuration `[hooks] custom_hooks_dir` to [configure the path](../../administration/gitaly/reference.md#custom-hooks) to + server-side custom hooks. + 1. Remove the `[gitlab-shell] dir` configuration. + ## 16.3.0 - For Go applications, [`crypto/tls`: verifying certificate chains containing large RSA keys is slow (CVE-2023-29409)](https://github.com/golang/go/issues/61460) diff --git a/lib/api/entities/feature.rb b/lib/api/entities/feature.rb index 48dd5a22a7e..f341472e8c2 100644 --- a/lib/api/entities/feature.rb +++ b/lib/api/entities/feature.rb @@ -7,8 +7,10 @@ module API expose :state, documentation: { type: 'string', example: 'off' } expose :gates, using: Entities::FeatureGate do |model| model.gates.map do |gate| - value = model.gate_values[gate.key] - + # in Flipper 0.26.1, they removed two GateValues#[] method calls for performance reasons + # https://github.com/flippercloud/flipper/pull/706/commits/ed914b6adc329455a634be843c38db479299efc7 + # https://github.com/flippercloud/flipper/commit/eee20f3ae278d168c8bf70a7a5fcc03bedf432b5 + value = model.gate_values.send(gate.key) # rubocop:disable GitlabSecurity/PublicSend # By default all gate values are populated. Only show relevant ones. if (value.is_a?(Integer) && value == 0) || (value.is_a?(Set) && value.empty?) next diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index edfb1880dc3..4dcca4bdbf9 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -184,6 +184,30 @@ module API end # rubocop: disable CodeReuse/ActiveRecord + def find_pipeline(id) + return unless id + + if id.to_s =~ INTEGER_ID_REGEX + ::Ci::Pipeline.find_by(id: id) + end + end + # rubocop: enable CodeReuse/ActiveRecord + + def find_pipeline!(id) + pipeline = find_pipeline(id) + check_pipeline_access(pipeline) + end + + def check_pipeline_access(pipeline) + return forbidden! unless authorized_project_scope?(pipeline&.project) + + return pipeline if can?(current_user, :read_pipeline, pipeline) + return unauthorized! if authenticate_non_public? + + not_found!('Pipeline') + end + + # rubocop: disable CodeReuse/ActiveRecord def find_group(id) if id.to_s =~ INTEGER_ID_REGEX Group.find_by(id: id) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 03f8fd19bde..e0118dd78d9 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -41222,9 +41222,6 @@ msgstr "" msgid "ScanResultPolicy|Attributes are automatically applied by the scanners" msgstr "" -msgid "ScanResultPolicy|Block users from modifying protected branches" -msgstr "" - msgid "ScanResultPolicy|Choose criteria type" msgstr "" @@ -41246,6 +41243,9 @@ msgstr "" msgid "ScanResultPolicy|Fix available is only applicable to container and dependency scanning" msgstr "" +msgid "ScanResultPolicy|If selected, the following choices will overwrite %{linkStart}project settings%{linkEnd} but only affect the branches selected in the policy." +msgstr "" + msgid "ScanResultPolicy|Is" msgstr "" @@ -41288,6 +41288,12 @@ msgstr "" msgid "ScanResultPolicy|Pre-existing" msgstr "" +msgid "ScanResultPolicy|Prevent branch protection modification" +msgstr "" + +msgid "ScanResultPolicy|Protected branch settings" +msgstr "" + msgid "ScanResultPolicy|Select a scan type before adding criteria" msgstr "" diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb index 5e28490b2c8..2017288b19d 100644 --- a/spec/lib/api/helpers_spec.rb +++ b/spec/lib/api/helpers_spec.rb @@ -247,6 +247,165 @@ RSpec.describe API::Helpers, feature_category: :shared do end end + describe '#find_pipeline' do + let(:pipeline) { create(:ci_pipeline) } + + shared_examples 'pipeline finder' do + context 'when pipeline exists' do + it 'returns requested pipeline' do + expect(helper.find_pipeline(existing_id)).to eq(pipeline) + end + end + + context 'when pipeline does not exists' do + it 'returns nil' do + expect(helper.find_pipeline(non_existing_id)).to be_nil + end + end + + context 'when pipeline id is not provided' do + it 'returns nil' do + expect(helper.find_pipeline(nil)).to be_nil + end + end + end + + context 'when ID is used as an argument' do + let(:existing_id) { pipeline.id } + let(:non_existing_id) { non_existing_record_id } + + it_behaves_like 'pipeline finder' + end + + context 'when string ID is used as an argument' do + let(:existing_id) { pipeline.id.to_s } + let(:non_existing_id) { non_existing_record_id } + + it_behaves_like 'pipeline finder' + end + + context 'when ID is a negative number' do + let(:existing_id) { pipeline.id } + let(:non_existing_id) { -1 } + + it_behaves_like 'pipeline finder' + end + end + + describe '#find_pipeline!' do + let_it_be(:project) { create(:project, :public) } + let_it_be(:pipeline) { create(:ci_pipeline, project: project) } + let_it_be(:user) { create(:user) } + + shared_examples 'private project without access' do + before do + project.update_column(:visibility_level, Gitlab::VisibilityLevel.level_value('private')) + allow(helper).to receive(:authenticate_non_public?).and_return(false) + end + + it 'returns not found' do + expect(helper).to receive(:not_found!) + + helper.find_pipeline!(pipeline.id) + end + end + + context 'when user is authenticated' do + before do + allow(helper).to receive(:current_user).and_return(user) + allow(helper).to receive(:initial_current_user).and_return(user) + end + + context 'public project' do + it 'returns requested pipeline' do + expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline) + end + end + + context 'private project' do + it_behaves_like 'private project without access' + + context 'without read pipeline permission' do + before do + allow(helper).to receive(:can?).with(user, :read_pipeline, pipeline).and_return(false) + end + + it_behaves_like 'private project without access' + end + end + + context 'with read pipeline permission' do + before do + allow(helper).to receive(:can?).with(user, :read_pipeline, pipeline).and_return(true) + end + + it 'returns requested pipeline' do + expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline) + end + end + end + + context 'when user is not authenticated' do + before do + allow(helper).to receive(:current_user).and_return(nil) + allow(helper).to receive(:initial_current_user).and_return(nil) + end + + context 'public project' do + it 'returns requested pipeline' do + expect(helper.find_pipeline!(pipeline.id)).to eq(pipeline) + end + end + + context 'private project' do + it_behaves_like 'private project without access' + end + end + + context 'support for IDs and paths as argument' do + let_it_be(:project) { create(:project) } + let_it_be(:pipeline) { create(:ci_pipeline, project: project) } + + let(:user) { project.first_owner } + + before do + allow(helper).to receive(:current_user).and_return(user) + allow(helper).to receive(:authorized_project_scope?).and_return(true) + allow(helper).to receive(:job_token_authentication?).and_return(false) + allow(helper).to receive(:authenticate_non_public?).and_return(false) + end + + shared_examples 'pipeline finder' do + context 'when pipeline exists' do + it 'returns requested pipeline' do + expect(helper.find_pipeline!(existing_id)).to eq(pipeline) + end + + it 'returns nil' do + expect(helper).to receive(:render_api_error!).with('404 Pipeline Not Found', 404) + expect(helper.find_pipeline!(non_existing_id)).to be_nil + end + end + end + + context 'when ID is used as an argument' do + context 'when pipeline id is an integer' do + let(:existing_id) { pipeline.id } + let(:non_existing_id) { non_existing_record_id } + + it_behaves_like 'pipeline finder' + end + + context 'when pipeline id is a string' do + let(:existing_id) { pipeline.id.to_s } + let(:non_existing_id) { "non_existing_record_id" } + + it_behaves_like 'pipeline finder' + end + end + end + end + describe '#find_group!' do let_it_be(:group) { create(:group, :public) } let_it_be(:user) { create(:user) } diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index 8a5b80e3051..e74bf8f7efa 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -142,5 +142,30 @@ RSpec.describe Ci::PipelinePolicy, :models do end end end + + describe 'read_dependency' do + let(:project) { create(:project, :repository) } + + before do + project.add_developer(user) + allow(policy).to receive(:can?).with(:read_dependency, project).and_return(can_read_project_dependencies) + end + + context 'when user is allowed to read project dependencies' do + let(:can_read_project_dependencies) { true } + + it 'is enabled' do + expect(policy).to be_allowed :read_dependency + end + end + + context 'when user is not allowed to read project dependencies' do + let(:can_read_project_dependencies) { false } + + it 'is disabled' do + expect(policy).not_to be_allowed :read_dependency + end + end + end end end |