diff --git a/app/assets/javascripts/access_level/constants.js b/app/assets/javascripts/access_level/constants.js index d346f3ed40e011abb778be7248301a70a9779c6b..a2c5701325a56a392d8796db58bbd1e3518f0ab2 100644 --- a/app/assets/javascripts/access_level/constants.js +++ b/app/assets/javascripts/access_level/constants.js @@ -6,6 +6,7 @@ export const ACCESS_LEVEL_MINIMAL_ACCESS_INTEGER = 5; export const ACCESS_LEVEL_GUEST_INTEGER = 10; export const ACCESS_LEVEL_PLANNER_INTEGER = 15; export const ACCESS_LEVEL_REPORTER_INTEGER = 20; +export const ACCESS_LEVEL_SECURITY_MANAGER_INTEGER = 25; export const ACCESS_LEVEL_DEVELOPER_INTEGER = 30; export const ACCESS_LEVEL_MAINTAINER_INTEGER = 40; export const ACCESS_LEVEL_OWNER_INTEGER = 50; @@ -18,6 +19,7 @@ export const ACCESS_LEVEL_GUEST_STRING = 'GUEST'; export const ACCESS_LEVEL_PLANNER_STRING = 'PLANNER'; export const ACCESS_LEVEL_REPORTER_STRING = 'REPORTER'; export const ACCESS_LEVEL_DEVELOPER_STRING = 'DEVELOPER'; +export const ACCESS_LEVEL_SECURITY_MANAGER_STRING = 'SECURITY_MANAGER'; export const ACCESS_LEVEL_MAINTAINER_STRING = 'MAINTAINER'; export const ACCESS_LEVEL_OWNER_STRING = 'OWNER'; @@ -27,6 +29,7 @@ export const ACCESS_LEVELS_INTEGER_TO_STRING = { [ACCESS_LEVEL_GUEST_INTEGER]: ACCESS_LEVEL_GUEST_STRING, [ACCESS_LEVEL_PLANNER_INTEGER]: ACCESS_LEVEL_PLANNER_STRING, [ACCESS_LEVEL_REPORTER_INTEGER]: ACCESS_LEVEL_REPORTER_STRING, + [ACCESS_LEVEL_SECURITY_MANAGER_INTEGER]: ACCESS_LEVEL_SECURITY_MANAGER_STRING, [ACCESS_LEVEL_DEVELOPER_INTEGER]: ACCESS_LEVEL_DEVELOPER_STRING, [ACCESS_LEVEL_MAINTAINER_INTEGER]: ACCESS_LEVEL_MAINTAINER_STRING, [ACCESS_LEVEL_OWNER_INTEGER]: ACCESS_LEVEL_OWNER_STRING, @@ -38,6 +41,7 @@ export const ACCESS_LEVELS_STRING_TO_INTEGER = { [ACCESS_LEVEL_GUEST_STRING]: ACCESS_LEVEL_GUEST_INTEGER, [ACCESS_LEVEL_PLANNER_STRING]: ACCESS_LEVEL_PLANNER_INTEGER, [ACCESS_LEVEL_REPORTER_STRING]: ACCESS_LEVEL_REPORTER_INTEGER, + [ACCESS_LEVEL_SECURITY_MANAGER_STRING]: ACCESS_LEVEL_SECURITY_MANAGER_INTEGER, [ACCESS_LEVEL_DEVELOPER_STRING]: ACCESS_LEVEL_DEVELOPER_INTEGER, [ACCESS_LEVEL_MAINTAINER_STRING]: ACCESS_LEVEL_MAINTAINER_INTEGER, [ACCESS_LEVEL_OWNER_STRING]: ACCESS_LEVEL_OWNER_INTEGER, @@ -49,6 +53,7 @@ const ACCESS_LEVEL_GUEST = __('Guest'); const ACCESS_LEVEL_PLANNER = __('Planner'); const ACCESS_LEVEL_REPORTER = __('Reporter'); const ACCESS_LEVEL_DEVELOPER = __('Developer'); +const ACCESS_LEVEL_SECURITY_MANAGER = __('Security Manager'); const ACCESS_LEVEL_MAINTAINER = __('Maintainer'); const ACCESS_LEVEL_OWNER = __('Owner'); export const ACCESS_LEVEL_ADMIN = __('Admin'); @@ -91,6 +96,15 @@ export const BASE_ROLES = [ 'MemberRole|The Reporter role is suitable for team members who need to stay informed about a project or group but do not actively contribute code.', ), }, + { + value: 'SECURITY_MANAGER', + text: ACCESS_LEVEL_SECURITY_MANAGER, + accessLevel: ACCESS_LEVEL_SECURITY_MANAGER_INTEGER, + occupiesSeat: true, + description: s__( + 'MemberRole|The Security Manager role is suitable for team members who need to manage security settings and track security issues.', + ), + }, { value: 'DEVELOPER', text: ACCESS_LEVEL_DEVELOPER, @@ -100,6 +114,7 @@ export const BASE_ROLES = [ 'MemberRole|The Developer role gives users access to contribute code while restricting sensitive administrative actions.', ), }, + { value: 'MAINTAINER', text: ACCESS_LEVEL_MAINTAINER, @@ -134,6 +149,7 @@ export const ACCESS_LEVEL_LABELS = { [ACCESS_LEVEL_GUEST_INTEGER]: ACCESS_LEVEL_GUEST, [ACCESS_LEVEL_PLANNER_INTEGER]: ACCESS_LEVEL_PLANNER, [ACCESS_LEVEL_REPORTER_INTEGER]: ACCESS_LEVEL_REPORTER, + [ACCESS_LEVEL_SECURITY_MANAGER_INTEGER]: ACCESS_LEVEL_SECURITY_MANAGER, [ACCESS_LEVEL_DEVELOPER_INTEGER]: ACCESS_LEVEL_DEVELOPER, [ACCESS_LEVEL_MAINTAINER_INTEGER]: ACCESS_LEVEL_MAINTAINER, [ACCESS_LEVEL_OWNER_INTEGER]: ACCESS_LEVEL_OWNER, diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index fb82a2d4501c5cd071255ded9769f017d3d0910a..e8ae28900f8cf98e7bea8c30b6a569566bf6653a 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -803,6 +803,7 @@ def localized_access_names Gitlab::Access::GUEST => _('Guest'), Gitlab::Access::PLANNER => _('Planner'), Gitlab::Access::REPORTER => _('Reporter'), + Gitlab::Access::SECURITY_MANAGER => _('Security Manager'), Gitlab::Access::DEVELOPER => _('Developer'), Gitlab::Access::MAINTAINER => _('Maintainer'), Gitlab::Access::OWNER => _('Owner') diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index d5f5dea98efa68f2c3b6b15e91b34e5cd3abc47b..54703a26e0031bafa0ae2947af6178f1db107425 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -16,6 +16,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy # This is not a linear condition (some policies available for planner might not be available for higher access levels) condition(:planner) { access_level == GroupMember::PLANNER } condition(:developer) { access_level >= GroupMember::DEVELOPER } + condition(:security_manager) { access_level == GroupMember::SECURITY_MANAGER } condition(:owner) { access_level >= GroupMember::OWNER } condition(:maintainer) { access_level >= GroupMember::MAINTAINER } condition(:reporter) { access_level >= GroupMember::REPORTER } @@ -292,6 +293,10 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy enable :read_internal_note end + rule { security_manager }.policy do + enable :security_manager_access + end + rule { admin | organization_owner }.policy do enable :read_group end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index ecc1d1d90c4c1000be8119a2ef6dd58e3fccaeba..263d0b30a9159aaee98f41e7d183018ab22ab4c5 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -26,6 +26,9 @@ class ProjectPolicy < BasePolicy desc "User has developer access" condition(:developer) { team_access_level >= Gitlab::Access::DEVELOPER } + desc "User has security manager access" + condition(:security_manager) { team_access_level == Gitlab::Access::SECURITY_MANAGER } + desc "User has maintainer access" condition(:maintainer) { team_access_level >= Gitlab::Access::MAINTAINER } @@ -345,6 +348,7 @@ class ProjectPolicy < BasePolicy rule { planner }.enable :planner_access rule { reporter }.enable :reporter_access rule { developer }.enable :developer_access + rule { security_manager }.enable :security_manager_access rule { maintainer }.enable :maintainer_access rule { owner | admin | organization_owner }.enable :owner_access @@ -445,6 +449,10 @@ class ProjectPolicy < BasePolicy prevent :create_merge_request_in end + rule { security_manager }.policy do + # TODO: Add security manager abilities + end + rule { can?(:reporter_access) & can?(:create_issue) }.enable :create_incident rule { can?(:reporter_access) & can?(:read_environment) }.enable :read_freeze_period diff --git a/config/authz/permissions/definitions_todo.txt b/config/authz/permissions/definitions_todo.txt index f6ab90032f64bd55a0236e9ce9ba88881df93657..595a0dda1047154ae142d6b616d17ac4f8b7bfa2 100644 --- a/config/authz/permissions/definitions_todo.txt +++ b/config/authz/permissions/definitions_todo.txt @@ -861,3 +861,4 @@ write_ai_agents write_model_experiments write_model_registry write_observability +security_manager_access diff --git a/doc/api/graphql/reference/_index.md b/doc/api/graphql/reference/_index.md index f28d1582e2abb5bf253fec8d5c429c745391666e..cc3922eb59de492ec4b1de8d3ef06fa0b7d3ee59 100644 --- a/doc/api/graphql/reference/_index.md +++ b/doc/api/graphql/reference/_index.md @@ -50656,6 +50656,7 @@ Access level to a resource. | `OWNER` | Owner access. | | `PLANNER` | Planner access. | | `REPORTER` | Reporter access. | +| `SECURITY_MANAGER` | Security manager access. | ### `AccessTokenGranularScopeAccess` @@ -52495,6 +52496,7 @@ Role of User. | `OWNER` | Owner. | | `PLANNER` | Planner. | | `REPORTER` | Reporter. | +| `SECURITY_MANAGER` | Security manager. | ### `GitlabSubscriptionsUserSort` diff --git a/ee/app/assets/javascripts/roles_and_permissions/graphql/group_roles.query.graphql b/ee/app/assets/javascripts/roles_and_permissions/graphql/group_roles.query.graphql index bb0fe017d8d4d3f8cfd60e61e77cf8255f12dfa8..e510bf393f4cddcd3d7ed2fe51ebaa99e20c5801 100644 --- a/ee/app/assets/javascripts/roles_and_permissions/graphql/group_roles.query.graphql +++ b/ee/app/assets/javascripts/roles_and_permissions/graphql/group_roles.query.graphql @@ -4,7 +4,9 @@ query getGroupRoles($fullPath: ID!, $includeCustomRoles: Boolean!) { group(fullPath: $fullPath) { id # Filter out the Minimal Access role (business requirement). - standardRoles(accessLevel: [GUEST, REPORTER, PLANNER, DEVELOPER, MAINTAINER, OWNER]) { + standardRoles( + accessLevel: [GUEST, REPORTER, PLANNER, DEVELOPER, SECURITY_MANAGER, MAINTAINER, OWNER] + ) { nodes { ...Role } diff --git a/ee/app/assets/javascripts/roles_and_permissions/graphql/instance_roles.query.graphql b/ee/app/assets/javascripts/roles_and_permissions/graphql/instance_roles.query.graphql index cd3e524edb92f371e95a31ec5c3df4cf134bcef8..5e753b18549798cd57ecbf91eb125a6f40687263 100644 --- a/ee/app/assets/javascripts/roles_and_permissions/graphql/instance_roles.query.graphql +++ b/ee/app/assets/javascripts/roles_and_permissions/graphql/instance_roles.query.graphql @@ -2,7 +2,9 @@ query getInstanceRoles($includeCustomRoles: Boolean!, $includeAdminRoles: Boolean!) { # Filter out the Minimal Access role (business requirement). - standardRoles(accessLevel: [GUEST, REPORTER, PLANNER, DEVELOPER, MAINTAINER, OWNER]) { + standardRoles( + accessLevel: [GUEST, REPORTER, PLANNER, DEVELOPER, SECURITY_MANAGER, MAINTAINER, OWNER] + ) { nodes { ...Role } diff --git a/ee/app/policies/ee/group_policy.rb b/ee/app/policies/ee/group_policy.rb index 94b394ccce1ea435e6d6f80379878076a6325ff3..e65cc70d30a6a5729086197ab1603322555b936a 100644 --- a/ee/app/policies/ee/group_policy.rb +++ b/ee/app/policies/ee/group_policy.rb @@ -393,6 +393,10 @@ module GroupPolicy enable :read_security_attribute end + rule { security_manager }.policy do + # TODO: Add security manager abilities for EE features + end + rule { reporter }.policy do enable :admin_issue_board_list enable :view_productivity_analytics diff --git a/ee/bin/custom-ability b/ee/bin/custom-ability index 1b301cf7d05b19593938d5a74103aa9e01d61cfd..cde9c80954267ad72059d5ff5f06ecbf9657a8c4 100755 --- a/ee/bin/custom-ability +++ b/ee/bin/custom-ability @@ -23,6 +23,7 @@ LEVELS = { 'Guest' => 10, 'Planner' => 15, 'Reporter' => 20, + 'Security Manager' => 25, 'Developer' => 30, 'Maintainer' => 40, 'Owner' => 50, diff --git a/ee/spec/features/groups/members/manage_members_spec.rb b/ee/spec/features/groups/members/manage_members_spec.rb index 211739796ecb58b9fc4fe2d26ced70f724f5dc0a..f01dbcf6a0dae9a6449d81c34bc928664465e888 100644 --- a/ee/spec/features/groups/members/manage_members_spec.rb +++ b/ee/spec/features/groups/members/manage_members_spec.rb @@ -474,7 +474,7 @@ def add_user_by_email(role, use_exact_text_match: true) let_it_be(:group_owner) { create(:user, owner_of: group) } - let(:access_levels) { %w[Guest Planner Reporter Developer Maintainer Owner] } + let(:access_levels) { ['Guest', 'Planner', 'Reporter', 'Security Manager', 'Developer', 'Maintainer', 'Owner'] } let(:member_role_text) { "#{member_role.name}\n#{member_role.description}" } before do diff --git a/ee/spec/frontend/pages/projects/shared/permissions/secrets_manager/components/secrets_manager_permissions_modal_spec.js b/ee/spec/frontend/pages/projects/shared/permissions/secrets_manager/components/secrets_manager_permissions_modal_spec.js index d330f8530434365e3892d3c27892076cb9b71e15..6701000fa26f31b89831fd1f0689a856ac48d6f4 100644 --- a/ee/spec/frontend/pages/projects/shared/permissions/secrets_manager/components/secrets_manager_permissions_modal_spec.js +++ b/ee/spec/frontend/pages/projects/shared/permissions/secrets_manager/components/secrets_manager_permissions_modal_spec.js @@ -140,7 +140,7 @@ describe('SecretsManagerPermissionsModal', () => { const USER_ITEMS = ['Administrator', 'John Doe']; const GROUP_ITEMS = ['Organization', 'test-org']; - const ROLE_ITEMS = ['Reporter', 'Developer', 'Maintainer']; + const ROLE_ITEMS = ['Reporter', 'Security Manager', 'Developer', 'Maintainer']; describe.each` category | title | fieldItems | selectedItem | principalId diff --git a/ee/spec/frontend/roles_and_permissions/components/manage_role/role_form_spec.js b/ee/spec/frontend/roles_and_permissions/components/manage_role/role_form_spec.js index 91fc8bfdb280bcb063463570e279121a99008474..abc6ad7d4aa0690a3760b64e94dadee6b1194c33 100644 --- a/ee/spec/frontend/roles_and_permissions/components/manage_role/role_form_spec.js +++ b/ee/spec/frontend/roles_and_permissions/components/manage_role/role_form_spec.js @@ -1,11 +1,11 @@ -import { GlFormInput, GlCollapsibleListbox, GlForm, GlFormGroup } from '@gitlab/ui'; +import { GlCollapsibleListbox, GlForm, GlFormGroup, GlFormInput } from '@gitlab/ui'; import { nextTick } from 'vue'; -import { createAlert } from '~/alert'; +import PermissionsSelector from 'ee/roles_and_permissions/components/manage_role/permissions_selector.vue'; import RoleForm from 'ee/roles_and_permissions/components/manage_role/role_form.vue'; +import { stubComponent } from 'helpers/stub_component'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import waitForPromises from 'helpers/wait_for_promises'; -import { stubComponent } from 'helpers/stub_component'; -import PermissionsSelector from 'ee/roles_and_permissions/components/manage_role/permissions_selector.vue'; +import { createAlert } from '~/alert'; import PageHeading from '~/vue_shared/components/page_heading.vue'; import { mockMemberRole } from '../../mock_data'; @@ -92,6 +92,7 @@ describe('RoleForm', () => { 'GUEST', 'PLANNER', 'REPORTER', + 'SECURITY_MANAGER', 'DEVELOPER', 'MAINTAINER', ]; diff --git a/ee/spec/frontend/roles_and_permissions/mock_data.js b/ee/spec/frontend/roles_and_permissions/mock_data.js index a793c62c8bf24c1bed94b0623eb1ffabd4fff39c..8a0d6f2247cb1289d462e02c69a9108e9640b32f 100644 --- a/ee/spec/frontend/roles_and_permissions/mock_data.js +++ b/ee/spec/frontend/roles_and_permissions/mock_data.js @@ -110,6 +110,15 @@ export const standardRoles = [ description: 'The Developer role gives users access to contribute code while restricting sensitive administrative actions.', }, + { + __typename: 'StandardRole', + id: 'gid://gitlab/StandardRole/SECURITY_MANAGER', + accessLevel: 30, + name: 'Security Manager', + detailsPath: 'role/SECURITY_MANAGER', + description: + 'The Security Manager role is designed for team members who need to oversee security features, including vulnerability management, security dashboards, and policy monitoring, while having restricted access to non-security related administrative functions.', + }, { __typename: 'StandardRole', id: 'gid://gitlab/StandardRole/MAINTAINER', diff --git a/ee/spec/policies/project_policy_spec.rb b/ee/spec/policies/project_policy_spec.rb index 35b6a2e81ccb63a80af373f5c3aad7c5d0bcf830..2164752eb7660e5c5bf3f1ced23db5e250d6bf05 100644 --- a/ee/spec/policies/project_policy_spec.rb +++ b/ee/spec/policies/project_policy_spec.rb @@ -1791,6 +1791,7 @@ :planner | nil | true :reporter | nil | true :developer | nil | true + :security_manager | nil | true :maintainer | nil | true :owner | nil | true :admin | false | false diff --git a/ee/spec/policies/requirements_management/requirement_policy_spec.rb b/ee/spec/policies/requirements_management/requirement_policy_spec.rb index c5b2df8ec6f831bab10e599dfeaf7a1df454ecb0..35610e631c787c2bbdac57d7a66653fa9001ea79 100644 --- a/ee/spec/policies/requirements_management/requirement_policy_spec.rb +++ b/ee/spec/policies/requirements_management/requirement_policy_spec.rb @@ -7,12 +7,13 @@ let_it_be(:admin) { create(:admin) } let_it_be(:planner) { create(:user) } let_it_be(:reporter) { create(:user) } + let_it_be(:security_manager) { create(:user) } let_it_be(:developer) { create(:user) } let_it_be(:maintainer) { create(:user) } let_it_be(:guest) { create(:user) } let_it_be(:project) do create(:project, :public, namespace: owner.namespace, planners: planner, reporters: reporter, developers: developer, - maintainers: maintainer, guests: guest) + maintainers: maintainer, guests: guest, security_managers: security_manager) end let_it_be(:resource, reload: true) { create(:work_item, :requirement, project: project).requirement } diff --git a/ee/spec/support/shared_examples/policies/requirement_policy_shared_examples.rb b/ee/spec/support/shared_examples/policies/requirement_policy_shared_examples.rb index 426d951f4a1f10d0cc651384898cdffc0f9eaa67..073af9270f8f549686e371b2aafd12c677f97f2a 100644 --- a/ee/spec/support/shared_examples/policies/requirement_policy_shared_examples.rb +++ b/ee/spec/support/shared_examples/policies/requirement_policy_shared_examples.rb @@ -65,6 +65,12 @@ it_behaves_like 'user with manage permissions' end + context 'with security manager' do + let(:current_user) { security_manager } + + it_behaves_like 'user with manage permissions' + end + context 'with guest' do let(:current_user) { guest } diff --git a/locale/gitlab.pot b/locale/gitlab.pot index b96411c49d666203611447f4c1afbbfe7665f0ee..17026f5efc5337fe34a03a8493fec109f1eda66d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -41489,6 +41489,9 @@ msgstr "" msgid "MemberRole|The Reporter role is suitable for team members who need to stay informed about a project or group but do not actively contribute code." msgstr "" +msgid "MemberRole|The Security Manager role is suitable for team members who need to manage security settings and track security issues." +msgstr "" + msgid "MemberRole|The Security Manager role provides comprehensive visibility and management over security aspects of the group or project." msgstr "" @@ -59898,6 +59901,9 @@ msgstr "" msgid "Security Finding not found" msgstr "" +msgid "Security Manager" +msgstr "" + msgid "Security Policy project already exists, but is not linked." msgstr "" diff --git a/qa/qa/resource/project_member.rb b/qa/qa/resource/project_member.rb index dfaa157038ce3cd245cdbed96b7c7409d49154cc..bdd87317540bd3ad7e10c577533f5115175d6708 100644 --- a/qa/qa/resource/project_member.rb +++ b/qa/qa/resource/project_member.rb @@ -10,6 +10,7 @@ def initialize @level = { guest: 10, reporter: 20, + security_manager: 25, developer: 30, maintainer: 40, owner: 50 diff --git a/spec/factories/user_highest_roles.rb b/spec/factories/user_highest_roles.rb index 04e3e344b4c4e02ef34d58fd960690676708f8e0..2b97f5670574b16983d43b9a55244b5831a4aa17 100644 --- a/spec/factories/user_highest_roles.rb +++ b/spec/factories/user_highest_roles.rb @@ -9,6 +9,7 @@ trait(:planner) { highest_access_level { GroupMember::PLANNER } } trait(:reporter) { highest_access_level { GroupMember::REPORTER } } trait(:developer) { highest_access_level { GroupMember::DEVELOPER } } + trait(:security_manager) { highest_access_level { GroupMember::SECURITY_MANAGER } } trait(:maintainer) { highest_access_level { GroupMember::MAINTAINER } } trait(:owner) { highest_access_level { GroupMember::OWNER } } end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 86f329c71445a5617e7371b5932f4a32f5c632d4..923190d6e031a3c1abeb19fdbbbf69bf1289ee09 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -227,6 +227,7 @@ reporter_of {} security_manager_of {} developer_of {} + security_manager_of {} maintainer_of {} owner_of {} # rubocop:enable Lint/EmptyBlock @@ -238,6 +239,7 @@ Array.wrap(evaluator.reporter_of).each { |target| target.add_reporter(user) } Array.wrap(evaluator.security_manager_of).each { |target| target.add_security_manager(user) } Array.wrap(evaluator.developer_of).each { |target| target.add_developer(user) } + Array.wrap(evaluator.security_manager_of).each { |target| target.add_security_manager(user) } Array.wrap(evaluator.maintainer_of).each { |target| target.add_maintainer(user) } Array.wrap(evaluator.owner_of).each { |target| target.add_owner(user) } end diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb index 7e2cc267ccd817c9f72658c2085a02e9e45a41fd..9de31a341b82489931b5c4b6172a4c5d6783ce90 100644 --- a/spec/features/projects/members/manage_members_spec.rb +++ b/spec/features/projects/members/manage_members_spec.rb @@ -103,7 +103,8 @@ page.within role_dropdown_selector do wait_for_requests toggle_listbox - expect_listbox_items(%w[Guest Planner Reporter Developer Maintainer Owner]) + expect_listbox_items( + ['Guest', 'Planner', 'Reporter', 'Security Manager', 'Developer', 'Maintainer', 'Owner']) end end end diff --git a/spec/frontend/members/mock_data.js b/spec/frontend/members/mock_data.js index 67ab21cb73646f23388f32b929b84b1a6df5f671..4fddd3c9ff95feae2fa89b0cb8414b9662143040 100644 --- a/spec/frontend/members/mock_data.js +++ b/spec/frontend/members/mock_data.js @@ -1,7 +1,7 @@ import { MEMBERS_TAB_TYPES, - MEMBER_STATE_CREATED, MEMBER_MODEL_TYPE_GROUP_MEMBER, + MEMBER_STATE_CREATED, } from '~/members/constants'; export const member = { @@ -57,6 +57,7 @@ export const member = { Guest: 10, Planner: 15, Reporter: 20, + 'Security Manager': 25, Developer: 30, Maintainer: 40, Owner: 50, diff --git a/spec/models/user_highest_role_spec.rb b/spec/models/user_highest_role_spec.rb index 234327caac908960420af5c9dc65fdbe22db7f9c..b3e13497808d4e09da8daa66bd58c3c0239c67f7 100644 --- a/spec/models/user_highest_role_spec.rb +++ b/spec/models/user_highest_role_spec.rb @@ -35,6 +35,7 @@ Gitlab::Access::REPORTER, Gitlab::Access::SECURITY_MANAGER, Gitlab::Access::DEVELOPER, + Gitlab::Access::SECURITY_MANAGER, Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER ] diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb index 98c85151e22f4ef8b3a2c9a7322d76e9e9cbb6fc..74cc86bca89431a2b52efb2e191f9b5d307a9710 100644 --- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb +++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb @@ -7,6 +7,7 @@ let_it_be_with_reload(:reporter) { create(:user) } let_it_be_with_reload(:developer) { create(:user) } let_it_be_with_reload(:maintainer) { create(:user) } + let_it_be_with_reload(:security_manager) { create(:user) } let_it_be_with_reload(:inherited_guest) { create(:user) } let_it_be_with_reload(:inherited_planner) { create(:user) } let_it_be_with_reload(:inherited_reporter) { create(:user) } @@ -142,6 +143,7 @@ project.add_reporter(reporter) project.add_developer(developer) project.add_maintainer(maintainer) + project.add_security_manager(security_manager) project.add_owner(owner) end end