diff --git a/.gitlab/ci/package-and-test/main.gitlab-ci.yml b/.gitlab/ci/package-and-test/main.gitlab-ci.yml index 23c40f30013..bdab06d2850 100644 --- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml +++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml @@ -39,12 +39,13 @@ download-knapsack-report: _quarantine: extends: - .qa - - .rules:test:manual + - .rules:test:manual-except-default-branch needs: - job: trigger-omnibus optional: true stage: test variables: + CREATE_TEST_FAILURE_ISSUES: 'false' QA_RSPEC_TAGS: --tag quarantine # ------------------------------------------ diff --git a/.gitlab/ci/qa-common/rules.gitlab-ci.yml b/.gitlab/ci/qa-common/rules.gitlab-ci.yml index fd8a02a786b..8c2f57c80cc 100644 --- a/.gitlab/ci/qa-common/rules.gitlab-ci.yml +++ b/.gitlab/ci/qa-common/rules.gitlab-ci.yml @@ -77,6 +77,11 @@ include: variables: QA_TESTS: "" +.rules:test:manual-except-default-branch: + rules: + - *default-branch + - !reference [.rules:test:manual, rules] + .rules:test:feature-flags-set: rules: # unset specific specs if pipeline has feature flag changes and run full suite diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb index c95cde86e38..de0b922687b 100644 --- a/app/policies/issue_policy.rb +++ b/app/policies/issue_policy.rb @@ -31,6 +31,14 @@ class IssuePolicy < IssuablePolicy condition(:group_issue, scope: :subject) { subject_container.is_a?(Group) } + condition(:service_desk_enabled, scope: :subject) do + if group_issue? + subject_container.has_project_with_service_desk_enabled? + else + subject_container.service_desk_enabled? + end + end + rule { group_issue & can?(:read_group) }.policy do enable :create_note end @@ -104,6 +112,8 @@ class IssuePolicy < IssuablePolicy enable :admin_issue_relation end + rule { support_bot & service_desk_enabled }.enable :admin_issue_relation + rule { can_read_crm_contacts }.policy do enable :read_crm_contacts end diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md index 69404f5a279..cc5e92787cc 100644 --- a/doc/administration/packages/container_registry.md +++ b/doc/administration/packages/container_registry.md @@ -838,9 +838,9 @@ project, you can [disable it from your project's settings](../../user/project/se ## Use an external container registry with GitLab as an auth endpoint WARNING: -Using external container registries in GitLab is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/376217) -in GitLab 15.8 and the end of support is scheduled for GitLab 16.0. -If you need to use external container registries instead of the GitLab container registry, +Using third-party container registries in GitLab was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/376217) +in GitLab 15.8 and support ended in GitLab 16.0. +If you need to use third-party container registries instead of the GitLab container registry, tell us about your use cases in [feedback issue 958](https://gitlab.com/gitlab-org/container-registry/-/issues/958). If you use an external container registry, some features associated with the diff --git a/doc/ci/cloud_services/aws/index.md b/doc/ci/cloud_services/aws/index.md index 5e13a09ff91..b7637a5e235 100644 --- a/doc/ci/cloud_services/aws/index.md +++ b/doc/ci/cloud_services/aws/index.md @@ -105,3 +105,23 @@ This error can occur for multiple reasons: - The cloud administrator has not configured the project to use OIDC with GitLab. - The role is restricted from being run on the branch or tag. See [configure a conditional role](../index.md). - `StringEquals` is used instead of `StringLike` when using a wildcard condition. See [related issue](https://gitlab.com/guided-explorations/aws/configure-openid-connect-in-aws/-/issues/2#note_852901934). + +### `Could not connect to openid configuration of provider` error + +After adding the Identity Provider in AWS IAM, you might get the following error: + +```plaintext +Your request has a problem. Please see the following details. + - Could not connect to openid configuration of provider: `https://gitlab.example.com` +``` + +This error occurs when the OIDC identity provider's issuer presents a certificate chain +that's out of order, or includes duplicate or additional certificates. + +Verify your GitLab instance's certificate chain. The chain must start with the domain or issuer URL, +then the intermediate certificate, and end with the root certificate. Use this command to +review the certificate chain, replacing `gitlab.example.com` with your GitLab hostname: + +```shell +echo | /opt/gitlab/embedded/bin/openssl s_client -connect gitlab.example.com:443 +``` diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md index 59452675216..278272a384b 100644 --- a/doc/security/webhooks.md +++ b/doc/security/webhooks.md @@ -147,80 +147,6 @@ example.com;gitlab.example.com example.com:8080 ``` -## Configure webhooks to support mutual TLS - -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27450) in GitLab 16.9. - -You can configure webhooks to support mutual TLS by configuring a client -certificate in PEM format. This certificate is set globally and -presented to the server during a TLS handshake. The certificate can also -be protected with a PEM passphrase. - -To configure the certificate, follow the instructions: - -::Tabs - -:::TabTitle Linux package (Omnibus) - -1. Edit `/etc/gitlab/gitlab.rb`: - - ```ruby - gitlab_rails['http_client']['tls_client_cert_file'] = '' - gitlab_rails['http_client']['tls_client_cert_password'] = '' - ``` - -1. Save the file and reconfigure GitLab: - - ```shell - sudo gitlab-ctl reconfigure - ``` - -:::TabTitle Docker - -1. Edit `docker-compose.yml`: - - ```yaml - version: "3.6" - services: - gitlab: - image: 'gitlab/gitlab-ee:latest' - restart: always - hostname: 'gitlab.example.com' - environment: - GITLAB_OMNIBUS_CONFIG: | - gitlab_rails['http_client']['tls_client_cert_file'] = '' - gitlab_rails['http_client']['tls_client_cert_password'] = '' - ``` - -1. Save the file and restart GitLab: - - ```shell - docker compose up -d - ``` - -:::TabTitle Self-compiled (source) - -1. Edit `/home/git/gitlab/config/gitlab.yml`: - - ```yaml - production: &base - http_client: - tls_client_cert_file: '' - tls_client_cert_password: '' - ``` - -1. Save the file and restart GitLab: - - ```shell - # For systems running systemd - sudo systemctl restart gitlab.target - - # For systems running SysV init - sudo service gitlab restart - ``` - -::EndTabs - ## Troubleshooting When filtering outbound requests, you might encounter the following issues. diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md index 7ff9f05d0a9..314e0ec6529 100644 --- a/doc/user/project/integrations/webhooks.md +++ b/doc/user/project/integrations/webhooks.md @@ -329,6 +329,87 @@ For a safer development environment, you can use the [GitLab Development Kit (GD You can [review recently triggered webhook payloads](#troubleshooting) in GitLab settings. For each webhook event, a detail page exists with information about the data GitLab sends and receives from the webhook endpoint. +## Configure webhooks to support mutual TLS + +DETAILS: +**Offering:** self-managed + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27450) in GitLab 16.9. + +Prerequisites: + +- You must be a GitLab administrator. + +You can configure webhooks to support mutual TLS by configuring a client +certificate in PEM format. This certificate is set globally and +presented to the server during a TLS handshake. The certificate can also +be protected with a PEM passphrase. + +To configure the certificate, follow the instructions below. + +::Tabs + +:::TabTitle Linux package (Omnibus) + +1. Edit `/etc/gitlab/gitlab.rb`: + + ```ruby + gitlab_rails['http_client']['tls_client_cert_file'] = '' + gitlab_rails['http_client']['tls_client_cert_password'] = '' + ``` + +1. Save the file and reconfigure GitLab: + + ```shell + sudo gitlab-ctl reconfigure + ``` + +:::TabTitle Docker + +1. Edit `docker-compose.yml`: + + ```yaml + version: "3.6" + services: + gitlab: + image: 'gitlab/gitlab-ee:latest' + restart: always + hostname: 'gitlab.example.com' + environment: + GITLAB_OMNIBUS_CONFIG: | + gitlab_rails['http_client']['tls_client_cert_file'] = '' + gitlab_rails['http_client']['tls_client_cert_password'] = '' + ``` + +1. Save the file and restart GitLab: + + ```shell + docker compose up -d + ``` + +:::TabTitle Self-compiled (source) + +1. Edit `/home/git/gitlab/config/gitlab.yml`: + + ```yaml + production: &base + http_client: + tls_client_cert_file: '' + tls_client_cert_password: '' + ``` + +1. Save the file and restart GitLab: + + ```shell + # For systems running systemd + sudo systemctl restart gitlab.target + + # For systems running SysV init + sudo service gitlab restart + ``` + +::EndTabs + ## Related topics - [Project hooks API](../../../api/projects.md#hooks) diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index 3936ac57ecc..77bb9146569 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -23,7 +23,6 @@ module Gitlab CommandError = Class.new(BaseError) CommitError = Class.new(BaseError) OSError = Class.new(BaseError) - UnknownRef = Class.new(BaseError) AmbiguousRef = Class.new(BaseError) CommandTimedOut = Class.new(CommandError) InvalidPageToken = Class.new(BaseError) @@ -46,6 +45,15 @@ module Gitlab end end + class ReferenceNotFoundError < BaseError + attr_reader :name + + def initialize(msg = nil, name = "") + super(msg) + @name = name + end + end + class << self include Gitlab::EncodingHelper diff --git a/lib/gitlab/git/merge_base.rb b/lib/gitlab/git/merge_base.rb index 905d72cadbf..c78338df1b5 100644 --- a/lib/gitlab/git/merge_base.rb +++ b/lib/gitlab/git/merge_base.rb @@ -13,7 +13,7 @@ module Gitlab # Returns the SHA of the first common ancestor def sha if unknown_refs.any? - raise UnknownRef, "Can't find merge base for unknown refs: #{unknown_refs.inspect}" + raise ReferenceNotFoundError, "Can't find merge base for unknown refs: #{unknown_refs.inspect}" end strong_memoize(:sha) do diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index dcb384e31d4..6f216fbf7a9 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -139,7 +139,7 @@ module Gitlab # `CommandError` by the wrapper. This has been converted in v15.3.0 to instead return a structured # error with a `tag_not_found` error, so rescuing from `Internal` errors can be removed in v15.4.0 and # later. - rescue Gitlab::Git::UnknownRef + rescue Gitlab::Git::ReferenceNotFoundError # This is the new error returned by `find_tag`, which knows to translate the structured error returned # by Gitaly when the tag does not exist. end diff --git a/lib/gitlab/git/wraps_gitaly_errors.rb b/lib/gitlab/git/wraps_gitaly_errors.rb index 20bcf3585e1..9e1c196d4e4 100644 --- a/lib/gitlab/git/wraps_gitaly_errors.rb +++ b/lib/gitlab/git/wraps_gitaly_errors.rb @@ -13,7 +13,7 @@ module Gitlab # status code to ensure adequate coverage of error cases. case e.code when GRPC::Core::StatusCodes::NOT_FOUND - raise Gitlab::Git::Repository::NoRepository, e + handle_not_found(e) when GRPC::Core::StatusCodes::INVALID_ARGUMENT raise ArgumentError, e when GRPC::Core::StatusCodes::DEADLINE_EXCEEDED @@ -40,6 +40,19 @@ module Gitlab raise ResourceExhaustedError, _("Upstream Gitaly has been exhausted. Try again later") end end + + def handle_not_found(exception) + detail = Gitlab::GitalyClient.decode_detailed_error(exception) + + case detail.class.name + when Gitaly::ReferenceNotFoundError.name + raise Gitlab::Git::ReferenceNotFoundError.new( + exception, detail.reference_name + ) + else + raise Gitlab::Git::Repository::NoRepository, exception + end + end end end end diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb index c251c126b07..3a92404fc6c 100644 --- a/lib/gitlab/gitaly_client/ref_service.rb +++ b/lib/gitlab/gitaly_client/ref_service.rb @@ -115,7 +115,7 @@ module Gitlab case detailed_error.try(:error) when :tag_not_found - raise Gitlab::Git::UnknownRef, "tag does not exist: #{tag_name}" + raise Gitlab::Git::ReferenceNotFoundError, "tag does not exist: #{tag_name}" else # When this is not a know structured error we simply re-raise the exception. raise e diff --git a/locale/gitlab.pot b/locale/gitlab.pot index f05ee97e45d..a9e2c205b0c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -19539,6 +19539,9 @@ msgstr "" msgid "Epic events" msgstr "" +msgid "Epic issue not found for given params" +msgstr "" + msgid "Epic not found for given params" msgstr "" @@ -26116,6 +26119,9 @@ msgstr "" msgid "Insufficient permissions for dast_configuration keyword" msgstr "" +msgid "Insufficient permissions to update relation" +msgstr "" + msgid "Integration" msgstr "" diff --git a/spec/lib/gitlab/git/merge_base_spec.rb b/spec/lib/gitlab/git/merge_base_spec.rb index cbe47aae852..418ef4569ff 100644 --- a/spec/lib/gitlab/git/merge_base_spec.rb +++ b/spec/lib/gitlab/git/merge_base_spec.rb @@ -42,7 +42,7 @@ RSpec.describe Gitlab::Git::MergeBase do it 'does not call merge_base on the repository but raises an error' do expect(repository).not_to receive(:merge_base) - expect { merge_base.sha }.to raise_error(Gitlab::Git::UnknownRef) + expect { merge_base.sha }.to raise_error(Gitlab::Git::ReferenceNotFoundError) end end diff --git a/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb b/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb index c321d4bbdb9..5b1dd41ac03 100644 --- a/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb +++ b/spec/lib/gitlab/git/wraps_gitaly_errors_spec.rb @@ -85,4 +85,35 @@ RSpec.describe Gitlab::Git::WrapsGitalyErrors, feature_category: :gitaly do .to raise_error(RuntimeError) end end + + context 'when wrap GRPC::NotFound' do + context 'with Gitaly::ReferenceNotFoundError detail' do + let(:original_error) do + new_detailed_error( + GRPC::Core::StatusCodes::NOT_FOUND, + 'not found', + Gitaly::ReferenceNotFoundError.new(reference_name: "foobar") + ) + end + + it "wraps in a Gitlab::Git::ReferenceNotFoundError" do + expect { wrapper.wrapped_gitaly_errors { raise original_error } }.to raise_error do |wrapped_error| + expect(wrapped_error).to be_a(Gitlab::Git::ReferenceNotFoundError) + expect(wrapped_error.name).to eql("foobar") + end + end + end + + context 'without detail' do + let(:original_error) do + GRPC::NotFound + end + + it "wraps in a Gitlab::Git::Repository::NoRepository" do + expect { wrapper.wrapped_gitaly_errors { raise original_error } }.to raise_error do |wrapped_error| + expect(wrapped_error).to be_a(Gitlab::Git::Repository::NoRepository) + end + end + end + end end diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb index 118b316f2d4..5b746b7ab1a 100644 --- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb @@ -128,7 +128,8 @@ RSpec.describe Gitlab::GitalyClient::RefService, feature_category: :gitaly do "tag was not found", Gitaly::FindTagError.new(tag_not_found: Gitaly::ReferenceNotFoundError.new))) - expect { client.find_tag('v1.0.0') }.to raise_error(Gitlab::Git::UnknownRef, 'tag does not exist: v1.0.0') + expect { client.find_tag('v1.0.0') }.to raise_error(Gitlab::Git::ReferenceNotFoundError, + 'tag does not exist: v1.0.0') end end end diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index 1d7748ee25a..94b05e50ef6 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -34,17 +34,17 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do end it 'allows support_bot to read issues, create and set metadata on new issues' do - expect(permissions(support_bot, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(support_bot, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(support_bot, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality) + expect(permissions(support_bot, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation) + expect(permissions(support_bot, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation) + expect(permissions(support_bot, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation) end end shared_examples 'support bot with service desk disabled' do it 'does not allow support_bot to read issues, create and set metadata on new issues' do - expect(permissions(support_bot, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(support_bot, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(support_bot, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality) + expect(permissions(support_bot, issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation) + expect(permissions(support_bot, issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation) + expect(permissions(support_bot, new_issue)).to be_disallowed(:create_issue, :set_issue_metadata, :set_confidentiality, :admin_issue_relation) end end @@ -71,6 +71,7 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do context 'a private project' do let_it_be(:project) { create(:project, :private) } + let_it_be_with_reload(:group_issue) { create(:issue, :group_level, namespace: group) } let_it_be_with_reload(:issue) { create(:issue, project: project, assignees: [assignee], author: author) } let_it_be_with_reload(:issue_no_assignee) { create(:issue, project: project) } let(:new_issue) { build(:issue, project: project, assignees: [assignee], author: author) } @@ -197,6 +198,7 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do context 'a public project' do let_it_be_with_reload(:project) { create(:project, :public) } let_it_be_with_reload(:issue) { create(:issue, project: project, assignees: [assignee], author: author) } + let_it_be_with_reload(:group_issue) { create(:issue, :group_level, namespace: group) } let_it_be_with_reload(:issue_no_assignee) { create(:issue, project: project) } let_it_be_with_reload(:issue_locked) { create(:issue, :locked, project: project, author: author, assignees: [assignee]) } let(:new_issue) { build(:issue, project: project) } @@ -252,27 +254,27 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do end it 'allows issue authors to read, reopen and update their issues' do - expect(permissions(author, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :reopen_issue, :admin_issue_relation) + expect(permissions(author, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :reopen_issue) expect(permissions(author, issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(author, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :admin_issue_relation) + expect(permissions(author, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid) expect(permissions(author, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(author, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue_relation) + expect(permissions(author, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue) expect(permissions(author, issue_locked)).to be_disallowed(:admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(author, new_issue)).to be_allowed(:create_issue, :admin_issue_relation) + expect(permissions(author, new_issue)).to be_allowed(:create_issue) expect(permissions(author, new_issue)).to be_disallowed(:set_issue_metadata) end it 'allows issue assignees to read, reopen and update their issues' do - expect(permissions(assignee, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :reopen_issue, :admin_issue_relation) + expect(permissions(assignee, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :reopen_issue) expect(permissions(assignee, issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(assignee, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :admin_issue_relation) + expect(permissions(assignee, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid) expect(permissions(assignee, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality) - expect(permissions(assignee, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue_relation) + expect(permissions(assignee, issue_locked)).to be_allowed(:read_issue, :read_issue_iid, :update_issue) expect(permissions(assignee, issue_locked)).to be_disallowed(:admin_issue, :reopen_issue, :set_issue_metadata, :set_confidentiality) end @@ -383,7 +385,7 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) } it 'does not allow guests to read confidential issues' do - expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue) + expect(permissions(guest, confidential_issue)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :admin_issue_relation) expect(permissions(guest, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) end @@ -398,14 +400,14 @@ RSpec.describe IssuePolicy, feature_category: :team_planning do end it 'allows issue authors to read and update their confidential issues' do - expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue_relation) + expect(permissions(author, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue) expect(permissions(author, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality) expect(permissions(author, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality) end it 'allows issue assignees to read and update their confidential issues' do - expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue_relation) + expect(permissions(assignee, confidential_issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue) expect(permissions(assignee, confidential_issue)).to be_disallowed(:admin_issue, :set_issue_metadata, :set_confidentiality) expect(permissions(assignee, confidential_issue_no_assignee)).to be_disallowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)