Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-06-23 21:11:36 +00:00
parent c5198a0a78
commit 0b79f8dae4
27 changed files with 601 additions and 558 deletions

View File

@ -1 +1 @@
889fff0a39dc1d79dc585f345e4fd82105b57a7f
31259f5394382f015730d7bbfeb775623d69145f

View File

@ -4,8 +4,10 @@ import { parseBoolean } from './lib/utils/common_utils';
import { __ } from './locale';
import { visitUrl } from './lib/utils/url_utility';
const DEFERRED_LINK_CLASS = '.deferred-link';
/**
* Integrates with server-side rendered callouts, adding dismissing interaction to them.
* See https://docs.gitlab.com/development/callouts/#server-side-rendered-callouts
*/
export default class PersistentUserCallout {
constructor(container, options = container.dataset) {
const { dismissEndpoint, featureId, groupId, projectId, deferLinks } = options;
@ -21,23 +23,13 @@ export default class PersistentUserCallout {
}
init() {
const followLink = this.container.querySelector('.js-follow-link');
if (this.closeButtons.length) {
this.handleCloseButtonCallout();
} else if (followLink) {
this.handleFollowLinkCallout(followLink);
}
}
handleCloseButtonCallout() {
this.closeButtons.forEach((closeButton) => {
closeButton.addEventListener('click', this.dismiss);
});
if (this.deferLinks) {
if (this.closeButtons.length && this.deferLinks) {
this.container.addEventListener('click', (event) => {
const deferredLinkEl = event.target.closest(DEFERRED_LINK_CLASS);
const deferredLinkEl = event.target.closest('.deferred-link');
if (deferredLinkEl) {
const { href, target } = deferredLinkEl;
@ -47,10 +39,6 @@ export default class PersistentUserCallout {
}
}
handleFollowLinkCallout(followLink) {
followLink.addEventListener('click', (event) => this.registerCalloutWithLink(event));
}
dismiss = (event, deferredLinkOptions = null) => {
event.preventDefault();
@ -80,27 +68,6 @@ export default class PersistentUserCallout {
});
};
registerCalloutWithLink(event) {
event.preventDefault();
const { href } = event.currentTarget;
axios
.post(this.dismissEndpoint, {
feature_name: this.featureId,
})
.then(() => {
window.location.assign(href);
})
.catch(() => {
createAlert({
message: __(
'An error occurred while acknowledging the notification. Refresh the page and try again.',
),
});
});
}
static factory(container, options) {
if (!container) {
return undefined;

View File

@ -10,8 +10,11 @@ import {
import SafeHtml from '~/vue_shared/directives/safe_html';
import { s__, __, sprintf } from '~/locale';
import Tracking from '~/tracking';
import PersistentUserCallout from '~/persistent_user_callout';
import { SET_STATUS_MODAL_ID } from '~/set_status_modal/constants';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { logError } from '~/lib/logger';
import { USER_MENU_TRACKING_DEFAULTS, DROPDOWN_Y_OFFSET, IMPERSONATING_OFFSET } from '../constants';
import UserMenuProfileItem from './user_menu_profile_item.vue';
@ -128,7 +131,6 @@ export default {
warningText: this.$options.i18n.oneOfGroupsRunningOutOfPipelineMinutes,
href: this.data.pipeline_minutes?.buy_pipeline_minutes_path,
extraAttrs: {
class: 'js-follow-link',
...USER_MENU_TRACKING_DEFAULTS,
'data-track-label': 'buy_pipeline_minutes',
},
@ -199,14 +201,6 @@ export default {
'current-clear-status-after': clearAfter || '',
};
},
buyPipelineMinutesCalloutData() {
return this.showNotificationDot
? {
'data-feature-id': this.data.pipeline_minutes.callout_attrs.feature_id,
'data-dismiss-endpoint': this.data.pipeline_minutes.callout_attrs.dismiss_endpoint,
}
: {};
},
showEnterAdminModeItem() {
return (
this.data.admin_mode.user_is_admin &&
@ -249,21 +243,38 @@ export default {
this.$refs.userDropdown.close();
},
initBuyCIMinsCallout() {
if (this.showNotificationDot) {
PersistentUserCallout.factory(this.$refs?.buyPipelineMinutesNotificationCallout.$el);
}
const el = this.$refs?.buyPipelineMinutesNotificationCallout?.$el;
el?.addEventListener('click', this.onBuyCIMinutesItemClick);
},
/* We're not sure this event is tracked by anyone
whether it stays will depend on the outcome of this discussion:
https://gitlab.com/gitlab-org/gitlab/-/issues/402713#note_1343072135 */
trackBuyCIMins() {
if (this.addBuyPipelineMinutesMenuItem) {
const {
'track-action': trackAction,
'track-label': label,
'track-property': property,
} = this.data.pipeline_minutes.tracking_attrs;
this.track(trackAction, { label, property });
async onBuyCIMinutesItemClick(event) {
/* NOTE: We're not sure this event is tracked by anyone
* whether it stays will depend on the outcome of this discussion:
* https://gitlab.com/gitlab-org/gitlab/-/issues/402713#note_1343072135
*/
const {
'track-action': trackAction,
'track-label': label,
'track-property': property,
} = this.data.pipeline_minutes.tracking_attrs;
this.track(trackAction, { label, property });
// Proceed to the URL if the notification dot is not shown
if (!this.showNotificationDot) return;
event.preventDefault();
const href = this.data.pipeline_minutes?.buy_pipeline_minutes_path;
const featureId = this.data.pipeline_minutes.callout_attrs.feature_id;
const dismissEndpoint = this.data.pipeline_minutes.callout_attrs.dismiss_endpoint;
try {
// dismiss the notification dot Callout
await axios.post(dismissEndpoint, { feature_name: featureId });
} catch (error) {
logError(error);
Sentry.captureException(error);
} finally {
// visit the URL whether the callout notification is dismissed or not
visitUrl(href);
}
},
trackSignOut() {
@ -344,9 +355,7 @@ export default {
v-if="addBuyPipelineMinutesMenuItem"
ref="buyPipelineMinutesNotificationCallout"
:item="buyPipelineMinutesItem"
v-bind="buyPipelineMinutesCalloutData"
data-testid="buy-pipeline-minutes-item"
@action="trackBuyCIMins"
>
<template #list-item>
<span class="gl-flex gl-flex-col">

View File

@ -10,26 +10,18 @@ export default {
...mapState(useAccessTokens, ['token']),
formInputGroupProps() {
return {
'data-testid': this.$options.inputId,
id: this.$options.inputId,
name: this.$options.inputId,
'data-testid': 'created-access-token-field',
};
},
},
methods: {
...mapActions(useAccessTokens, ['setToken']),
},
inputId: 'access-token-field',
};
</script>
<template>
<gl-alert
data-testid="new-access-token"
variant="success"
class="gl-mb-5"
@dismiss="setToken(null)"
>
<gl-alert variant="success" class="gl-mb-5" @dismiss="setToken(null)">
<input-copy-toggle-visibility
:copy-button-title="s__('AccessTokens|Copy token')"
:label="s__('AccessTokens|Your token')"

View File

@ -92,6 +92,9 @@ export default {
groupAttrs: {
class: 'gl-form-input-xl',
},
inputAttrs: {
'data-testid': 'access-token-name-field',
},
},
description: {
label: s__('AccessTokens|Description'),
@ -144,6 +147,7 @@ export default {
:state="validation.state"
:value="value"
:target="null"
data-testid="expiry-date-field"
@input="input"
@clear="clearDatepicker"
/>
@ -170,6 +174,7 @@ export default {
:key="scope.value"
:value="scope.value"
:state="validation.state"
:data-testid="`${scope.value}-checkbox`"
>
{{ scope.value }}
<template #help>{{ scope.text }}</template>
@ -179,7 +184,13 @@ export default {
</gl-form-fields>
<div class="gl-flex gl-gap-3">
<gl-button variant="confirm" type="submit" class="js-no-auto-disable" :loading="busy">
<gl-button
variant="confirm"
type="submit"
class="js-no-auto-disable"
:loading="busy"
data-testid="create-token-button"
>
{{ s__('AccessTokens|Create token') }}
</gl-button>
<gl-button variant="default" type="reset">

View File

@ -21,8 +21,9 @@
.upload-dropzone-card {
@apply gl-transition-[background,border];
stroke: $gl-border-color-default;
@apply gl-text-default;
@apply gl-border-0;
@apply gl-rounded-base;
&:hover,
&:focus,

View File

@ -4,6 +4,7 @@
$tabs-holder-z-index: 250;
$comparison-empty-state-height: 62px;
$merge-request-sticky-header-height: 45px;
.apply-suggestions-input-min-width {
@include media-breakpoint-up(lg) {
@ -167,13 +168,13 @@ $comparison-empty-state-height: 62px;
z-index: $tabs-holder-z-index;
&:has(.detail-page-description)::after {
height: calc(45px + 26px); // Height of the 2 sticky bars combined
height: calc(#{$merge-request-sticky-header-height} + 26px); // Height of the 2 sticky bars combined
}
&::after {
content: '';
top: $calc-application-header-height;
height: 45px;
height: $merge-request-sticky-header-height;
@include translucent-glass-background;
@apply gl-border-b gl-fixed gl-left-0 gl-right-0 gl-z-0 gl-hidden;
}
@ -186,7 +187,7 @@ $comparison-empty-state-height: 62px;
.merge-request-tabs {
@apply gl-h-auto;
}
.nav-links li a {
@apply gl-py-4;
}

View File

@ -1,11 +1,10 @@
@use 'components/rapid_diffs/constants';
@use 'page_bundles/merge_request' as mr;
@import 'mixins_and_variables_and_functions';
@import 'components/rapid_diffs';
$mr-tabs-height: $grid-size * 6;
.rd-app {
--rd-app-sticky-top: calc(#{$calc-application-header-height} + #{$mr-tabs-height});
--rd-app-sticky-top: calc(#{$calc-application-header-height} + #{mr.$merge-request-sticky-header-height});
// MR tabs are hidden on small breakpoint
@include media-breakpoint-down(sm) {

View File

@ -11,7 +11,6 @@ module SearchHelper
:snippets,
:sort,
:force_search_results,
:project_ids,
:type
].freeze

View File

@ -9,9 +9,9 @@ module Search
attr_accessor :project, :current_user, :params
def initialize(user, project_or_projects, params)
def initialize(user, project, params)
@current_user = user
@project = project_or_projects
@project = project
@params = params.dup
end

View File

@ -29,10 +29,6 @@ class SearchService
end
strong_memoize_attr :group
def projects
# overridden in EE
end
def search_type_errors
# overridden in EE
end

View File

@ -3,6 +3,6 @@ migration_job_name: BackfillArchivedAndTraversalIdsToVulnerabilityStatistics
description: Backfill project.archived and project.namespace.traversal_ids values to the denormalized columns of the same name on vulnerability_statistics
feature_category: vulnerability_management
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177993
milestone: '18.2'
queued_migration_version: 20250620051921
milestone: '17.11'
queued_migration_version: 20250404035239
finalized_by: 20250422130050

View File

@ -4,25 +4,11 @@ class RequeueBackfillArchivedAndTraversalIdsToVulnerabilityStatisticsAgain < Git
milestone '18.2'
restrict_gitlab_migration gitlab_schema: :gitlab_sec
MIGRATION = "BackfillArchivedAndTraversalIdsToVulnerabilityStatistics"
DELAY_INTERVAL = 2.minutes
BATCH_SIZE = 1000
SUB_BATCH_SIZE = 100
def up
delete_batched_background_migration(MIGRATION, :vulnerability_statistics, :id, [])
queue_batched_background_migration(
MIGRATION,
:vulnerability_statistics,
:id,
job_interval: DELAY_INTERVAL,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
# no-op
end
def down
delete_batched_background_migration(MIGRATION, :vulnerability_statistics, :id, [])
# no-op
end
end

View File

@ -15,12 +15,12 @@ title: GitLab Dedicated users and notifications
## Add Switchboard users
Administrators can add two types of Switchboard users to their GitLab Dedicated instance:
Administrators can add two types of Switchboard users to manage and view their GitLab Dedicated instance:
- **Read only**: Users can only view instance data.
- **Admin**: Users can edit the instance configuration and manage users.
To add a new user to your GitLab Dedicated instance:
To add a new user to Switchboard for your GitLab Dedicated instance:
1. Sign in to [Switchboard](https://console.gitlab-dedicated.com/).
1. From the top of the page, select **Users**.
@ -30,6 +30,8 @@ To add a new user to your GitLab Dedicated instance:
An invitation to use Switchboard is sent to the user.
There is no direct link between the users in Switchboard and the users in the GitLab Dedicated instance.
### Manage notification preferences
You can specify whether you want to receive email notifications from Switchboard. You will only receive notifications after you:

View File

@ -54,7 +54,8 @@ GET /projects/:id/protected_environments
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/_index.md#namespaced-paths). |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_environments/"
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/5/protected_environments/"
```
Example response:
@ -92,7 +93,8 @@ GET /projects/:id/protected_environments/:name
| `name` | string | yes | The name of the protected environment |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_environments/production"
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/5/protected_environments/production"
```
Example response:
@ -136,10 +138,11 @@ Elements in the `deploy_access_levels` and `approval_rules` array should be one
Each user must have access to the project and each group must [have this project shared](../user/project/members/sharing_projects_groups.md).
```shell
curl --header 'Content-Type: application/json' --request POST \
curl --header 'Content-Type: application/json' \
--request POST \
--data '{"name": "production", "deploy_access_levels": [{"group_id": 9899826}], "approval_rules": [{"group_id": 134}, {"group_id": 135, "required_approvals": 2}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/projects/22034114/protected_environments"
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments"
```
Example response:
@ -218,10 +221,11 @@ To delete:
### Example: Create a `deploy_access_level` record
```shell
curl --header 'Content-Type: application/json' --request PUT \
curl --header 'Content-Type: application/json' \
--request PUT \
--data '{"deploy_access_levels": [{"group_id": 9899829, access_level: 40}]' \
--header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
```
Example response:
@ -246,9 +250,11 @@ Example response:
### Example: Update a `deploy_access_level` record
```shell
curl --header 'Content-Type: application/json' --request PUT \
curl --header 'Content-Type: application/json' \
--request PUT \
--data '{"deploy_access_levels": [{"id": 12, "group_id": 22034120}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
--header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
```
```json
@ -271,9 +277,11 @@ curl --header 'Content-Type: application/json' --request PUT \
### Example: Delete a `deploy_access_level` record
```shell
curl --header 'Content-Type: application/json' --request PUT \
curl --header 'Content-Type: application/json' \
--request PUT \
--data '{"deploy_access_levels": [{"id": 12, "_destroy": true}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
--header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
```
Example response:
@ -289,10 +297,11 @@ Example response:
### Example: Create an `approval_rule` record
```shell
curl --header 'Content-Type: application/json' --request PUT \
curl --header 'Content-Type: application/json' \
--request PUT \
--data '{"approval_rules": [{"group_id": 134, "required_approvals": 1}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
```
Example response:
@ -317,9 +326,11 @@ Example response:
### Example: Update an `approval_rule` record
```shell
curl --header 'Content-Type: application/json' --request PUT \
curl --header 'Content-Type: application/json' \
--request PUT \
--data '{"approval_rules": [{"id": 38, "group_id": 135, "required_approvals": 2}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
--header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
```
```json
@ -342,9 +353,11 @@ curl --header 'Content-Type: application/json' --request PUT \
### Example: Delete an `approval_rule` record
```shell
curl --header 'Content-Type: application/json' --request PUT \
curl --header 'Content-Type: application/json' \
--request PUT \
--data '{"approval_rules": [{"id": 38, "_destroy": true}]}' \
--header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
--header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/22034114/protected_environments/production"
```
Example response:
@ -370,5 +383,7 @@ DELETE /projects/:id/protected_environments/:name
| `name` | string | yes | The name of the protected environment. |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_environments/staging"
curl --request DELETE \
--header "PRIVATE-TOKEN: <your_access_token>" \
--url "https://gitlab.example.com/api/v4/projects/5/protected_environments/staging"
```

View File

@ -311,6 +311,27 @@ You cannot use this token to access any other data. Anyone who has
your token can create issues and merge requests as if they were
you. If you think your token has leaked, reset the token immediately.
### Workspace token
{{< history >}}
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/194097) in GitLab 18.2.
{{< /history >}}
Each [workspace](../../user/workspace/_index.md) has an internal, automatically managed token that
does not expire. It allows HTTP and SSH communication with a workspace. It exists whenever a workspace
is requested to be in the **running** state, and is automatically injected and used by the workspace.
Starting a stopped workspace creates a new workspace token.
Restarting a running workspace deletes the existing token and creates a new token.
You cannot directly view or manage this internal token. You cannot use this token to access any other data.
To revoke a workspace token,
[**stop** or **terminate** the workspace](../../user/workspace/_index.md#manage-workspaces-from-a-project).
The token is deleted immediately.
## Available scopes
This table shows default scopes per token. For some tokens, you can limit scopes further when you create the token.
@ -355,6 +376,7 @@ The following table shows the prefixes for each type of token.
| Feed token | `glft-` |
| Incoming mail token | `glimt-` |
| GitLab agent for Kubernetes token | `glagent-` |
| Workspace token | `glwt-` (Added in GitLab 18.2) |
| GitLab session cookies | `_gitlab_session=` |
| SCIM Tokens | `glsoat-` <br /> &bull; ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435096) in GitLab 16.8 behind a feature flag named `prefix_scim_tokens`. Disabled by default.) <br > &bull; ([Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/435423) in GitLab 16.9. Feature flag `prefix_scim_tokens` removed.) |
| Feature Flags Client token | `glffct-` |

View File

@ -108,103 +108,125 @@ Group permissions for [CI/CD](../ci/_index.md) features including runners, varia
Group permissions for [compliance](compliance/_index.md) features including compliance center, audit events, compliance frameworks, and licenses.
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| View [audit events](compliance/audit_events.md) | | | | ✓ | ✓ | ✓ | Users can view only events based on their individual actions. For more details, see the [prerequisites](compliance/audit_events.md#prerequisites). |
| View licenses in the [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ | |
| View the [compliance center](compliance/compliance_center/_index.md) | | | | | | ✓ | |
| Manage [compliance frameworks](compliance/compliance_frameworks/_index.md) | | | | | | ✓ | |
| Assign [compliance frameworks](compliance/compliance_frameworks/_index.md) to projects | | | | | | ✓ | |
| Manage [audit streams](compliance/audit_event_streaming.md) | | | | | | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| -------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View [audit events](compliance/audit_events.md) <sup>1</sup> | | | | ✓ | ✓ | ✓ |
| View licenses in the [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ |
| View the [compliance center](compliance/compliance_center/_index.md) | | | | | | ✓ |
| Manage [compliance frameworks](compliance/compliance_frameworks/_index.md) | | | | | | ✓ |
| Assign [compliance frameworks](compliance/compliance_frameworks/_index.md) to projects | | | | | | ✓ |
| Manage [audit streams](compliance/audit_event_streaming.md) | | | | | | ✓ |
**Footnotes**
1. Users can view only events based on their individual actions. For more details, see the [prerequisites](compliance/audit_events.md#prerequisites).
### GitLab Duo group permissions
Group permissions for [GitLab Duo](gitlab_duo/_index.md):
| Action | Non-member | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| --------------------------------------------------------------------------------------------------------- | :--------: | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| Use Duo features | | | | ✓ | ✓ | ✓ | ✓ | Requirements differ depending on if the user has GitLab Duo Core, Pro, or Enterprise. <sup>1</sup> |
| Configure [Duo feature availability](gitlab_duo/turn_on_off.md#for-a-group-or-subgroup) | | | | | | ✓ | ✓ | |
| Configure [GitLab Duo Self Hosted](../administration/gitlab_duo_self_hosted/configure_duo_features.md) | | | | | | | ✓ | |
| Enable [beta and experimental features](gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features) | | | | | | | ✓ | |
| Purchase [Duo seats](../subscriptions/subscription-add-ons.md#purchase-additional-gitlab-duo-seats) | | | | | | | ✓ | |
| Action | Non-member | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| --------------------------------------------------------------------------------------------------------- | :--------: | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| Use Duo features <sup>1</sup> | | | | ✓ | ✓ | ✓ | ✓ |
| Configure [Duo feature availability](gitlab_duo/turn_on_off.md#for-a-group-or-subgroup) | | | | | | ✓ | ✓ |
| Configure [GitLab Duo Self Hosted](../administration/gitlab_duo_self_hosted/configure_duo_features.md) | | | | | | | ✓ |
| Enable [beta and experimental features](gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features) | | | | | | | ✓ |
| Purchase [Duo seats](../subscriptions/subscription-add-ons.md#purchase-additional-gitlab-duo-seats) | | | | | | | ✓ |
**Footnotes**
1. If the user has GitLab Duo Pro or Enterprise, the
[user must be assigned a seat to gain access to that Duo add-on](../subscriptions/subscription-add-ons.md#assign-gitlab-duo-seats). If the user has GitLab Duo Core, there are
no other requirements.
[user must be assigned a seat to gain access to that Duo add-on](../subscriptions/subscription-add-ons.md#assign-gitlab-duo-seats).
If the user has GitLab Duo Core, there are no other requirements.
### Groups group permissions
Group permissions for [group features](group/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
|---------------------------------------------------------------------------------------------|:-----:|:-------:|:--------:|:---------:|:----------:|:-----:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) projects in group | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| View group [audit events](compliance/audit_events.md) | | | | ✓ | ✓ | ✓ | Developers and Maintainers can only view events based on their individual actions. For more details, see the [prerequisites](compliance/audit_events.md#prerequisites). |
| Create project in group | | | | ✓ | ✓ | ✓ | Developers, Maintainers and Owners: Only if the project creation role is set [for the instance](../administration/settings/visibility_and_access_controls.md#define-which-roles-can-create-projects) or [for the group](group/_index.md#specify-who-can-add-projects-to-a-group).<br><br>Developers: Developers can push commits to the default branch of a new project only if the [default branch protection](group/manage.md#change-the-default-branch-protection-of-a-group) is set to "Partially protected" or "Not protected". |
| Create subgroup | | | | | ✓ | ✓ | Maintainers: Only if users with the Maintainer role [can create subgroups](group/subgroups/_index.md#change-who-can-create-subgroups). |
| Change custom settings for [project integrations](project/integrations/_index.md) | | | | | | ✓ | |
| Edit [epic](group/epics/_index.md) comments (posted by any user) | | ✓ | | | ✓ | ✓ | |
| Fork project into a group | | | | | ✓ | ✓ | |
| View [Billing](../subscriptions/manage_subscription.md#view-subscription) | | | | | | ✓ | Does not apply to subgroups |
| View group [Usage Quotas](storage_usage_quotas.md) page | | | | | | ✓ | Does not apply to subgroups |
| [Migrate group](group/import/_index.md) | | | | | | ✓ | |
| Delete group | | | | | | ✓ | |
| Manage [subscriptions, storage, and compute minutes](../subscriptions/gitlab_com/_index.md) | | | | | | ✓ | |
| Manage [group access tokens](group/settings/group_access_tokens.md) | | | | | | ✓ | |
| Change group visibility level | | | | | | ✓ | |
| Edit group settings | | | | | | ✓ | |
| Configure project templates | | | | | | ✓ | |
| Configure [SAML SSO](group/saml_sso/_index.md) | | | | | | ✓ | Does not apply to subgroups |
| Disable notification emails | | | | | | ✓ | |
| Import [project](project/settings/import_export.md) | | | | | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ------------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) projects in group | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View group [audit events](compliance/audit_events.md) <sup>1</sup> | | | | ✓ | ✓ | ✓ |
| Create project in group <sup>2</sup> | | | | ✓ | ✓ | ✓ |
| Create subgroup <sup>3</sup> | | | | | ✓ | ✓ |
| Change custom settings for [project integrations](project/integrations/_index.md) | | | | | | ✓ |
| Edit [epic](group/epics/_index.md) comments (posted by any user) | | ✓ | | | ✓ | ✓ |
| Fork project into a group | | | | | ✓ | ✓ |
| View [Billing](../subscriptions/manage_subscription.md#view-subscription) <sup>4</sup> | | | | | | ✓ |
| View group [Usage Quotas](storage_usage_quotas.md) page <sup>4</sup> | | | | | | ✓ |
| [Migrate group](group/import/_index.md) | | | | | | ✓ |
| Delete group | | | | | | ✓ |
| Manage [subscriptions, storage, and compute minutes](../subscriptions/gitlab_com/_index.md) | | | | | | ✓ |
| Manage [group access tokens](group/settings/group_access_tokens.md) | | | | | | ✓ |
| Change group visibility level | | | | | | ✓ |
| Edit group settings | | | | | | ✓ |
| Configure project templates | | | | | | ✓ |
| Configure [SAML SSO](group/saml_sso/_index.md) <sup>4</sup> | | | | | | ✓ |
| Disable notification emails | | | | | | ✓ |
| Import [project](project/settings/import_export.md) | | | | | ✓ | ✓ |
**Footnotes**
1. Developers and Maintainers can only view events based on their individual actions. For more
information, see the [prerequisites](compliance/audit_events.md#prerequisites).
1. Developers, Maintainers and Owners: Only if the project creation role is set
[for the instance](../administration/settings/visibility_and_access_controls.md#define-which-roles-can-create-projects)
or [for the group](group/_index.md#specify-who-can-add-projects-to-a-group).
<br>Developers: Developers can push commits to the default branch of a new project only
if the [default branch protection](group/manage.md#change-the-default-branch-protection-of-a-group)
is set to "Partially protected" or "Not protected".
1. Maintainers: Only if users with the Maintainer role [can create subgroups](group/subgroups/_index.md#change-who-can-create-subgroups).
1. Does not apply to subgroups.
### Project planning group permissions
Group permissions for project planning features including iterations, milestones, and labels:
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ------------------------------------------------------------------------------------------ | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View epic | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) epics <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create epic | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Edit epic, including metadata, item locking, and resolving threads | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Delete epic | | ✓ | | | | ✓ |
| Manage [epic boards](group/epics/epic_boards.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add issue to an [epic](group/epics/_index.md) <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add/remove [child epics](group/epics/manage_epics.md#multi-level-child-epics) <sup>3</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ----------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| Manage group labels | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage group milestones | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage iterations | | ✓ | ✓ | ✓ | ✓ | ✓ |
**Footnotes**
Group permissions for [epics](group/epics/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
|-------------------------------------------------------------------------------|:-----:|:-------:|:--------:|:---------:|:----------:|:-----:|-------------------------------------------------------------------------------------------------------------------|
| View epic | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) epics | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | You must have permission to [view the epic](group/epics/manage_epics.md#who-can-view-an-epic). |
| Create epic | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Edit epic, including metadata, item locking, and resolving threads | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Delete epic | | ✓ | | | | ✓ | |
| Manage [epic boards](group/epics/epic_boards.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Add issue to an [epic](group/epics/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | You must have permission to [view the epic](group/epics/manage_epics.md#who-can-view-an-epic) and edit the issue. |
| Add/remove [child epics](group/epics/manage_epics.md#multi-level-child-epics) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | You must have permission to [view](group/epics/manage_epics.md#who-can-view-an-epic) the parent and child epics. |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ | |
1. You must have permission to [view the epic](group/epics/manage_epics.md#who-can-view-an-epic).
1. You must have permission to [view the epic](group/epics/manage_epics.md#who-can-view-an-epic) and edit the issue.
1. You must have permission to [view](group/epics/manage_epics.md#who-can-view-an-epic) the parent and child epics.
Group permissions for [wikis](project/wiki/group.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
|----------------------------------------|:-----:|:-------:|:--------:|:---------:|:----------:|:-----:|-----------------------------------------------------------------------------------------------------------------------------|
| View group wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Guests: In addition, if your group is public or internal, all users who can see the group can also see group wiki pages. |
| [Search](search/_index.md) group wikis | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Guests: In addition, if your group is public or internal, all users who can see the group can also search group wiki pages. |
| Create group wiki pages | | ✓ | | ✓ | ✓ | ✓ | |
| Edit group wiki pages | | ✓ | | ✓ | ✓ | ✓ | |
| Delete group wiki pages | | ✓ | | ✓ | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| --------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View group wiki <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) group wikis <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create group wiki pages | | ✓ | | ✓ | ✓ | ✓ |
| Edit group wiki pages | | ✓ | | ✓ | ✓ | ✓ |
| Delete group wiki pages | | ✓ | | ✓ | ✓ | ✓ |
### Packages and registries group permissions
**Footnotes**
1. Guests: In addition, if your group is public or internal, all users who can see the group can also see group wiki pages.
1. Guests: In addition, if your group is public or internal, all users who can see the group can also search group wiki pages.
#### Packages and registries group permissions
Group permissions for [container registry](packages/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| Pull a container registry image | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Guests can only view events based on their individual actions. |
| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Delete a container registry image | | | | ✓ | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| Pull a container registry image <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Delete a container registry image | | | | ✓ | ✓ | ✓ |
**Footnotes**
1. Guests can only view events based on their individual actions.
Group permissions for [package registry](packages/_index.md):
@ -289,23 +311,27 @@ Project permissions for [analytics](analytics/_index.md) features including valu
Project permissions for [application security](application_security/secure_your_application.md) features including dependency management, security analyzers, security policies, and vulnerability management.
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ---------------------------------------------------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| View [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ | |
| View licenses in [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ | |
| View [security dashboard](application_security/security_dashboard/_index.md) | | | | ✓ | ✓ | ✓ | |
| View [vulnerability report](application_security/vulnerability_report/_index.md) | | | | ✓ | ✓ | ✓ | |
| Create [vulnerability manually](application_security/vulnerability_report/_index.md#manually-add-a-vulnerability) | | | | | ✓ | ✓ | |
| Create [issue](application_security/vulnerabilities/_index.md#create-a-gitlab-issue-for-a-vulnerability) from vulnerability finding | | | | ✓ | ✓ | ✓ | |
| Create [on-demand DAST scans](application_security/dast/on-demand_scan.md) | | | | ✓ | ✓ | ✓ | |
| Run [on-demand DAST scans](application_security/dast/on-demand_scan.md) | | | | ✓ | ✓ | ✓ | |
| Create [individual security policies](application_security/policies/_index.md) | | | | ✓ | ✓ | ✓ | |
| Change [individual security policies](application_security/policies/_index.md) | | | | ✓ | ✓ | ✓ | |
| Delete [individual security policies](application_security/policies/_index.md) | | | | ✓ | ✓ | ✓ | |
| Create [CVE ID request](application_security/cve_id_request.md) | | | | | ✓ | ✓ | |
| Change vulnerability status | | | | | ✓ | ✓ | The `admin_vulnerability` permission was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/412693) from the Developer role in GitLab 17.0. |
| Create or assign [security policy project](application_security/policies/_index.md) | | | | | | ✓ | |
| Manage [security configurations](application_security/detect/security_configuration.md) | | | | | | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ----------------------------------------------------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ |
| View licenses in [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ |
| View [security dashboard](application_security/security_dashboard/_index.md) | | | | ✓ | ✓ | ✓ |
| View [vulnerability report](application_security/vulnerability_report/_index.md) | | | | ✓ | ✓ | ✓ |
| Create [vulnerability manually](application_security/vulnerability_report/_index.md#manually-add-a-vulnerability) | | | | | ✓ | ✓ |
| Create [issue](application_security/vulnerabilities/_index.md#create-a-gitlab-issue-for-a-vulnerability) from vulnerability finding | | | | ✓ | ✓ | ✓ |
| Create [on-demand DAST scans](application_security/dast/on-demand_scan.md) | | | | ✓ | ✓ | ✓ |
| Run [on-demand DAST scans](application_security/dast/on-demand_scan.md) | | | | ✓ | ✓ | ✓ |
| Create [individual security policies](application_security/policies/_index.md) | | | | ✓ | ✓ | ✓ |
| Change [individual security policies](application_security/policies/_index.md) | | | | ✓ | ✓ | ✓ |
| Delete [individual security policies](application_security/policies/_index.md) | | | | ✓ | ✓ | ✓ |
| Create [CVE ID request](application_security/cve_id_request.md) | | | | | ✓ | ✓ |
| Change vulnerability status <sup>1</sup> | | | | | ✓ | ✓ |
| Create or assign [security policy project](application_security/policies/_index.md) | | | | | | ✓ |
| Manage [security configurations](application_security/detect/security_configuration.md) | | | | | | ✓ |
**Footnotes**
1. The `admin_vulnerability` permission was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/412693) from the Developer role in GitLab 17.0.
### CI/CD
@ -318,86 +344,132 @@ Project permissions for [application security](application_security/secure_your_
Project Owners can perform any listed action, and can delete pipelines:
| Action | Non-member | Guest | Planner | Reporter | Developer | Maintainer | Notes |
| ------------------------------------------------------------------------------------------------------------------------------ | :--------: | :---: | :-----: | :------: | :-------: | :--------: | ----- |
| View existing artifacts | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members and guests: Only if the project is public. |
| View list of jobs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members: Only if the project is public and **Public pipelines** is enabled in **Project Settings > CI/CD**.<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD**. |
| View artifacts | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members: Only if the project is public, **Public pipelines** is enabled in **Project Settings > CI/CD**, and [`artifacts:public: false`](../ci/yaml/_index.md#artifactspublic) is not set on the job.<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD** and `artifacts:public: false` is not set on the job.<br>Reporters: Only if `artifacts:public: false` is not set on the job. |
| Download artifacts | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members: Only if the project is public, **Public pipelines** is enabled in **Project Settings > CI/CD**, and [`artifacts:public: false`](../ci/yaml/_index.md#artifactspublic) is not set on the job.<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD** and `artifacts:public: false` is not set on the job.<br>Reporters: Only if `artifacts:public: false` is not set on the job. |
| View [environments](../ci/environments/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members and guests: Only if the project is public. |
| View job logs and job details page | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members: Only if the project is public and **Public pipelines** is enabled in **Project Settings > CI/CD**.<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD**. |
| View pipelines and pipeline details pages | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members: Only if the project is public and **Public pipelines** is enabled in **Project Settings > CI/CD**.<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD**. |
| View pipelines tab in MR | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members and guests: Only if the project is public. |
| View [vulnerabilities in a pipeline](application_security/detect/security_scanning_results.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD**. |
| Run deployment job for a protected environment | | | | ✓ | ✓ | ✓ | Reporters: Only if the user is [part of a group with access to the protected environment](../ci/environments/protected_environments.md#deployment-only-access-to-protected-environments).<br>Developers and maintainers: Only if the user is [allowed to deploy to the protected branch](../ci/environments/protected_environments.md#protecting-environments). |
| View [agents for Kubernetes](clusters/agent/_index.md) | | | | | ✓ | ✓ | |
| View project [Secure Files](../api/secure_files.md) | | | | | ✓ | ✓ | |
| Download project [Secure Files](../api/secure_files.md) | | | | | ✓ | ✓ | |
| View a job with [debug logging](../ci/variables/variables_troubleshooting.md#enable-debug-logging) | | | | | ✓ | ✓ | |
| Create [environments](../ci/environments/_index.md) | | | | | ✓ | ✓ | |
| Delete [environments](../ci/environments/_index.md) | | | | | ✓ | ✓ | |
| Stop [environments](../ci/environments/_index.md) | | | | | ✓ | ✓ | |
| Run CI/CD pipeline | | | | | ✓ | ✓ | |
| Run CI/CD pipeline for a protected branch | | | | | ✓ | ✓ | Developers and maintainers: Only if the user is [allowed to merge or push to the protected branch](../ci/pipelines/_index.md#pipeline-security-on-protected-branches). |
| Run CI/CD job | | | | | ✓ | ✓ | |
| Delete job logs or job artifacts | | | | | ✓ | ✓ | Developers: Only if the job was triggered by the user and runs for a non-protected branch. |
| Enable [review apps](../ci/review_apps/_index.md) | | | | | ✓ | ✓ | |
| Cancel jobs | | | | | ✓ | ✓ | Cancellation permissions can be [restricted in the pipeline settings](../ci/pipelines/settings.md#restrict-roles-that-can-cancel-pipelines-or-jobs). |
| Retry jobs | | | | | ✓ | ✓ | |
| Read [Terraform](infrastructure/_index.md) state | | | | | ✓ | ✓ | |
| Run [interactive web terminals](../ci/interactive_web_terminal/_index.md) | | | | | ✓ | ✓ | |
| Use pipeline editor | | | | | ✓ | ✓ | |
| Manage [agents for Kubernetes](clusters/agent/_index.md) | | | | | | ✓ | |
| Manage CI/CD settings | | | | | | ✓ | |
| Manage job triggers | | | | | | ✓ | |
| Manage project CI/CD variables | | | | | | ✓ | |
| Manage project protected environments | | | | | | ✓ | |
| Manage project [Secure Files](../api/secure_files.md) | | | | | | ✓ | |
| Manage [Terraform](infrastructure/_index.md) state | | | | | | ✓ | |
| Add project runners to project | | | | | | ✓ | |
| Clear runner caches manually | | | | | | ✓ | |
| Enable instance runners in project | | | | | | ✓ | |
| Action | Non-member | Guest | Planner | Reporter | Developer | Maintainer |
| ----------------------------------------------------------------------------------------------------------- | :--------: | :---: | :-----: | :------: | :-------: | :--------: |
| View existing artifacts <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View list of jobs <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View artifacts <sup>3</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Download artifacts <sup>3</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [environments](../ci/environments/_index.md) <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View job logs and job details page <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View pipelines and pipeline details pages <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View pipelines tab in MR <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [vulnerabilities in a pipeline](application_security/detect/security_scanning_results.md) <sup>4</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Run deployment job for a protected environment <sup>5</sup> | | | | ✓ | ✓ | ✓ |
| View [agents for Kubernetes](clusters/agent/_index.md) | | | | | ✓ | ✓ |
| View project [Secure Files](../api/secure_files.md) | | | | | ✓ | ✓ |
| Download project [Secure Files](../api/secure_files.md) | | | | | ✓ | ✓ |
| View a job with [debug logging](../ci/variables/variables_troubleshooting.md#enable-debug-logging) | | | | | ✓ | ✓ |
| Create [environments](../ci/environments/_index.md) | | | | | ✓ | ✓ |
| Delete [environments](../ci/environments/_index.md) | | | | | ✓ | ✓ |
| Stop [environments](../ci/environments/_index.md) | | | | | ✓ | ✓ |
| Run CI/CD pipeline | | | | | ✓ | ✓ |
| Run CI/CD pipeline for a protected branch <sup>6</sup> | | | | | ✓ | ✓ |
| Run CI/CD job | | | | | ✓ | ✓ |
| Delete job logs or job artifacts <sup>7</sup> | | | | | ✓ | ✓ |
| Enable [review apps](../ci/review_apps/_index.md) | | | | | ✓ | ✓ |
| Cancel jobs <sup>8</sup> | | | | | ✓ | ✓ |
| Retry jobs | | | | | ✓ | ✓ |
| Read [Terraform](infrastructure/_index.md) state | | | | | ✓ | ✓ |
| Run [interactive web terminals](../ci/interactive_web_terminal/_index.md) | | | | | ✓ | ✓ |
| Use pipeline editor | | | | | ✓ | ✓ |
| Manage [agents for Kubernetes](clusters/agent/_index.md) | | | | | | ✓ |
| Manage CI/CD settings | | | | | | ✓ |
| Manage job triggers | | | | | | ✓ |
| Manage project CI/CD variables | | | | | | ✓ |
| Manage project protected environments | | | | | | ✓ |
| Manage project [Secure Files](../api/secure_files.md) | | | | | | ✓ |
| Manage [Terraform](infrastructure/_index.md) state | | | | | | ✓ |
| Add project runners to project | | | | | | ✓ |
| Clear runner caches manually | | | | | | ✓ |
| Enable instance runners in project | | | | | | ✓ |
**Footnotes**
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
<!-- markdownlint-disable MD029 -->
1. Non-members and guests: Only if the project is public.
2. Non-members: Only if the project is public and **Public pipelines** is enabled in **Project Settings > CI/CD**.
<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD**.
3. Non-members: Only if the project is public, **Public pipelines** is enabled in **Project Settings > CI/CD**,
and [`artifacts:public: false`](../ci/yaml/_index.md#artifactspublic) is not set on the job.
<br>Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD** and
`artifacts:public: false` is not set on the job.<br>Reporters: Only if `artifacts:public: false`
is not set on the job.
4. Guests: Only if **Public pipelines** is enabled in **Project Settings > CI/CD**.
5. Reporters: Only if the user is [part of a group with access to the protected environment](../ci/environments/protected_environments.md#deployment-only-access-to-protected-environments).
<br>Developers and maintainers: Only if the user is [allowed to deploy to the protected branch](../ci/environments/protected_environments.md#protecting-environments).
6. Developers and maintainers: Only if the user is [allowed to merge or push to the protected branch](../ci/pipelines/_index.md#pipeline-security-on-protected-branches).
7. Developers: Only if the job was triggered by the user and runs for a non-protected branch.
8. Cancellation permissions can be [restricted in the pipeline settings](../ci/pipelines/settings.md#restrict-roles-that-can-cancel-pipelines-or-jobs).
<!-- markdownlint-enable MD029 -->
This table shows granted privileges for jobs triggered by specific roles.
Project Owners can do any listed action, but no users can push source and LFS together.
Guest users and members with the Reporter role cannot do any of these actions.
| Action | Developer | Maintainer | Notes |
| -------------------------------------------- | :-------: | :--------: | ----- |
| Clone source and LFS from current project | ✓ | ✓ | |
| Clone source and LFS from public projects | ✓ | ✓ | |
| Clone source and LFS from internal projects | ✓ | ✓ | Developers and Maintainers: Only if the triggering user is not an external user. |
| Clone source and LFS from private projects | ✓ | ✓ | Only if the triggering user is a member of the project. See also [Usage of private Docker images with `if-not-present` pull policy](https://docs.gitlab.com/runner/security/#usage-of-private-docker-images-with-if-not-present-pull-policy). |
| Pull container images from current project | ✓ | ✓ | |
| Pull container images from public projects | ✓ | ✓ | |
| Pull container images from internal projects | ✓ | ✓ | Developers and Maintainers: Only if the triggering user is not an external user. |
| Pull container images from private projects | ✓ | ✓ | Only if the triggering user is a member of the project. See also [Usage of private Docker images with `if-not-present` pull policy](https://docs.gitlab.com/runner/security/#usage-of-private-docker-images-with-if-not-present-pull-policy). |
| Push container images to current project | ✓ | ✓ | You cannot push container images to other projects. |
| Action | Developer | Maintainer |
| --------------------------------------------------------- | :-------: | :--------: |
| Clone source and LFS from current project | ✓ | ✓ |
| Clone source and LFS from public projects | ✓ | ✓ |
| Clone source and LFS from internal projects <sup>1</sup> | ✓ | ✓ |
| Clone source and LFS from private projects <sup>2</sup> | ✓ | ✓ |
| Pull container images from current project | ✓ | ✓ |
| Pull container images from public projects | ✓ | ✓ |
| Pull container images from internal projects <sup>1</sup> | ✓ | ✓ |
| Pull container images from private projects <sup>2</sup> | ✓ | ✓ |
| Push container images to current project <sup>3</sup> | ✓ | ✓ |
**Footnotes**
1. Developers and Maintainers: Only if the triggering user is not an external user.
1. Only if the triggering user is a member of the project. See also [Usage of private Docker images with `if-not-present` pull policy](https://docs.gitlab.com/runner/security/#usage-of-private-docker-images-with-if-not-present-pull-policy).
1. You cannot push container images to other projects.
### Compliance
Project permissions for [compliance](compliance/_index.md) features including compliance center, audit events, compliance frameworks, and licenses.
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ------------------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| View [allowed and denied licenses in MR](compliance/license_scanning_of_cyclonedx_files/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | On GitLab Self-Managed, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](../administration/external_users.md) must be have at least the Reporter role, even if the project is internal. Users with the Guest role on GitLab.com are able to perform this action only on public projects because internal visibility is not available. |
| View [audit events](compliance/audit_events.md) | | | | ✓ | ✓ | ✓ | Users can only view events based on their individual actions. For more details, see the [prerequisites](compliance/audit_events.md#prerequisites). |
| View licenses in [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ | |
| Manage [audit streams](compliance/audit_event_streaming.md) | | | | | | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| --------------------------------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View [allowed and denied licenses in MR](compliance/license_scanning_of_cyclonedx_files/_index.md) <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [audit events](compliance/audit_events.md) <sup>2</sup> | | | | ✓ | ✓ | ✓ |
| View licenses in [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ |
| Manage [audit streams](compliance/audit_event_streaming.md) | | | | | | ✓ |
**Footnotes**
1. On GitLab Self-Managed, users with the Guest role are able to perform this action only on public
and internal projects (not on private projects). [External users](../administration/external_users.md)
must have at least the Reporter role, even if the project is internal. Users with the Guest
role on GitLab.com are able to perform this action only on public projects because internal
visibility is not available.
1. Users can only view events based on their individual actions. For more details, see the [prerequisites](compliance/audit_events.md#prerequisites).
### Machine learning model registry and experiment
Project permissions for [model registry](project/ml/model_registry/_index.md) and [model experiments](project/ml/experiment_tracking/_index.md).
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ----------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | :---: |
| View [models and versions](project/ml/model_registry/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members can only view models and versions in public projects with the **Everyone with access** visibility level. Non-members can't view internal projects, even if they're logged in. |
| View [model experiments](project/ml/experiment_tracking/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Non-members can only view model experiments in public projects with the **Everyone with access** visibility level. Non-members can't view internal projects, even if they're logged in. |
| Create models, versions, and artifacts | | | | ✓ | ✓ | ✓ | You can also upload and download artifacts with the package registry API, which uses it's own set of permissions. |
| Edit & delete models, versions, and artifacts | | | | ✓ | ✓ | ✓ | |
| Create experiments and candidates | | | | ✓ | ✓ | ✓ | |
| Edit & delete experiments and candidates | | | | ✓ | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View [models and versions](project/ml/model_registry/_index.md) <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [model experiments](project/ml/experiment_tracking/_index.md) <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create models, versions, and artifacts <sup>3</sup> | | | | ✓ | ✓ | ✓ |
| Edit & delete models, versions, and artifacts | | | | ✓ | ✓ | ✓ |
| Create experiments and candidates | | | | ✓ | ✓ | ✓ |
| Edit & delete experiments and candidates | | | | ✓ | ✓ | ✓ |
**Footnotes**
1. Non-members can only view models and versions in public projects with the **Everyone with access**
visibility level. Non-members can't view internal projects, even if they're logged in.
1. Non-members can only view model experiments in public projects with the **Everyone with access**
visibility level. Non-members can't view internal projects, even if they're logged in.
1. You can also upload and download artifacts with the package registry API, which uses
a different set of permissions.
### Monitoring
@ -425,70 +497,85 @@ Project permissions for monitoring including [error tracking](../operations/erro
Project permissions for [issues](project/issues/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
|-----------------------------------------------------------------------|:-----:|:-------:|:--------:|:---------:|:----------:|:-----:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| View issues | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) issues and comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Create issues | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| View [confidential issues](project/issues/confidential_issues.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) confidential issues and comments | | | ✓ | ✓ | ✓ | ✓ | |
| Edit issues, including metadata, item locking, and resolving threads | | ✓ | ✓ | ✓ | ✓ | ✓ | Metadata includes labels, assignees, milestones, epics, weight, confidentiality, time tracking, and more.<br /><br />Guest users can only set metadata when creating an issue. They cannot change the metadata on existing issues. Guest users can modify the title and description of issues that they authored or are assigned to. |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Close and reopen issues | | ✓ | ✓ | ✓ | ✓ | ✓ | Guest users can close and reopen issues that they authored or are assigned to. |
| Manage [design management](project/issues/design_management.md) files | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Manage [issue boards](project/issue_board.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Manage [milestones](project/milestones/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) milestones | | | ✓ | ✓ | ✓ | ✓ | |
| Archive or reopen [requirements](project/requirements/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | Guest users can archive and reopen issues that they authored or are assigned to. |
| Create or edit [requirements](project/requirements/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | Guest users can modify the title and description that they authored or are assigned to. |
| Import or export [requirements](project/requirements/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Archive [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Create [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Move [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Reopen [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Import](project/issues/csv_import.md) issues from a CSV file | | ✓ | | ✓ | ✓ | ✓ | |
| [Export](project/issues/csv_export.md) issues to a CSV file | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Delete issues | | ✓ | | | | ✓ | |
| Manage [Feature flags](../operations/feature_flags.md) | | | | ✓ | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| --------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View issues | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) issues and comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create issues | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [confidential issues](project/issues/confidential_issues.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) confidential issues and comments | | | ✓ | ✓ | ✓ | ✓ |
| Edit issues, including metadata, item locking, and resolving threads <sup>1</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Close and reopen issues <sup>2</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage [design management](project/issues/design_management.md) files | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage [issue boards](project/issue_board.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage [milestones](project/milestones/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) milestones | | | ✓ | ✓ | ✓ | ✓ |
| Archive or reopen [requirements](project/requirements/_index.md) <sup>3</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create or edit [requirements](project/requirements/_index.md) <sup>4</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Import or export [requirements](project/requirements/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Archive [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Move [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Reopen [test cases](../ci/test_cases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Import](project/issues/csv_import.md) issues from a CSV file | | ✓ | | ✓ | ✓ | ✓ |
| [Export](project/issues/csv_export.md) issues to a CSV file | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Delete issues | | ✓ | | | | ✓ |
| Manage [Feature flags](../operations/feature_flags.md) | | | | ✓ | ✓ | ✓ |
**Footnotes**
1. Metadata includes labels, assignees, milestones, epics, weight, confidentiality, time tracking,
and more. Guest users can only set metadata when creating an issue. They cannot change the
metadata on existing issues. Guest users can modify the title and description of issues that
they authored or are assigned to.
1. Guest users can close and reopen issues that they authored or are assigned to.
1. Guest users can archive and reopen issues that they authored or are assigned to.
1. Guest users can modify the title and description that they authored or are assigned to.
Project permissions for [tasks](tasks.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| View tasks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) tasks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Create tasks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Edit tasks, including metadata, item locking, and resolving threads | | ✓ | ✓ | ✓ | ✓ | ✓ | Guest users can modify the title and description that they authored or are assigned to. |
| Add a linked item | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Convert to another item type | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Remove from issue | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Delete tasks | | ✓ | | | | ✓ | Users who don't have the Planner or Owner role can delete the tasks they authored. |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| -------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View tasks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) tasks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create tasks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Edit tasks, including metadata, item locking, and resolving threads <sup>1</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add a linked item | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Convert to another item type | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Remove from issue | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Delete tasks <sup>2</sup> | | ✓ | | | | ✓ |
**Footnotes**
1. Guest users can modify the title and description that they authored or are assigned to.
1. Users who don't have the Planner or Owner role can delete the tasks they authored.
Project permissions for [OKRs](okrs.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| ------------------------------------------------------------------ | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| View OKRs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) OKRs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Create OKRs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Edit OKRs, including metadata, item locking, and resolving threads | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Add a child OKR | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Add a linked item | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Convert to another item type | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Edit OKRs | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Change confidentiality in OKR | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| ------------------------------------------------------------------ | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View OKRs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) OKRs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create OKRs | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Edit OKRs, including metadata, item locking, and resolving threads | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add a child OKR | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add a linked item | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Convert to another item type | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Edit OKRs | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Change confidentiality in OKR | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Add internal note | | ✓ | ✓ | ✓ | ✓ | ✓ |
Project permissions for [wikis](project/wiki/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
|----------------------------------|:-----:|:-------:|:--------:|:---------:|:----------:|:-----:|-------|
| View wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) wikis | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Create wiki pages | | ✓ | | ✓ | ✓ | ✓ | |
| Edit wiki pages | | ✓ | | ✓ | ✓ | ✓ | |
| Delete wiki pages | | ✓ | | ✓ | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| -------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) wikis | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create wiki pages | | ✓ | | ✓ | ✓ | ✓ |
| Edit wiki pages | | ✓ | | ✓ | ✓ | ✓ |
| Delete wiki pages | | ✓ | | ✓ | ✓ | ✓ |
### Packages and registry
@ -509,59 +596,90 @@ Project permissions for [container registry](packages/_index.md):
Project permissions for [package registry](packages/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| --------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| Pull a package | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | On GitLab Self-Managed, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](../administration/external_users.md) must be given explicit access (at least the **Reporter** role) even if the project is internal. Users with the Guest role on GitLab.com are only able to perform this action on public projects because internal visibility is not available. |
| Publish a package | | | | ✓ | ✓ | ✓ | |
| Delete a package | | | | | ✓ | ✓ | |
| Delete a file associated with a package | | | | | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| --------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| Pull a package <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Publish a package | | | | ✓ | ✓ | ✓ |
| Delete a package | | | | | ✓ | ✓ |
| Delete a file associated with a package | | | | | ✓ | ✓ |
**Footnotes**
1. On GitLab Self-Managed, users with the Guest role are able to perform this action only on public
and internal projects (not on private projects). [External users](../administration/external_users.md)
must be given explicit access (at least the **Reporter** role) even if the project is internal.
Users with the Guest role on GitLab.com are only able to perform this action on public projects
because internal visibility is not available.
### Projects
Project permissions for [project features](project/organize_work_with_projects.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
|--------------------------------------------------------------------------------------|:-----:|:-------:|:--------:|:---------:|:----------:|:-----:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Download project | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | On GitLab Self-Managed, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](../administration/external_users.md) must be given explicit access (at least the **Reporter** role) even if the project is internal. Users with the Guest role on GitLab.com are only able to perform this action on public projects because internal visibility is not available. |
| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Reposition comments on images (posted by any user) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Applies only to comments on [Design Management](project/issues/design_management.md) designs. |
| View [Insights](project/insights/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| View [Requirements](project/requirements/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| View [time tracking](project/time_tracking.md) reports | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | On GitLab Self-Managed, users with the Guest role are able to perform this action only on public and internal projects (not on private projects). [External users](../administration/external_users.md) must be given explicit access (at least the **Reporter** role) even if the project is internal. Users with the Guest role on GitLab.com are only able to perform this action on public projects because internal visibility is not available. |
| View [snippets](snippets.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| [Search](search/_index.md) [snippets](snippets.md) and comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| View [project traffic statistics](../api/project_statistics.md) | | | ✓ | ✓ | ✓ | ✓ | |
| Create [snippets](snippets.md) | | | ✓ | ✓ | ✓ | ✓ | |
| View [releases](project/releases/_index.md) | | ✓ | ✓ | ✓ | ✓ | ✓ | Guest users can access GitLab [**Releases**](project/releases/_index.md) for downloading assets but are not allowed to download the source code nor see [repository information like commits and release evidence](project/releases/_index.md#view-a-release-and-download-assets). |
| Manage [releases](project/releases/_index.md) | | | | | ✓ | ✓ | If the [tag is protected](project/protected_tags.md), this depends on the access given to Developers and Maintainers. |
| Configure [webhooks](project/integrations/webhooks.md) | | | | | ✓ | ✓ | |
| Manage [project access tokens](project/settings/project_access_tokens.md) | | | | | ✓ | ✓ | For GitLab Self-Managed, project access tokens are available in all tiers. For GitLab.com, project access tokens are supported in the Premium and Ultimate tier (excluding [trial licenses](https://about.gitlab.com/free-trial/)). |
| [Export project](project/settings/import_export.md) | | | | | ✓ | ✓ | |
| Rename project | | | | | ✓ | ✓ | |
| Edit project badges | | | | | ✓ | ✓ | |
| Edit project settings | | | | | ✓ | ✓ | |
| Change [project features visibility](public_access.md) level | | | | | ✓ | ✓ | A Maintainer or Owner can't change project features visibility level if [project visibility](public_access.md) is set to private. |
| Change custom settings for [project integrations](project/integrations/_index.md) | | | | | ✓ | ✓ | |
| Edit comments (posted by any user) | | | | | ✓ | ✓ | |
| Add [deploy keys](project/deploy_keys/_index.md) | | | | | ✓ | ✓ | |
| Manage [Project Operations](../operations/_index.md) | | | | | ✓ | ✓ | |
| View [Usage Quotas](storage_usage_quotas.md) page | | | | | ✓ | ✓ | |
| Globally delete [snippets](snippets.md) | | | | | ✓ | ✓ | |
| Globally edit [snippets](snippets.md) | | | | | ✓ | ✓ | |
| Archive project | | | | | | ✓ | |
| Change project visibility level | | | | | | ✓ | |
| Delete project | | | | | | ✓ | |
| Disable notification emails | | | | | | ✓ | |
| Transfer project | | | | | | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| -------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| Download project <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Reposition comments on images (posted by any user) <sup>2</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [Insights](project/insights/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [Requirements](project/requirements/_index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [time tracking](project/time_tracking.md) reports <sup>1</sup> | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [snippets](snippets.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Search](search/_index.md) [snippets](snippets.md) and comments | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| View [project traffic statistics](../api/project_statistics.md) | | | ✓ | ✓ | ✓ | ✓ |
| Create [snippets](snippets.md) | | | ✓ | ✓ | ✓ | ✓ |
| View [releases](project/releases/_index.md) <sup>3</sup> | | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage [releases](project/releases/_index.md) <sup>4</sup> | | | | | ✓ | ✓ |
| Configure [webhooks](project/integrations/webhooks.md) | | | | | ✓ | ✓ |
| Manage [project access tokens](project/settings/project_access_tokens.md) <sup>5</sup> | | | | | ✓ | ✓ |
| [Export project](project/settings/import_export.md) | | | | | ✓ | ✓ |
| Rename project | | | | | ✓ | ✓ |
| Edit project badges | | | | | ✓ | ✓ |
| Edit project settings | | | | | ✓ | ✓ |
| Change [project features visibility](public_access.md) level <sup>6</sup> | | | | | ✓ | ✓ |
| Change custom settings for [project integrations](project/integrations/_index.md) | | | | | ✓ | ✓ |
| Edit comments (posted by any user) | | | | | ✓ | ✓ |
| Add [deploy keys](project/deploy_keys/_index.md) | | | | | ✓ | ✓ |
| Manage [Project Operations](../operations/_index.md) | | | | | ✓ | ✓ |
| View [Usage Quotas](storage_usage_quotas.md) page | | | | | ✓ | ✓ |
| Globally delete [snippets](snippets.md) | | | | | ✓ | ✓ |
| Globally edit [snippets](snippets.md) | | | | | ✓ | ✓ |
| Archive project | | | | | | ✓ |
| Change project visibility level | | | | | | ✓ |
| Delete project | | | | | | ✓ |
| Disable notification emails | | | | | | ✓ |
| Transfer project | | | | | | ✓ |
**Footnotes**
<!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix -->
<!-- markdownlint-disable MD029 -->
1. On GitLab Self-Managed, users with the Guest role are able to perform this action only on
public and internal projects (not on private projects). [External users](../administration/external_users.md)
must be given explicit access (at least the **Reporter** role) even if the project is internal.
Users with the Guest role on GitLab.com are only able to perform this action on public projects
because internal visibility is not available.
2. Applies only to comments on [Design Management](project/issues/design_management.md) designs.
3. Guest users can access GitLab [**Releases**](project/releases/_index.md) for downloading
assets but are not allowed to download the source code nor see
[repository information like commits and release evidence](project/releases/_index.md#view-a-release-and-download-assets).
4. If the [tag is protected](project/protected_tags.md), this depends on the access given to
Developers and Maintainers.
5. For GitLab Self-Managed, project access tokens are available in all tiers. For GitLab.com,
project access tokens are supported in the Premium and Ultimate tier (excluding [trial licenses](https://about.gitlab.com/free-trial/)).
6. A Maintainer or Owner can't change project features visibility level if
[project visibility](public_access.md) is set to private.
<!-- markdownlint-enable MD029 -->
Project permissions for [GitLab Pages](project/pages/_index.md):
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner | Notes |
| -------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: | ----- |
| View GitLab Pages protected by [access control](project/pages/pages_access_control.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
| Manage GitLab Pages | | | | | ✓ | ✓ | |
| Manage GitLab Pages domain and certificates | | | | | ✓ | ✓ | |
| Remove GitLab Pages | | | | | ✓ | ✓ | |
| Action | Guest | Planner | Reporter | Developer | Maintainer | Owner |
| -------------------------------------------------------------------------------------- | :---: | :-----: | :------: | :-------: | :--------: | :---: |
| View GitLab Pages protected by [access control](project/pages/pages_access_control.md) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage GitLab Pages | | | | | ✓ | ✓ |
| Manage GitLab Pages domain and certificates | | | | | ✓ | ✓ |
| Remove GitLab Pages | | | | | ✓ | ✓ |
### Repository

View File

@ -44,21 +44,9 @@ module Gitlab
end
end
# rubocop:disable CodeReuse/ActiveRecord
def users
results = super
if @project.is_a?(Array)
team_members_for_projects = User.joins(:project_authorizations).where(project_authorizations: { project_id: @project })
.allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422045')
results = results.where(id: team_members_for_projects)
else
results = results.where(id: @project.team.members)
end
results
super.id_in(@project.team.members)
end
# rubocop:enable CodeReuse/ActiveRecord
def limited_blobs_count
@limited_blobs_count ||= blobs(limit: count_limit).count

View File

@ -7067,9 +7067,6 @@ msgstr ""
msgid "An error occurred when updating the title"
msgstr ""
msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
msgstr ""
msgid "An error occurred while adding approvers"
msgstr ""
@ -14804,6 +14801,9 @@ msgstr ""
msgid "CodeSuggestions|GitLab Duo Pro"
msgstr ""
msgid "CodeSuggestions|GitLab Duo Self-Hosted"
msgstr ""
msgid "CodeSuggestions|GitLab Duo should be operational."
msgstr ""

View File

@ -14,6 +14,21 @@ module QA
include QA::Page::Component::ConfirmModal
end
base.view 'app/assets/javascripts/vue_shared/access_tokens/components/access_token.vue' do
element 'created-access-token-field'
end
base.view 'app/assets/javascripts/vue_shared/access_tokens/components/access_tokens.vue' do
element 'add-new-token-button'
end
base.view 'app/assets/javascripts/vue_shared/access_tokens/components/access_token_form.vue' do
element 'create-token-button'
element 'access-token-name-field'
element 'expiry-date-field'
element 'api-checkbox', '${scope.value}-checkbox' # rubocop:disable QA/ElementWithPattern
end
base.view 'app/assets/javascripts/access_tokens/components/expires_at_field.vue' do
element 'expiry-date-field'
end
@ -24,20 +39,13 @@ module QA
end
base.view 'app/views/shared/tokens/_scopes_form.html.haml' do
element 'api-label', '#{scope}-label' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck
element 'api-checkbox', '#{scope}-checkbox' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck
end
base.view 'app/assets/javascripts/access_tokens/components/new_access_token_app.vue' do
element 'access-token-section'
element 'created-access-token-field'
end
# rubocop:disable Layout/LineLength -- Single line is more readable
base.view 'app/assets/javascripts/vue_shared/components/input_copy_toggle_visibility/input_copy_toggle_visibility.vue' do
element 'toggle-visibility-button'
end
# rubocop:enable Layout/LineLength
base.view 'app/assets/javascripts/access_tokens/components/access_token_table_app.vue' do
element 'revoke-button'
end
@ -70,7 +78,7 @@ module QA
end
def check_api
click_element('api-label')
check_element('api-checkbox', true)
end
def click_create_token_button
@ -78,9 +86,7 @@ module QA
end
def created_access_token
within_element('access-token-section') do
find_element('created-access-token-field').value
end
find_element('created-access-token-field').value
end
def fill_expiry_date(date)
@ -94,10 +100,6 @@ module QA
fill_element('expiry-date-field', date)
end
def has_token_row_for_name?(token_name)
page.has_css?('tr', text: token_name, wait: 1.0)
end
def first_token_row_for_name(token_name)
page.find('tr', text: token_name, match: :first, wait: 1.0)
end

View File

@ -16,7 +16,6 @@ ee/spec/frontend/boards/components/board_list_spec.js
ee/spec/frontend/boards/components/board_new_issue_spec.js
ee/spec/frontend/boards/components/epics_swimlanes_spec.js
ee/spec/frontend/ci/secrets/components/secrets_breadcrumbs_spec.js
ee/spec/frontend/compliance_dashboard/components/frameworks_report/edit_framework/components/policies_section_spec.js
ee/spec/frontend/compliance_dashboard/components/frameworks_report/report_spec.js
ee/spec/frontend/dependencies/components/app_spec.js
ee/spec/frontend/dependencies/components/dependency_location_spec.js

View File

@ -1,5 +1,4 @@
import MockAdapter from 'axios-mock-adapter';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
@ -50,23 +49,6 @@ describe('PersistentUserCallout', () => {
return fixture;
}
function createFollowLinkFixture() {
const fixture = document.createElement('div');
fixture.innerHTML = `
<ul>
<li
class="container"
data-dismiss-endpoint="${dismissEndpoint}"
data-feature-id="${featureName}"
>
<a class="js-follow-link" href="/somewhere-pleasant">A Link</a>
</li>
</ul>
`;
return fixture;
}
describe('dismiss', () => {
const buttons = {};
let mockAxios;
@ -173,55 +155,6 @@ describe('PersistentUserCallout', () => {
});
});
describe('follow links', () => {
let link;
let mockAxios;
let persistentUserCallout;
useMockLocationHelper();
beforeEach(() => {
const fixture = createFollowLinkFixture();
const container = fixture.querySelector('.container');
link = fixture.querySelector('.js-follow-link');
mockAxios = new MockAdapter(axios);
persistentUserCallout = new PersistentUserCallout(container);
jest.spyOn(persistentUserCallout.container, 'remove').mockImplementation(() => {});
});
afterEach(() => {
mockAxios.restore();
});
it('uses a link to trigger callout and defers following until callout is finished', async () => {
const { href } = link;
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_OK);
link.click();
await waitForPromises();
expect(window.location.assign).toHaveBeenCalledWith(href);
expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
expect(mockAxios.history.post[0].data).toBe(JSON.stringify({ feature_name: featureName }));
});
it('invokes Flash when the dismiss request fails', async () => {
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
link.click();
await waitForPromises();
expect(window.location.assign).not.toHaveBeenCalled();
expect(createAlert).toHaveBeenCalledWith({
message:
'An error occurred while acknowledging the notification. Refresh the page and try again.',
});
});
});
describe('factory', () => {
it('returns an instance of PersistentUserCallout with the provided container property', () => {
const fixture = createFixture();

View File

@ -1,14 +1,24 @@
import MockAdapter from 'axios-mock-adapter';
import { GlAvatar, GlDisclosureDropdown } from '@gitlab/ui';
import { nextTick } from 'vue';
import axios from '~/lib/utils/axios_utils';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import UserMenu from '~/super_sidebar/components/user_menu.vue';
import UserMenuProfileItem from '~/super_sidebar/components/user_menu_profile_item.vue';
import SetStatusModal from '~/set_status_modal/set_status_modal_wrapper.vue';
import { mockTracking } from 'helpers/tracking_helper';
import PersistentUserCallout from '~/persistent_user_callout';
import { visitUrl } from '~/lib/utils/url_utility';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import waitForPromises from 'helpers/wait_for_promises';
import { logError } from '~/lib/logger';
import { userMenuMockData, userMenuMockStatus, userMenuMockPipelineMinutes } from '../mock_data';
jest.mock('~/sentry/sentry_browser_wrapper');
jest.mock('~/lib/utils/url_utility');
jest.mock('~/lib/logger');
describe('UserMenu component', () => {
let wrapper;
let trackingSpy;
@ -290,6 +300,7 @@ describe('UserMenu component', () => {
});
describe('Buy compute minutes item', () => {
/** @type {import('@vue/test-utils').Wrapper} */
let item;
const setItem = ({
@ -343,7 +354,8 @@ describe('UserMenu component', () => {
});
it('tracks the click on the item', () => {
item.vm.$emit('action');
showDropdown();
item.trigger('click');
expect(trackingSpy).toHaveBeenCalledWith(
undefined,
userMenuMockPipelineMinutes.tracking_attrs['track-action'],
@ -356,29 +368,23 @@ describe('UserMenu component', () => {
});
describe('Callout & notification dot', () => {
let spyFactory;
/** @type {MockAdapter} */
let mockAxios;
const dismissEndpoint = userMenuMockPipelineMinutes.callout_attrs.dismiss_endpoint;
const featureName = userMenuMockPipelineMinutes.callout_attrs.feature_id;
const href = userMenuMockPipelineMinutes.buy_pipeline_minutes_path;
beforeEach(() => {
spyFactory = jest.spyOn(PersistentUserCallout, 'factory');
mockAxios = new MockAdapter(axios);
});
afterEach(() => {
mockAxios.restore();
});
describe('When `show_notification_dot` is `false`', () => {
beforeEach(() => {
setItem({ show_buy_pipeline_minutes: true, show_notification_dot: false });
showDropdown();
});
it('does not set callout attributes', () => {
expect(item.attributes()).not.toEqual(
expect.objectContaining({
'data-feature-id': userMenuMockPipelineMinutes.callout_attrs.feature_id,
'data-dismiss-endpoint': userMenuMockPipelineMinutes.callout_attrs.dismiss_endpoint,
}),
);
});
it('does not initialize the Persistent Callout', () => {
expect(spyFactory).not.toHaveBeenCalled();
});
it('does not render notification dot', () => {
@ -386,6 +392,21 @@ describe('UserMenu component', () => {
false,
);
});
describe('clicking menu item', () => {
beforeEach(() => {
showDropdown();
item.trigger('click');
});
it('does not call the callout dismiss endpoint', () => {
expect(mockAxios.history.post.length).toBe(0);
});
it('does not manually proceed to the URL', () => {
expect(visitUrl).not.toHaveBeenCalled();
});
});
});
describe('When `show_notification_dot` is `true`', () => {
@ -394,24 +415,51 @@ describe('UserMenu component', () => {
showDropdown();
});
it('sets the callout data attributes', () => {
expect(item.attributes()).toEqual(
expect.objectContaining({
'data-feature-id': userMenuMockPipelineMinutes.callout_attrs.feature_id,
'data-dismiss-endpoint': userMenuMockPipelineMinutes.callout_attrs.dismiss_endpoint,
}),
);
});
it('initializes the Persistent Callout', () => {
expect(spyFactory).toHaveBeenCalled();
});
it('renders notification dot', () => {
expect(wrapper.findByTestId('buy-pipeline-minutes-notification-dot').exists()).toBe(
true,
);
});
describe('clicking menu item', () => {
describe('with successful callout dismissal', () => {
beforeEach(async () => {
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_OK);
item.trigger('click');
await waitForPromises();
});
it('dismisses the callout', () => {
expect(mockAxios.history.post[0].data).toBe(
JSON.stringify({ feature_name: featureName }),
);
});
it('proceeds to the original URL', () => {
expect(visitUrl).not.toHaveBeenCalledWith('abc');
});
});
describe('with failed callout dismissal', () => {
beforeEach(async () => {
mockAxios.onPost(dismissEndpoint).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
item.trigger('click');
await waitForPromises();
});
it('reports the error to the Sentry', () => {
expect(Sentry.captureException).toHaveBeenCalled();
});
it('reports the error to the console', () => {
expect(logError).toHaveBeenCalled();
});
it('proceeds to the original URL', () => {
expect(visitUrl).toHaveBeenCalledWith(href);
});
});
});
});
});

View File

@ -36,9 +36,7 @@ describe('AccessToken', () => {
expect(findInputCopyToggleVisibility().props()).toMatchObject({
copyButtonTitle: 'Copy token',
formInputGroupProps: {
'data-testid': 'access-token-field',
id: 'access-token-field',
name: 'access-token-field',
'data-testid': 'created-access-token-field',
},
initialVisibility: false,
readonly: true,

View File

@ -574,18 +574,5 @@ RSpec.describe Gitlab::ProjectSearchResults, feature_category: :global_search do
expect(objects).to contain_exactly(user_1)
end
context 'when multiple projects provided' do
let_it_be(:project_2) { create(:project, namespace: group) }
subject(:results) { described_class.new(user, query, project: [project, project_2], repository_ref: repository_ref, filters: filters) }
it 'returns users belonging to projects matching the search query' do
create(:project_member, :developer, user: user_1, project: project)
create(:project_member, :developer, user: user_3, project: project_2)
expect(objects).to contain_exactly(user_1, user_3)
end
end
end
end

View File

@ -1,27 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe RequeueBackfillArchivedAndTraversalIdsToVulnerabilityStatisticsAgain, migration: :gitlab_sec, feature_category: :vulnerability_management do
let!(:batched_migration) { described_class::MIGRATION }
it 'schedules a new batched migration' do
reversible_migration do |migration|
migration.before -> {
expect(batched_migration).not_to have_scheduled_batched_migration
}
migration.after -> {
expect(batched_migration).to have_scheduled_batched_migration(
gitlab_schema: :gitlab_sec,
table_name: :vulnerability_statistics,
column_name: :id,
interval: described_class::DELAY_INTERVAL,
batch_size: described_class::BATCH_SIZE,
sub_batch_size: described_class::SUB_BATCH_SIZE
)
}
end
end
end

View File

@ -16,10 +16,7 @@ module Features
# Keep after migrate_user_access_tokens_ui feature flag removal
def new_access_token
within_testid('new-access-token') do
find_by_testid('toggle-visibility-button').click
find_field('access-token-field').value
end
find_by_testid('created-access-token-field').value
end
def active_access_tokens_counter