Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-07-14 21:11:03 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-14 21:11:03 +0300
commit3da283df313b950685c1513b6b69a68de9c4ab11 (patch)
tree046edea54a5ea4945d7115ebb6552d55532eec38
parent2aea9a0c91723b8800b016335930c59390cda7c9 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS1
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/test-on-gdk/main.gitlab-ci.yml4
-rw-r--r--.gitpod.yml2
-rw-r--r--CHANGELOG.md4
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js10
-rw-r--r--app/assets/javascripts/notes/components/mr_discussion_filter.vue11
-rw-r--r--app/assets/javascripts/profile/components/follow.vue33
-rw-r--r--app/assets/javascripts/profile/components/followers_tab.vue4
-rw-r--r--app/assets/javascripts/profile/components/following_tab.vue4
-rw-r--r--app/assets/javascripts/profile/components/snippets/snippets_tab.vue37
-rw-r--r--app/assets/javascripts/profile/index.js4
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note.vue10
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue4
-rw-r--r--app/helpers/users_helper.rb4
-rw-r--r--app/services/groups/transfer_service.rb5
-rw-r--r--app/services/members/creator_service.rb50
-rw-r--r--app/services/members/groups/creator_service.rb2
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml2
-rw-r--r--config/feature_flags/development/scan_execution_policy_pipelines.yml2
-rw-r--r--doc/administration/admin_area.md4
-rw-r--r--doc/administration/auth/ldap/index.md4
-rw-r--r--doc/administration/moderate_users.md393
-rw-r--r--doc/administration/postgresql/replication_and_failover.md2
-rw-r--r--doc/administration/reporting/git_abuse_rate_limit.md2
-rw-r--r--doc/administration/settings/protected_paths.md2
-rw-r--r--doc/administration/settings/sign_up_restrictions.md4
-rw-r--r--doc/administration/settings/user_and_ip_rate_limits.md240
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/api/group_access_tokens.md5
-rw-r--r--doc/api/personal_access_tokens.md15
-rw-r--r--doc/api/project_access_tokens.md5
-rw-r--r--doc/api/settings.md4
-rw-r--r--doc/api/users.md4
-rw-r--r--doc/architecture/blueprints/work_items/index.md2
-rw-r--r--doc/development/internal_analytics/snowplow/infrastructure.md2
-rw-r--r--doc/development/jh_features_review.md14
-rw-r--r--doc/integration/omniauth.md2
-rw-r--r--doc/security/responding_to_security_incidents.md4
-rw-r--r--doc/subscriptions/self_managed/index.md8
-rw-r--r--doc/user/admin_area/moderate_users.md396
-rw-r--r--doc/user/admin_area/settings/user_and_ip_rate_limits.md243
-rw-r--r--doc/user/ai_features.md18
-rw-r--r--doc/user/application_security/policies/index.md1
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md27
-rw-r--r--doc/user/gitlab_com/index.md6
-rw-r--r--doc/user/group/moderate_users.md2
-rw-r--r--doc/user/profile/account/delete_account.md4
-rw-r--r--doc/user/upgrade_email_bypass.md2
-rw-r--r--locale/gitlab.pot30
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb12
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb18
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb12
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb4
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb6
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb24
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb14
-rw-r--r--qa/qa/specs/features/api/1_manage/rate_limits_spec.rb2
-rw-r--r--spec/frontend/lib/utils/common_utils_spec.js34
-rw-r--r--spec/frontend/notes/components/mr_discussion_filter_spec.js28
-rw-r--r--spec/frontend/profile/components/follow_spec.js49
-rw-r--r--spec/frontend/profile/components/followers_tab_spec.js2
-rw-r--r--spec/frontend/profile/components/following_tab_spec.js2
-rw-r--r--spec/frontend/profile/components/snippets/snippets_tab_spec.js43
-rw-r--r--spec/frontend/profile/mock_data.js1
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_spec.js10
-rw-r--r--spec/helpers/users_helper_spec.rb18
68 files changed, 1099 insertions, 824 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 8537dac7547..58e481dea77 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -1103,7 +1103,6 @@ lib/gitlab/checks/**
/ee/app/assets/javascripts/access_tokens/
/ee/app/assets/javascripts/audit_events/components/tokens/
/ee/app/assets/javascripts/audit_events/token_utils.js
-/ee/app/assets/javascripts/batch_comments/
/ee/app/assets/javascripts/groups/settings/components/
/ee/app/assets/javascripts/pages/admin/application_settings/general/components/
/ee/app/assets/javascripts/pages/groups/omniauth_callbacks/
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 6b6dd6bef60..f1905742ac6 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -613,6 +613,8 @@
.as-if-jh-default-exclusion-rules:
rules:
+ - if: '$ADD_JH_FILES_TOKEN == null'
+ when: never
- <<: *if-security-merge-request
when: never
- <<: *if-merge-request-targeting-stable-branch
diff --git a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
index bd5fdf78a63..8937ee44638 100644
--- a/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
+++ b/.gitlab/ci/test-on-gdk/main.gitlab-ci.yml
@@ -134,12 +134,12 @@ gdk-qa-smoke-with-load-balancer:
variables:
QA_SCENARIO: Test::Instance::Smoke
QA_RUN_TYPE: gdk-qa-smoke
+ allow_failure: true
rules:
- changes:
- ".gitlab/ci/test-on-gdk/**"
- "lib/gitlab/database/load_balancing/**/*"
-# TODO: set non manual once smoke tests prove to be stable
gdk-qa-reliable:
extends:
- .gdk-qa-base
@@ -149,7 +149,7 @@ gdk-qa-reliable:
QA_RUN_TYPE: gdk-qa-blocking
allow_failure: true
rules:
- - when: manual
+ - when: always
gdk-qa-reliable-with-load-balancer:
extends:
diff --git a/.gitpod.yml b/.gitpod.yml
index 81e08a98674..0a047495ac6 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -92,7 +92,7 @@ tasks:
# Give Gitpod a few more seconds to set up everything ...
sleep 5
printf "$(date) – GitLab is up (took ~%.1f minutes)\n" "$((10*$SECONDS/60))e-1" | tee -a /workspace/startup.log
- gp preview $(gp url 3000) || true
+ gp preview $(gp url 3000) --external || true
PREBUILD_LOG=(/workspace/.gitpod/prebuild-log-*)
[[ -f /workspace/gitpod_start_time.sh ]] && printf "Took %.1f minutes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitpod.yml being executed through to completion %s\n" "$((10*(($(date +%s)-${START_UNIXTIME}))/60))e-1" "$([[ -f "$PREBUILD_LOG" ]] && echo "With Prebuilds")"
)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10f4e443ffc..4f0ed487109 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1818,6 +1818,10 @@ entry.
- [Add index to group_group_links table](gitlab-org/gitlab@9a3f2c1a90b54074e61d0abf07101ce664198e81) ([merge request](gitlab-org/gitlab!117386))
- [Validate the projects.creator_id foregin key synchronously](gitlab-org/gitlab@ed9351984a16f20506babf6eab6706b917904ed1) ([merge request](gitlab-org/gitlab!117147))
+## 15.11.12 (2023-07-14)
+
+No changes.
+
## 15.11.11 (2023-07-04)
### Security (1 change)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 253fb8a5a0b..8e10bde7119 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-4c314694734330f910ce5d1409c0d462a02628ff
+6f26cab11ed6ade703ad23809b5fa053989b7ff3
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 7795dac18bc..cca4cf68f5e 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -721,3 +721,13 @@ export const getFirstPropertyValue = (data) => {
return data[key];
};
+
+export const isCurrentUser = (userId) => {
+ const currentUserId = window.gon?.current_user_id;
+
+ if (!currentUserId) {
+ return false;
+ }
+
+ return Number(userId) === currentUserId;
+};
diff --git a/app/assets/javascripts/notes/components/mr_discussion_filter.vue b/app/assets/javascripts/notes/components/mr_discussion_filter.vue
index 2338c9eef67..7ca0c4730a9 100644
--- a/app/assets/javascripts/notes/components/mr_discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/mr_discussion_filter.vue
@@ -62,6 +62,12 @@ export default {
this.updateMergeRequestFilters(filters);
this.selectedFilters = filters;
},
+ deselectAll() {
+ this.selectedFilters = [];
+ },
+ selectAll() {
+ this.selectedFilters = MR_FILTER_OPTIONS.map((f) => f.value);
+ },
},
MR_FILTER_OPTIONS,
};
@@ -84,9 +90,14 @@ export default {
<gl-collapsible-listbox
v-model="selectedFilters"
:items="$options.MR_FILTER_OPTIONS"
+ :header-text="__('Filter activity')"
+ :show-select-all-button-label="__('Select all')"
+ :reset-button-label="__('Deselect all')"
multiple
placement="right"
@hidden="applyFilters"
+ @reset="deselectAll"
+ @select-all="selectAll"
>
<template #toggle>
<gl-button class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!">
diff --git a/app/assets/javascripts/profile/components/follow.vue b/app/assets/javascripts/profile/components/follow.vue
index 7bab8a1c30d..2673ab6fbf4 100644
--- a/app/assets/javascripts/profile/components/follow.vue
+++ b/app/assets/javascripts/profile/components/follow.vue
@@ -1,7 +1,14 @@
<script>
-import { GlAvatarLabeled, GlAvatarLink, GlLoadingIcon, GlPagination } from '@gitlab/ui';
+import {
+ GlAvatarLabeled,
+ GlAvatarLink,
+ GlLoadingIcon,
+ GlPagination,
+ GlEmptyState,
+} from '@gitlab/ui';
import { DEFAULT_PER_PAGE } from '~/api';
import { NEXT, PREV } from '~/vue_shared/components/pagination/constants';
+import { isCurrentUser } from '~/lib/utils/common_utils';
export default {
i18n: {
@@ -13,7 +20,9 @@ export default {
GlAvatarLink,
GlLoadingIcon,
GlPagination,
+ GlEmptyState,
},
+ inject: ['followEmptyState', 'userId'],
props: {
/**
* Expected format:
@@ -48,12 +57,34 @@ export default {
required: false,
default: DEFAULT_PER_PAGE,
},
+ currentUserEmptyStateTitle: {
+ type: String,
+ required: true,
+ },
+ visitorEmptyStateTitle: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ emptyStateTitle() {
+ return isCurrentUser(this.userId)
+ ? this.currentUserEmptyStateTitle
+ : this.visitorEmptyStateTitle;
+ },
},
};
</script>
<template>
<gl-loading-icon v-if="loading" class="gl-mt-5" size="md" />
+ <gl-empty-state
+ v-else-if="!users.length"
+ class="gl-mt-5"
+ :svg-path="followEmptyState"
+ :svg-height="144"
+ :title="emptyStateTitle"
+ />
<div v-else>
<div class="gl-my-n3 gl-mx-n3 gl-display-flex gl-flex-wrap">
<div v-for="user in users" :key="user.id" class="gl-p-3 gl-w-full gl-md-w-half gl-lg-w-25p">
diff --git a/app/assets/javascripts/profile/components/followers_tab.vue b/app/assets/javascripts/profile/components/followers_tab.vue
index 1fa579bc611..927424d6c3f 100644
--- a/app/assets/javascripts/profile/components/followers_tab.vue
+++ b/app/assets/javascripts/profile/components/followers_tab.vue
@@ -12,6 +12,8 @@ export default {
errorMessage: s__(
'UserProfile|An error occurred loading the followers. Please refresh the page to try again.',
),
+ currentUserEmptyStateTitle: s__('UserProfile|You do not have any followers'),
+ visitorEmptyStateTitle: s__("UserProfile|This user doesn't have any followers"),
},
components: {
GlBadge,
@@ -68,6 +70,8 @@ export default {
:loading="loading"
:page="page"
:total-items="totalItems"
+ :current-user-empty-state-title="$options.i18n.currentUserEmptyStateTitle"
+ :visitor-empty-state-title="$options.i18n.visitorEmptyStateTitle"
@pagination-input="onPaginationInput"
/>
</gl-tab>
diff --git a/app/assets/javascripts/profile/components/following_tab.vue b/app/assets/javascripts/profile/components/following_tab.vue
index 27c16ee5b46..66c7ee42a3f 100644
--- a/app/assets/javascripts/profile/components/following_tab.vue
+++ b/app/assets/javascripts/profile/components/following_tab.vue
@@ -12,6 +12,8 @@ export default {
errorMessage: s__(
'UserProfile|An error occurred loading the following. Please refresh the page to try again.',
),
+ currentUserEmptyStateTitle: s__('UserProfile|You are not following other users'),
+ visitorEmptyStateTitle: s__("UserProfile|This user isn't following other users"),
},
components: {
GlBadge,
@@ -69,6 +71,8 @@ export default {
:loading="loading"
:page="page"
:total-items="totalItems"
+ :current-user-empty-state-title="$options.i18n.currentUserEmptyStateTitle"
+ :visitor-empty-state-title="$options.i18n.visitorEmptyStateTitle"
@pagination-input="onPaginationInput"
/>
</gl-tab>
diff --git a/app/assets/javascripts/profile/components/snippets/snippets_tab.vue b/app/assets/javascripts/profile/components/snippets/snippets_tab.vue
index fce5e2f5e78..95649f9645b 100644
--- a/app/assets/javascripts/profile/components/snippets/snippets_tab.vue
+++ b/app/assets/javascripts/profile/components/snippets/snippets_tab.vue
@@ -1,9 +1,11 @@
<script>
import { GlTab, GlKeysetPagination, GlEmptyState } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { s__, __ } from '~/locale';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_USER } from '~/graphql_shared/constants';
import { SNIPPET_MAX_LIST_COUNT } from '~/profile/constants';
+import { isCurrentUser } from '~/lib/utils/common_utils';
+import { helpPagePath } from '~/helpers/help_page_helper';
import getUserSnippets from '../graphql/get_user_snippets.query.graphql';
import SnippetRow from './snippet_row.vue';
@@ -11,7 +13,11 @@ export default {
name: 'SnippetsTab',
i18n: {
title: s__('UserProfile|Snippets'),
- noSnippets: s__('UserProfiles|No snippets found.'),
+ currentUserEmptyStateTitle: s__('UserProfile|Get started with snippets'),
+ visitorEmptyStateTitle: s__("UserProfile|This user doesn't have any snippets"),
+ emptyStateDescription: s__('UserProfile|Store, share, and embed bits of code and text.'),
+ newSnippet: __('New snippet'),
+ learnMore: __('Learn more'),
},
components: {
GlTab,
@@ -19,7 +25,7 @@ export default {
GlEmptyState,
SnippetRow,
},
- inject: ['userId', 'snippetsEmptyState'],
+ inject: ['userId', 'snippetsEmptyState', 'newSnippetPath'],
data() {
return {
userInfo: {},
@@ -57,6 +63,14 @@ export default {
hasSnippets() {
return this.userSnippets?.length;
},
+ emptyStateTitle() {
+ return isCurrentUser(this.userId)
+ ? this.$options.i18n.currentUserEmptyStateTitle
+ : this.$options.i18n.visitorEmptyStateTitle;
+ },
+ emptyStateDescription() {
+ return isCurrentUser(this.userId) ? this.$options.i18n.emptyStateDescription : null;
+ },
},
methods: {
isLastSnippet(index) {
@@ -76,6 +90,7 @@ export default {
beforeToken: this.pageInfo.startCursor,
};
},
+ helpPagePath,
},
};
</script>
@@ -100,11 +115,17 @@ export default {
</div>
</template>
<template v-if="!hasSnippets">
- <gl-empty-state class="gl-mt-5" :svg-height="75" :svg-path="snippetsEmptyState">
- <template #title>
- <p class="gl-font-weight-bold gl-mt-n5">{{ $options.i18n.noSnippets }}</p>
- </template>
- </gl-empty-state>
+ <gl-empty-state
+ class="gl-mt-5"
+ :svg-path="snippetsEmptyState"
+ :svg-height="144"
+ :title="emptyStateTitle"
+ :description="emptyStateDescription"
+ :primary-button-link="newSnippetPath"
+ :primary-button-text="$options.i18n.newSnippet"
+ :secondary-button-text="$options.i18n.learnMore"
+ :secondary-button-link="helpPagePath('user/snippets')"
+ />
</template>
</gl-tab>
</template>
diff --git a/app/assets/javascripts/profile/index.js b/app/assets/javascripts/profile/index.js
index 198ffdb434b..76430d7b34d 100644
--- a/app/assets/javascripts/profile/index.js
+++ b/app/assets/javascripts/profile/index.js
@@ -21,6 +21,8 @@ export const initProfileTabs = () => {
utcOffset,
userId,
snippetsEmptyState,
+ newSnippetPath,
+ followEmptyState,
} = el.dataset;
const apolloProvider = new VueApollo({
@@ -39,6 +41,8 @@ export const initProfileTabs = () => {
utcOffset,
userId,
snippetsEmptyState,
+ newSnippetPath,
+ followEmptyState,
},
render(createElement) {
return createElement(ProfileTabs);
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note.vue b/app/assets/javascripts/work_items/components/notes/work_item_note.vue
index cffcadc09c9..a2667a379e1 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note.vue
@@ -11,7 +11,6 @@ import { getLocationHash } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import EditedAt from '~/issues/show/components/edited.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import NoteBody from '~/work_items/components/notes/work_item_note_body.vue';
import NoteHeader from '~/notes/components/note_header.vue';
import NoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
@@ -34,7 +33,7 @@ export default {
WorkItemCommentForm,
EditedAt,
},
- mixins: [Tracking.mixin(), glFeatureFlagsMixin()],
+ mixins: [Tracking.mixin()],
inject: ['fullPath'],
props: {
workItemId: {
@@ -370,12 +369,7 @@ export default {
/>
</div>
<div class="note-awards" :class="isFirstNote ? '' : 'gl-pl-7'">
- <work-item-note-awards-list
- v-if="glFeatures.workItemsMvc2"
- :note="note"
- :work-item-iid="workItemIid"
- :is-modal="isModal"
- />
+ <work-item-note-awards-list :note="note" :work-item-iid="workItemIid" :is-modal="isModal" />
</div>
</div>
</timeline-entry-item>
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue b/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue
index bc5dfe37280..427115695d6 100644
--- a/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue
+++ b/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue
@@ -10,7 +10,6 @@ import * as Sentry from '@sentry/browser';
import { __, sprintf } from '~/locale';
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import ReplyButton from '~/notes/components/note_actions/reply_button.vue';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getMutation, optimisticAwardUpdate } from '../../notes/award_utils';
export default {
@@ -36,7 +35,6 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [glFeatureFlagsMixin()],
inject: ['fullPath'],
props: {
workItemIid: {
@@ -199,7 +197,7 @@ export default {
{{ __('Contributor') }}
</user-access-role-badge>
<emoji-picker
- v-if="showAwardEmoji && glFeatures.workItemsMvc2"
+ v-if="showAwardEmoji"
toggle-class="note-action-button note-emoji-button btn-icon btn-default-tertiary"
data-testid="note-emoji-button"
@click="setAwardEmoji"
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index 383f482687c..29998a996e2 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -190,7 +190,9 @@ module UsersHelper
user_activity_path: user_activity_path(user, :json),
utc_offset: local_timezone_instance(user.timezone).now.utc_offset,
user_id: user.id,
- snippets_empty_state: image_path('illustrations/empty-state/empty-snippets-md.svg')
+ snippets_empty_state: image_path('illustrations/empty-state/empty-snippets-md.svg'),
+ new_snippet_path: (new_snippet_path if can?(current_user, :create_snippet)),
+ follow_empty_state: image_path('illustrations/empty-state/empty-friends-md.svg')
}
end
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index 16454360ee2..81d4dfddaab 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -197,6 +197,11 @@ module Groups
return if @new_parent_group
return unless @group.owners.empty?
+ add_owner_on_transferred_group
+ end
+
+ # Overridden in EE
+ def add_owner_on_transferred_group
@group.add_owner(current_user)
end
diff --git a/app/services/members/creator_service.rb b/app/services/members/creator_service.rb
index 699c5b94c53..a6fff3003ac 100644
--- a/app/services/members/creator_service.rb
+++ b/app/services/members/creator_service.rb
@@ -34,16 +34,7 @@ module Members
# @param sources [Group, Project, Array<Group>, Array<Project>, Group::ActiveRecord_Relation,
# Project::ActiveRecord_Relation] - Can't be an array of source ids because we don't know the type of source.
# @return Array<Member>
- def add_members(
- sources,
- invitees,
- access_level,
- current_user: nil,
- expires_at: nil,
- tasks_to_be_done: [],
- tasks_project_id: nil,
- ldap: nil
- ) # rubocop:disable Metrics/ParameterLists
+ def add_members(sources, invitees, access_level, **args)
return [] unless invitees.present?
sources = Array.wrap(sources) if sources.is_a?(ApplicationRecord) # For single source
@@ -51,7 +42,9 @@ module Members
Member.transaction do
sources.flat_map do |source|
# If this user is attempting to manage Owner members and doesn't have permission, do not allow
- next [] if managing_owners?(current_user, access_level) && cannot_manage_owners?(source, current_user)
+ if managing_owners?(args[:current_user], access_level) && cannot_manage_owners?(source, args[:current_user])
+ next []
+ end
emails, users, existing_members = parse_users_list(source, invitees)
@@ -59,12 +52,8 @@ module Members
source: source,
access_level: access_level,
existing_members: existing_members,
- current_user: current_user,
- expires_at: expires_at,
- tasks_to_be_done: tasks_to_be_done,
- tasks_project_id: tasks_project_id,
- ldap: ldap
- }
+ tasks_to_be_done: args[:tasks_to_be_done] || []
+ }.merge(parsed_args(args))
members = emails.map do |email|
new(invitee: email, builder: InviteMemberBuilder, **common_arguments).execute
@@ -79,26 +68,21 @@ module Members
end
end
- def add_member(
- source,
- invitee,
- access_level,
- current_user: nil,
- expires_at: nil,
- ldap: nil
- ) # rubocop:disable Metrics/ParameterLists
- add_members(
- source,
- [invitee],
- access_level,
- current_user: current_user,
- expires_at: expires_at,
- ldap: ldap
- ).first
+ def add_member(source, invitee, access_level, **args)
+ add_members(source, [invitee], access_level, **args).first
end
private
+ def parsed_args(args)
+ {
+ current_user: args[:current_user],
+ expires_at: args[:expires_at],
+ tasks_project_id: args[:tasks_project_id],
+ ldap: args[:ldap]
+ }
+ end
+
def managing_owners?(current_user, access_level)
current_user && Gitlab::Access.sym_options_with_owner[access_level] == Gitlab::Access::OWNER
end
diff --git a/app/services/members/groups/creator_service.rb b/app/services/members/groups/creator_service.rb
index dd3d44e4d96..864be01a96d 100644
--- a/app/services/members/groups/creator_service.rb
+++ b/app/services/members/groups/creator_service.rb
@@ -21,3 +21,5 @@ module Members
end
end
end
+
+Members::Groups::CreatorService.prepend_mod_with('Members::Groups::CreatorService')
diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml
index 572c2b73019..af67ed28309 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -55,7 +55,7 @@
- unless Gitlab.com?
.form-group
= f.label :deactivate_dormant_users, _('Dormant users'), class: 'label-bold'
- - dormant_users_help_link = help_page_path('user/admin_area/moderate_users', anchor: 'automatically-deactivate-dormant-users')
+ - dormant_users_help_link = help_page_path('administration/moderate_users', anchor: 'automatically-deactivate-dormant-users')
- dormant_users_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: dormant_users_help_link }
= f.gitlab_ui_checkbox_component :deactivate_dormant_users, _('Deactivate dormant users after a period of inactivity'), help_text: _('Users can reactivate their account by signing in. %{link_start}Learn more.%{link_end}').html_safe % { link_start: dormant_users_help_link_start, link_end: '</a>'.html_safe }
.form-group
diff --git a/config/feature_flags/development/scan_execution_policy_pipelines.yml b/config/feature_flags/development/scan_execution_policy_pipelines.yml
index bf2b2934ba9..b062b9940c3 100644
--- a/config/feature_flags/development/scan_execution_policy_pipelines.yml
+++ b/config/feature_flags/development/scan_execution_policy_pipelines.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415607
milestone: '16.1'
type: development
group: group::security policies
-default_enabled: false
+default_enabled: true
diff --git a/doc/administration/admin_area.md b/doc/administration/admin_area.md
index 65e437be487..82ee7c92c6d 100644
--- a/doc/administration/admin_area.md
+++ b/doc/administration/admin_area.md
@@ -85,8 +85,8 @@ To list users matching a specific criteria, select one of the following tabs on
- **2FA Enabled**
- **2FA Disabled**
- **External**
-- **[Blocked](../user/admin_area/moderate_users.md#block-a-user)**
-- **[Deactivated](../user/admin_area/moderate_users.md#deactivate-a-user)**
+- **[Blocked](../administration/moderate_users.md#block-a-user)**
+- **[Deactivated](../administration/moderate_users.md#deactivate-a-user)**
- **Without projects**
For each user, the following are listed:
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index ba22a07c052..1905a009eb6 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -1000,13 +1000,13 @@ authenticated with the TLS protocol.
Users deleted from the LDAP server:
- Are immediately blocked from signing in to GitLab.
-- [No longer consume a license](../../../user/admin_area/moderate_users.md).
+- [No longer consume a license](../../../administration/moderate_users.md).
However, these users can continue to use Git with SSH until the next time the
[LDAP check cache runs](ldap_synchronization.md#adjust-ldap-user-sync-schedule).
To delete the account immediately, you can manually
-[block the user](../../../user/admin_area/moderate_users.md#block-a-user).
+[block the user](../../../administration/moderate_users.md#block-a-user).
## Update user email addresses
diff --git a/doc/administration/moderate_users.md b/doc/administration/moderate_users.md
new file mode 100644
index 00000000000..41d61d8418f
--- /dev/null
+++ b/doc/administration/moderate_users.md
@@ -0,0 +1,393 @@
+---
+stage: Manage
+group: Authentication and Authorization
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: howto
+---
+
+# Moderate users (administration) **(FREE SELF)**
+
+This is the administration documentation. For information about moderating users at the group level, see the [group-level documentation](../user/group/moderate_users.md).
+
+GitLab administrators can moderate user access by approving, blocking, banning, or deactivating
+users.
+
+## Users pending approval
+
+A user in _pending approval_ state requires action by an administrator. A user sign up can be in a
+pending approval state because an administrator has enabled any of the following options:
+
+- [Require administrator approval for new sign-ups](../administration/settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups) setting.
+- [User cap](../administration/settings/sign_up_restrictions.md#user-cap).
+- [Block auto-created users (OmniAuth)](../integration/omniauth.md#configure-common-settings)
+- [Block auto-created users (LDAP)](../administration/auth/ldap/index.md#basic-configuration-settings)
+
+When a user registers for an account while this setting is enabled:
+
+- The user is placed in a **Pending approval** state.
+- The user sees a message telling them their account is awaiting approval by an administrator.
+
+A user pending approval:
+
+- Is functionally identical to a [blocked](#block-a-user) user.
+- Cannot sign in.
+- Cannot access Git repositories or the GitLab API.
+- Does not receive any notifications from GitLab.
+- Does not consume a [seat](../subscriptions/self_managed/index.md#billable-users).
+
+An administrator must [approve their sign up](#approve-or-reject-a-user-sign-up) to allow them to
+sign in.
+
+### View user sign ups pending approval
+
+To view user sign ups pending approval:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Pending approval** tab.
+
+### Approve or reject a user sign up
+
+A user sign up pending approval can be approved or rejected from the Admin Area.
+
+To approve or reject a user sign up:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Pending approval** tab.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Approve** or **Reject**.
+
+Approving a user:
+
+- Activates their account.
+- Changes the user's state to active.
+- Consumes a subscription [seat](../subscriptions/self_managed/index.md#billable-users).
+
+## Block and unblock users
+
+GitLab administrators can block and unblock users.
+
+### Block a user
+
+To completely prevent access of a user to the GitLab instance,
+administrators can choose to block the user.
+
+Users can be blocked [via an abuse report](../administration/review_abuse_reports.md#blocking-users),
+by removing them in LDAP, or directly from the Admin Area. To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Block**.
+
+A blocked user:
+
+- Cannot sign in.
+- Cannot access Git repositories or the API.
+- Does not receive any notifications from GitLab.
+- Cannot use [slash commands](../user/project/integrations/gitlab_slack_application.md#slash-commands).
+- Does not consume a [seat](../subscriptions/self_managed/index.md#billable-users).
+
+Personal projects, and group and user history of the blocked user are left intact.
+
+NOTE:
+Users can also be blocked using the [GitLab API](../api/users.md#block-user).
+
+### Unblock a user
+
+A blocked user can be unblocked from the Admin Area. To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Blocked** tab.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Unblock**.
+
+The user's state is set to active and they consume a
+[seat](../subscriptions/self_managed/index.md#billable-users).
+
+NOTE:
+Users can also be unblocked using the [GitLab API](../api/users.md#unblock-user).
+
+The unblock option may be unavailable for LDAP users. To enable the unblock option,
+the LDAP identity first needs to be deleted:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Blocked** tab.
+1. Select a user.
+1. Select the **Identities** tab.
+1. Find the LDAP provider and select **Delete**.
+
+## Activate and deactivate users
+
+GitLab administrators can deactivate and activate users.
+
+### Deactivate a user
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22257) in GitLab 12.4.
+
+To temporarily prevent access by a GitLab user that has no recent activity,
+administrators can choose to deactivate the user.
+
+Deactivating a user is functionally identical to [blocking a user](#block-and-unblock-users),
+with the following differences:
+
+- It does not prohibit the user from logging back in via the UI.
+- Once a deactivated user logs back into the GitLab UI, their account is set to active.
+
+A deactivated user:
+
+- Cannot access Git repositories or the API.
+- Does not receive any notifications from GitLab.
+- Cannot use [slash commands](../user/project/integrations/gitlab_slack_application.md#slash-commands).
+- Does not consume a [seat](../subscriptions/self_managed/index.md#billable-users).
+
+Personal projects, and group and user history of the deactivated user are left intact.
+
+NOTE:
+Users are notified about account deactivation if
+[user deactivation emails](../user/admin_area/settings/email.md#user-deactivation-emails) are enabled.
+
+A user can be deactivated from the Admin Area. To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Deactivate**.
+
+For the deactivation option to be visible to an administrator, the user:
+
+- Must have a state of active.
+- Must be [dormant](#automatically-deactivate-dormant-users).
+
+NOTE:
+Users can also be deactivated using the [GitLab API](../api/users.md#deactivate-user).
+
+### Automatically deactivate dormant users
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/320875) in GitLab 14.0.
+> - Exclusion of GitLab generate bots [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340346) in GitLab 14.5
+> - Customizable time period [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336747) in GitLab 15.4
+> - The lower limit for inactive period set to 90 days [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100793) in GitLab 15.5
+
+Administrators can enable automatic deactivation of users who either:
+
+- Were created more than a week ago and have not signed in.
+- Have no activity for a specified period of time (default and minimum is 90 days).
+
+To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Settings > General**.
+1. Expand the **Account and limit** section.
+1. Under **Dormant users**, check **Deactivate dormant users after a period of inactivity**.
+1. Under **Days of inactivity before deactivation**, enter the number of days before deactivation. Minimum value is 90 days.
+1. Select **Save changes**.
+
+When this feature is enabled, GitLab runs a job once a day to deactivate the dormant users.
+
+A maximum of 100,000 users can be deactivated per day.
+
+NOTE:
+GitLab generated bots are excluded from the automatic deactivation of dormant users.
+
+### Automatically delete unconfirmed users **(PREMIUM SELF)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514) in GitLab 16.1 [with a flag](../administration/feature_flags.md) named `delete_unconfirmed_users_setting`. Disabled by default.
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124982) in GitLab 16.2.
+
+Prerequisites:
+
+- You must be an administrator.
+
+You can enable automatic deletion of users who both:
+
+- Never confirmed their email address.
+- Signed up for GitLab more than a specified number of days in the past.
+
+You can configure these settings using either the [Settings API](../api/settings.md) or in a Rails console:
+
+```ruby
+ Gitlab::CurrentSettings.update(delete_unconfirmed_users: true)
+ Gitlab::CurrentSettings.update(unconfirmed_users_delete_after_days: 365)
+```
+
+When the `delete_unconfirmed_users` setting is enabled, GitLab runs a job once an hour to delete the unconfirmed users.
+The job only deletes users who signed up more than `unconfirmed_users_delete_after_days` days in the past.
+
+This job only runs when the `email_confirmation_setting` is set to `soft` or `hard`.
+
+A maximum of 240,000 users can be deleted per day.
+
+### Activate a user
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22257) in GitLab 12.4.
+
+A deactivated user can be activated from the Admin Area.
+
+To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Deactivated** tab.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Activate**.
+
+The user's state is set to active and they consume a
+[seat](../subscriptions/self_managed/index.md#billable-users).
+
+NOTE:
+A deactivated user can also activate their account themselves by logging back in via the UI.
+Users can also be activated using the [GitLab API](../api/users.md#activate-user).
+
+## Ban and unban users
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327353) in GitLab 14.2 [with a flag](../administration/feature_flags.md) named `ban_user_feature_flag`. Disabled by default.
+> - Ban and unban users [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/327353) in GitLab 14.8. Feature flag `ban_user_feature_flag` removed.
+> - Hiding merge requests of banned users [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107836) in GitLab 15.8 [with a flag](../administration/feature_flags.md) named `hide_merge_requests_from_banned_users`. Disabled by default.
+> - Hiding comments of banned users [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112973) in GitLab 15.11 [with a flag](../administration/feature_flags.md) named `hidden_notes`. Disabled by default.
+> - Hiding projects of banned users [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121488) in GitLab 16.2 [with a flag](../administration/feature_flags.md) named `hide_projects_of_banned_users`. Disabled by default.
+
+GitLab administrators can ban and unban users. Banned users are blocked, and their projects, issues, merge requests, and comments are hidden.
+
+### Ban a user
+
+To block a user and hide their contributions, administrators can ban the user.
+
+Users can be banned using the Admin Area. To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Ban user**.
+
+The banned user does not consume a [seat](../subscriptions/self_managed/index.md#billable-users).
+
+### Unban a user
+
+A banned user can be unbanned using the Admin Area. To do this:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Banned** tab.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Unban user**.
+
+The user's state is set to active and they consume a
+[seat](../subscriptions/self_managed/index.md#billable-users).
+
+### Delete a user
+
+Use the Admin Area to delete users.
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Banned** tab.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Delete user**.
+1. Type the username.
+1. Select **Delete user**.
+
+NOTE:
+You can only delete a user if there are inherited or direct owners of a group. You cannot delete a user if they are the only group owner.
+
+You can also delete a user and their contributions, such as merge requests, issues, and groups of which they are the only group owner.
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Overview > Users**.
+1. Select the **Banned** tab.
+1. Optional. Select a user.
+1. Select the **{settings}** **User administration** dropdown list.
+1. Select **Delete user and contributions**.
+1. Type the username.
+1. Select **Delete user and contributions**.
+
+NOTE:
+Before 15.1, additionally groups of which deleted user were the only owner among direct members were deleted.
+
+## Troubleshooting
+
+When moderating users, you may need to perform bulk actions on them based on certain conditions. The following rails console scripts show some examples of this. You may [start a rails console session](../administration/operations/rails_console.md#starting-a-rails-console-session) and use scripts similar to the following:
+
+### Deactivate users that have no recent activity
+
+Administrators can deactivate users that have no recent activity.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+days_inactive = 90
+inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
+
+inactive_users.each do |user|
+ puts "user '#{user.username}': #{user.last_activity_on}"
+ user.deactivate!
+end
+```
+
+### Block users that have no recent activity
+
+Administrators can block users that have no recent activity.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+days_inactive = 90
+inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
+
+inactive_users.each do |user|
+ puts "user '#{user.username}': #{user.last_activity_on}"
+ user.block!
+end
+```
+
+### Block or delete users that have no projects or groups
+
+Administrators can block or delete users that have no projects or groups.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+users = User.where('id NOT IN (select distinct(user_id) from project_authorizations)')
+
+# How many users are removed?
+users.count
+
+# If that count looks sane:
+
+# You can either block the users:
+users.each { |user| user.blocked? ? nil : user.block! }
+
+# Or you can delete them:
+ # need 'current user' (your user) for auditing purposes
+current_user = User.find_by(username: '<your username>')
+
+users.each do |user|
+ DeleteUserWorker.perform_async(current_user.id, user.id)
+end
+```
diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md
index 7daca57be22..80dc39e4adc 100644
--- a/doc/administration/postgresql/replication_and_failover.md
+++ b/doc/administration/postgresql/replication_and_failover.md
@@ -837,7 +837,7 @@ Read more about the data returned by the replica
### Selecting the appropriate Patroni replication method
-[Review the Patroni documentation carefully](https://patroni.readthedocs.io/en/latest/SETTINGS.html#postgresql)
+[Review the Patroni documentation carefully](https://patroni.readthedocs.io/en/latest/yaml_configuration.html#postgresql)
before making changes as **_some of the options carry a risk of potential data
loss if not fully understood_**. The [replication mode](https://patroni.readthedocs.io/en/latest/replication_modes.html)
configured determines the amount of tolerable data loss.
diff --git a/doc/administration/reporting/git_abuse_rate_limit.md b/doc/administration/reporting/git_abuse_rate_limit.md
index 7bb368efdd1..270a7cb4800 100644
--- a/doc/administration/reporting/git_abuse_rate_limit.md
+++ b/doc/administration/reporting/git_abuse_rate_limit.md
@@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This is the administration documentation. For information about Git abuse rate limiting at the group level, see the [group-level documentation](../../user/group/reporting/git_abuse_rate_limit.md).
-Git abuse rate limiting is a feature to automatically [ban users](../../user/admin_area/moderate_users.md#ban-and-unban-users) who download, clone, or fork more than a specified number of repositories in any project in the instance in a given time frame. Banned users cannot sign in to the instance and cannot access any non-public group via HTTP or SSH. The rate limit also applies to users who authenticate with a [personal](../../user/profile/personal_access_tokens.md) or [group access token](../../user/group/settings/group_access_tokens.md).
+Git abuse rate limiting is a feature to automatically [ban users](../../administration/moderate_users.md#ban-and-unban-users) who download, clone, or fork more than a specified number of repositories in any project in the instance in a given time frame. Banned users cannot sign in to the instance and cannot access any non-public group via HTTP or SSH. The rate limit also applies to users who authenticate with a [personal](../../user/profile/personal_access_tokens.md) or [group access token](../../user/group/settings/group_access_tokens.md).
Git abuse rate limiting does not apply to instance administrators, [deploy tokens](../../user/project/deploy_tokens/index.md), or [deploy keys](../../user/project/deploy_keys/index.md).
diff --git a/doc/administration/settings/protected_paths.md b/doc/administration/settings/protected_paths.md
index 28ca3651387..451ddff1409 100644
--- a/doc/administration/settings/protected_paths.md
+++ b/doc/administration/settings/protected_paths.md
@@ -24,7 +24,7 @@ After 10 requests, the client must wait 60 seconds before it can try again.
See also:
- List of paths [protected by default](../instance_limits.md#by-protected-path).
-- [User and IP rate limits](../../user/admin_area/settings/user_and_ip_rate_limits.md#response-headers)
+- [User and IP rate limits](user_and_ip_rate_limits.md#response-headers)
for the headers returned to blocked requests.
## Configure protected paths
diff --git a/doc/administration/settings/sign_up_restrictions.md b/doc/administration/settings/sign_up_restrictions.md
index c9daeb109da..09a0868c8a2 100644
--- a/doc/administration/settings/sign_up_restrictions.md
+++ b/doc/administration/settings/sign_up_restrictions.md
@@ -34,7 +34,7 @@ To disable sign ups:
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/267568) in GitLab 13.6.
When this setting is enabled, any user visiting your GitLab domain and signing up for a new account using the registration form
-must be explicitly [approved](../../user/admin_area/moderate_users.md#approve-or-reject-a-user-sign-up) by an
+must be explicitly [approved](../../administration/moderate_users.md#approve-or-reject-a-user-sign-up) by an
administrator before they can start using their account. In GitLab 13.6 and later, this setting is
enabled by default for new GitLab instances. It is only applicable if sign ups are enabled.
@@ -84,7 +84,7 @@ The following settings are available:
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/292600) in GitLab 13.9.
When the number of billable users reaches the user cap, any user who is added or requests access must be
-[approved](../../user/admin_area/moderate_users.md#approve-or-reject-a-user-sign-up) by an administrator before they can start using
+[approved](../../administration/moderate_users.md#approve-or-reject-a-user-sign-up) by an administrator before they can start using
their account.
If an administrator [increases](#set-the-user-cap-number) or [removes](#remove-the-user-cap) the
diff --git a/doc/administration/settings/user_and_ip_rate_limits.md b/doc/administration/settings/user_and_ip_rate_limits.md
new file mode 100644
index 00000000000..44bd08a8824
--- /dev/null
+++ b/doc/administration/settings/user_and_ip_rate_limits.md
@@ -0,0 +1,240 @@
+---
+stage: none
+group: unassigned
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+type: reference
+---
+
+# User and IP rate limits **(FREE SELF)**
+
+Rate limiting is a common technique used to improve the security and durability
+of a web application. For more details, see
+[Rate limits](../../security/rate_limits.md).
+
+The following limits are disabled by default:
+
+- [Unauthenticated API requests (per IP)](#enable-unauthenticated-api-request-rate-limit).
+- [Unauthenticated web requests (per IP)](#enable-unauthenticated-web-request-rate-limit).
+- [Authenticated API requests (per user)](#enable-authenticated-api-request-rate-limit).
+- [Authenticated web requests (per user)](#enable-authenticated-web-request-rate-limit).
+
+NOTE:
+By default, all Git operations are first tried unauthenticated. Because of this, HTTP Git operations
+may trigger the rate limits configured for unauthenticated requests.
+
+NOTE:
+[In GitLab 14.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/344807),
+the rate limits for API requests don't affect requests made by the frontend, as these are always
+counted as web traffic.
+
+## Enable unauthenticated API request rate limit
+
+To enable the unauthenticated request rate limit:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Settings > Network**.
+1. Expand **User and IP rate limits**.
+1. Select **Enable unauthenticated API request rate limit**.
+
+ - Optional. Update the **Maximum unauthenticated API requests per rate limit period per IP** value.
+ Defaults to `3600`.
+ - Optional. Update the **Unauthenticated rate limit period in seconds** value.
+ Defaults to `3600`.
+
+## Enable unauthenticated web request rate limit
+
+To enable the unauthenticated request rate limit:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Settings > Network**.
+1. Expand **User and IP rate limits**.
+1. Select **Enable unauthenticated web request rate limit**.
+
+ - Optional. Update the **Maximum unauthenticated web requests per rate limit period per IP** value.
+ Defaults to `3600`.
+ - Optional. Update the **Unauthenticated rate limit period in seconds** value.
+ Defaults to `3600`.
+
+## Enable authenticated API request rate limit
+
+To enable the authenticated API request rate limit:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Settings > Network**.
+1. Expand **User and IP rate limits**.
+1. Select **Enable authenticated API request rate limit**.
+
+ - Optional. Update the **Maximum authenticated API requests per rate limit period per user** value.
+ Defaults to `7200`.
+ - Optional. Update the **Authenticated API rate limit period in seconds** value.
+ Defaults to `3600`.
+
+## Enable authenticated web request rate limit
+
+To enable the unauthenticated request rate limit:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Settings > Network**.
+1. Expand **User and IP rate limits**.
+1. Select **Enable authenticated web request rate limit**.
+
+ - Optional. Update the **Maximum authenticated web requests per rate limit period per user** value.
+ Defaults to `7200`.
+ - Optional. Update the **Authenticated web rate limit period in seconds** value.
+ Defaults to `3600`.
+
+## Use a custom rate limit response
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50693) in GitLab 13.8.
+
+A request that exceeds a rate limit returns a `429` response code and a
+plain-text body, which by default is `Retry later`.
+
+To use a custom response:
+
+1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
+1. Select **Admin Area**.
+1. Select **Settings > Network**.
+1. Expand **User and IP rate limits**.
+1. In the **Plain-text response to send to clients that hit a rate limit** text box,
+ add the plain-text response message.
+
+## Response headers
+
+> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/731) in GitLab 13.8, the `RateLimit` headers. `Retry-After` was introduced in an earlier version.
+
+When a client exceeds the associated rate limit, the following requests are
+blocked. The server may respond with rate-limiting information allowing the
+requester to retry after a specific period of time. These information are
+attached into the response headers.
+
+| Header | Example | Description |
+|:----------------------|:--------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `RateLimit-Limit` | `60` | The request quota for the client **each minute**. If the rate limit period set in the Admin Area is different from 1 minute, the value of this header is adjusted to approximately the nearest 60-minute period. |
+| `RateLimit-Name` | `throttle_authenticated_web` | Name of the throttle blocking the requests. |
+| `RateLimit-Observed` | `67` | Number of requests associated to the client in the time window. |
+| `RateLimit-Remaining` | `0` | Remaining quota in the time window. The result of `RateLimit-Limit` - `RateLimit-Observed`. |
+| `RateLimit-Reset` | `1609844400` | [Unix time](https://en.wikipedia.org/wiki/Unix_time)-formatted time when the request quota is reset. |
+| `RateLimit-ResetTime` | `Tue, 05 Jan 2021 11:00:00 GMT` | [RFC2616](https://www.rfc-editor.org/rfc/rfc2616#section-3.3.1)-formatted date and time when the request quota is reset. |
+| `Retry-After` | `30` | Remaining duration **in seconds** until the quota is reset. This is a [standard HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After). |
+
+## Use an HTTP header to bypass rate limiting
+
+> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/622) in GitLab 13.6.
+
+Depending on the needs of your organization, you may want to enable rate limiting
+but have some requests bypass the rate limiter.
+
+You can do this by marking requests that should bypass the rate limiter with a custom
+header. You must do this somewhere in a load balancer or reverse proxy in front of
+GitLab. For example:
+
+1. Pick a name for your bypass header. For example, `Gitlab-Bypass-Rate-Limiting`.
+1. Configure your load balancer to set `Gitlab-Bypass-Rate-Limiting: 1` on requests
+ that should bypass GitLab rate limiting.
+1. Configure your load balancer to either:
+ - Erase `Gitlab-Bypass-Rate-Limiting`.
+ - Set `Gitlab-Bypass-Rate-Limiting` to a value other than `1` on all requests that
+ should be affected by rate limiting.
+1. Set the environment variable `GITLAB_THROTTLE_BYPASS_HEADER`.
+ - For [Linux package installations](https://docs.gitlab.com/omnibus/settings/environment-variables.html),
+ set `'GITLAB_THROTTLE_BYPASS_HEADER' => 'Gitlab-Bypass-Rate-Limiting'` in `gitlab_rails['env']`.
+ - For source installations, set `export GITLAB_THROTTLE_BYPASS_HEADER=Gitlab-Bypass-Rate-Limiting`
+ in `/etc/default/gitlab`.
+
+It is important that your load balancer erases or overwrites the bypass
+header on all incoming traffic. Otherwise, you must trust your
+users to not set that header and bypass the GitLab rate limiter.
+
+The bypass works only if the header is set to `1`.
+
+Requests that bypassed the rate limiter because of the bypass header
+are marked with `"throttle_safelist":"throttle_bypass_header"` in
+[`production_json.log`](../logs/index.md#production_jsonlog).
+
+To disable the bypass mechanism, make sure the environment variable
+`GITLAB_THROTTLE_BYPASS_HEADER` is unset or empty.
+
+## Allow specific users to bypass authenticated request rate limiting
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49127) in GitLab 13.7.
+
+Similarly to the bypass header described above, it is possible to allow
+a certain set of users to bypass the rate limiter. This only applies
+to authenticated requests: with unauthenticated requests, by definition
+GitLab does not know who the user is.
+
+The allowlist is configured as a comma-separated list of user IDs in
+the `GITLAB_THROTTLE_USER_ALLOWLIST` environment variable. If you want
+users 1, 53 and 217 to bypass the authenticated request rate limiter,
+the allowlist configuration would be `1,53,217`.
+
+- For [Linux package installations](https://docs.gitlab.com/omnibus/settings/environment-variables.html),
+ set `'GITLAB_THROTTLE_USER_ALLOWLIST' => '1,53,217'` in `gitlab_rails['env']`.
+- For source installations, set `export GITLAB_THROTTLE_USER_ALLOWLIST=1,53,217`
+ in `/etc/default/gitlab`.
+
+Requests that bypassed the rate limiter because of the user allowlist
+are marked with `"throttle_safelist":"throttle_user_allowlist"` in
+[`production_json.log`](../logs/index.md#production_jsonlog).
+
+At application startup, the allowlist is logged in [`auth.log`](../logs/index.md#authlog).
+
+## Try out throttling settings before enforcing them
+
+> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/629) in GitLab 13.6.
+
+You can try out throttling settings by setting the `GITLAB_THROTTLE_DRY_RUN` environment variable to
+a comma-separated list of throttle names.
+
+The possible names are:
+
+- `throttle_unauthenticated`
+ - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/335300) in GitLab 14.3. Use `throttle_unauthenticated_api` or `throttle_unauthenticated_web` instead.
+ `throttle_unauthenticated` is still supported and selects both of them.
+- `throttle_unauthenticated_api`
+- `throttle_unauthenticated_web`
+- `throttle_authenticated_api`
+- `throttle_authenticated_web`
+- `throttle_unauthenticated_protected_paths`
+- `throttle_authenticated_protected_paths_api`
+- `throttle_authenticated_protected_paths_web`
+- `throttle_unauthenticated_packages_api`
+- `throttle_authenticated_packages_api`
+- `throttle_authenticated_git_lfs`
+- `throttle_unauthenticated_files_api`
+- `throttle_authenticated_files_api`
+- `throttle_unauthenticated_deprecated_api`
+- `throttle_authenticated_deprecated_api`
+
+For example, to try out throttles for all authenticated requests to
+non-protected paths can be done by setting
+`GITLAB_THROTTLE_DRY_RUN='throttle_authenticated_web,throttle_authenticated_api'`.
+
+To enable dry run mode for all throttles, the variable can be set to `*`.
+
+Setting a throttle to dry run mode logs a message to the
+[`auth.log`](../logs/index.md#authlog) when it would hit the limit, while letting the
+request continue. The log message contains an `env` field set to `track`. The `matched`
+field contains the name of throttle that was hit.
+
+It is important to set the environment variable **before** enabling
+the rate limiting in the settings. The settings in the Admin Area
+take effect immediately, while setting the environment variable
+requires a restart of all the Puma processes.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, for example `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index aa2607e259b..8d925bdf6ff 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -16604,6 +16604,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
| <a id="groupprojectsincludesubgroups"></a>`includeSubgroups` | [`Boolean`](#boolean) | Include also subgroup projects. |
| <a id="groupprojectsnotaimedfordeletion"></a>`notAimedForDeletion` | [`Boolean`](#boolean) | Include projects that are not aimed for deletion. |
+| <a id="groupprojectssbomcomponentid"></a>`sbomComponentId` | [`ID`](#id) | Return only the projects related to the specified SBOM component. |
| <a id="groupprojectssearch"></a>`search` | [`String`](#string) | Search project with most similar names or paths. |
| <a id="groupprojectssort"></a>`sort` | [`NamespaceProjectSort`](#namespaceprojectsort) | Sort projects by this criteria. |
| <a id="groupprojectswithissuesenabled"></a>`withIssuesEnabled` | [`Boolean`](#boolean) | Return only projects with issues enabled. |
@@ -19227,6 +19228,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="namespaceprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
| <a id="namespaceprojectsincludesubgroups"></a>`includeSubgroups` | [`Boolean`](#boolean) | Include also subgroup projects. |
| <a id="namespaceprojectsnotaimedfordeletion"></a>`notAimedForDeletion` | [`Boolean`](#boolean) | Include projects that are not aimed for deletion. |
+| <a id="namespaceprojectssbomcomponentid"></a>`sbomComponentId` | [`ID`](#id) | Return only the projects related to the specified SBOM component. |
| <a id="namespaceprojectssearch"></a>`search` | [`String`](#string) | Search project with most similar names or paths. |
| <a id="namespaceprojectssort"></a>`sort` | [`NamespaceProjectSort`](#namespaceprojectsort) | Sort projects by this criteria. |
| <a id="namespaceprojectswithissuesenabled"></a>`withIssuesEnabled` | [`Boolean`](#boolean) | Return only projects with issues enabled. |
diff --git a/doc/api/group_access_tokens.md b/doc/api/group_access_tokens.md
index 2493dfcc039..4904785c2f0 100644
--- a/doc/api/group_access_tokens.md
+++ b/doc/api/group_access_tokens.md
@@ -152,6 +152,11 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
- Token with the specified ID does not exist.
- `404: Not Found` if the user is an administrator but the token with the specified ID does not exist.
+### Automatic reuse detection
+
+Refer to [automatic reuse detection for personal access tokens](personal_access_tokens.md#automatic-reuse-detection)
+for more information.
+
## Revoke a group access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77236) in GitLab 14.7.
diff --git a/doc/api/personal_access_tokens.md b/doc/api/personal_access_tokens.md
index 691c094f9eb..a6b319bb8f1 100644
--- a/doc/api/personal_access_tokens.md
+++ b/doc/api/personal_access_tokens.md
@@ -235,6 +235,21 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
- Token with the specified ID does not exist.
- `404: Not Found` if the user is an administrator but the token with the specified ID does not exist.
+### Automatic reuse detection
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/395352) in GitLab 16.2
+
+For each rotated token, the previous and now revoked token is referenced. This
+chain of references defines a token family. In a token family, only the latest
+token is active, and all other tokens in that family are revoked.
+
+When a revoked token from a token family is used in an authentication attempt,
+that attempt fails and the active token from the token family gets revoked.
+This mechanism helps to prevent compromise when a personal access token is
+leaked.
+
+Automatic reuse detection is enabled for API requests.
+
## Revoke a personal access token
Revoke a personal access token by either:
diff --git a/doc/api/project_access_tokens.md b/doc/api/project_access_tokens.md
index 36129bf6576..5cb4276fa1d 100644
--- a/doc/api/project_access_tokens.md
+++ b/doc/api/project_access_tokens.md
@@ -161,6 +161,11 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
- Token with the specified ID does not exist.
- `404: Not Found` if the user is an administrator but the token with the specified ID does not exist.
+### Automatic reuse detection
+
+Refer to [automatic reuse detection for personal access tokens](personal_access_tokens.md#automatic-reuse-detection)
+for more information.
+
## Revoke a project access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9.
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 66993d4adfa..f7966a404f2 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -324,7 +324,7 @@ listed in the descriptions of the relevant settings.
| `container_registry_expiration_policies_worker_capacity` | integer | no | Number of workers for [cleanup policies](../user/packages/container_registry/reduce_container_registry_storage.md#set-cleanup-limits-to-conserve-resources). |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes. |
| `package_registry_cleanup_policies_worker_capacity` | integer | no | Number of workers assigned to the packages cleanup policies. |
-| `deactivate_dormant_users` | boolean | no | Enable [automatic deactivation of dormant users](../user/admin_area/moderate_users.md#automatically-deactivate-dormant-users). |
+| `deactivate_dormant_users` | boolean | no | Enable [automatic deactivation of dormant users](../administration/moderate_users.md#automatically-deactivate-dormant-users). |
| `deactivate_dormant_users_period` | integer | no | Length of time (in days) after which a user is considered dormant. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336747) in GitLab 15.3. |
| `default_artifacts_expire_in` | string | no | Set the default expiration time for each job's artifacts. |
| `default_branch_name` | string | no | [Instance-level custom initial branch name](../user/project/repository/branches/default.md#instance-level-custom-initial-branch-name). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225258) in GitLab 13.2. |
@@ -493,7 +493,7 @@ listed in the descriptions of the relevant settings.
| `repository_size_limit` **(PREMIUM)** | integer | no | Size limit per repository (MB) |
| `repository_storages_weighted` | hash of strings to integers | no | (GitLab 13.1 and later) Hash of names of taken from `gitlab.yml` to [weights](../administration/repository_storage_paths.md#configure-where-new-repositories-are-stored). New projects are created in one of these stores, chosen by a weighted random selection. |
| `repository_storages` | array of strings | no | (GitLab 13.0 and earlier) List of names of enabled storage paths, taken from `gitlab.yml`. New projects are created in one of these stores, chosen at random. |
-| `require_admin_approval_after_user_signup` | boolean | no | When enabled, any user that signs up for an account using the registration form is placed under a **Pending approval** state and has to be explicitly [approved](../user/admin_area/moderate_users.md) by an administrator. |
+| `require_admin_approval_after_user_signup` | boolean | no | When enabled, any user that signs up for an account using the registration form is placed under a **Pending approval** state and has to be explicitly [approved](../administration/moderate_users.md) by an administrator. |
| `require_two_factor_authentication` | boolean | no | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. |
| `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-Administrator users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. |
| `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. |
diff --git a/doc/api/users.md b/doc/api/users.md
index 1897c23f813..d66340cb255 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1755,7 +1755,7 @@ Returns:
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` when trying to deactivate a user that is:
- Blocked by administrator or by LDAP synchronization.
- - Not [dormant](../user/admin_area/moderate_users.md#automatically-deactivate-dormant-users).
+ - Not [dormant](../administration/moderate_users.md#automatically-deactivate-dormant-users).
- Internal.
## Activate user **(FREE SELF)**
@@ -1924,7 +1924,7 @@ Example Responses:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339925) in GitLab 14.3.
-Rejects specified user that is [pending approval](../user/admin_area/moderate_users.md#users-pending-approval). Available only for administrators.
+Rejects specified user that is [pending approval](../administration/moderate_users.md#users-pending-approval). Available only for administrators.
```plaintext
POST /users/:id/reject
diff --git a/doc/architecture/blueprints/work_items/index.md b/doc/architecture/blueprints/work_items/index.md
index cd74003c912..9924b0db9f4 100644
--- a/doc/architecture/blueprints/work_items/index.md
+++ b/doc/architecture/blueprints/work_items/index.md
@@ -74,7 +74,7 @@ All Work Item types share the same pool of predefined widgets and are customized
| start and due date | |
| status\* | |
| weight | |
-| [notes](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) | work_items_mvc |
+| [notes](https://gitlab.com/gitlab-org/gitlab/-/issues/378949) | |
\* status is not currently a widget, but a part of the root work item, similar to title
diff --git a/doc/development/internal_analytics/snowplow/infrastructure.md b/doc/development/internal_analytics/snowplow/infrastructure.md
index 9679abac6b7..462dee2c39b 100644
--- a/doc/development/internal_analytics/snowplow/infrastructure.md
+++ b/doc/development/internal_analytics/snowplow/infrastructure.md
@@ -55,7 +55,7 @@ In contrast to a typical Snowplow pipeline, after enrichment, GitLab Snowplow ev
#### Why events need to be pseudonymized
GitLab is bound by its [obligations to community](https://about.gitlab.com/handbook/product/analytics-instrumentation-guide/service-usage-data-commitment/)
-and by [legal regulations](https://about.gitlab.com/handbook/legal/privacy/services-usage-data/) to protect the privacy of its users.
+and by [legal regulations](https://about.gitlab.com/handbook/legal/privacy/customer-product-usage-information/) to protect the privacy of its users.
GitLab must provide valuable insights for business decisions, and there is a need
for a better understanding of different users' behavior patterns. The
diff --git a/doc/development/jh_features_review.md b/doc/development/jh_features_review.md
index 7e90d79c067..f4ed7070948 100644
--- a/doc/development/jh_features_review.md
+++ b/doc/development/jh_features_review.md
@@ -99,6 +99,20 @@ the relevant EE and JH modules by the name of the receiver module.
If reviewing the corresponding JH file is needed, it should be found at
[JH repository](https://jihulab.com/gitlab-cn/gitlab).
+NOTE:
+In some cases, JH does need to override something we don't need, and in that
+case it is ok to also add `prepend_mod` for the modules. When we do this,
+also add a comment mentioning it, and a link to the JH module using it.
+This way we know where it's used and when we might not need it anymore,
+and we do not remove them only because we're not using it, accidentally
+breaking JH. An example of this:
+
+```ruby
+# Added for JiHu
+# Used in https://jihulab.com/gitlab-cn/gitlab/-/blob/main-jh/jh/lib/jh/api/integrations.rb
+API::Integrations.prepend_mod
+```
+
### General guidance for writing JH extensions
See [Guidelines for implementing Enterprise Edition features](ee_features.md)
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 2a871b97a28..0389b91fc70 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -47,7 +47,7 @@ Linux package, Docker, and self-compiled | Helm chart | Description | Default va
----------------------------|------------|-------------|-----------
`allow_single_sign_on` | `allowSingleSignOn` | List of providers that automatically create a GitLab account. The provider names are available in the **OmniAuth provider name** column in the [supported providers table](#supported-providers). | `false`, which means that signing in using your OmniAuth provider account without a pre-existing GitLab account is not allowed. You must create a GitLab account first, and then connect it to your OmniAuth provider account through your profile settings.
`auto_link_ldap_user` | `autoLinkLdapUser` | Creates an LDAP identity in GitLab for users that are created through an OmniAuth provider. You can enable this setting if you have [LDAP integration](../administration/auth/ldap/index.md) enabled. Requires the `uid` of the user to be the same in both LDAP and the OmniAuth provider. | `false`
-`block_auto_created_users` | `blockAutoCreatedUsers` | Places automatically-created users in a [Pending approval](../user/admin_area/moderate_users.md#users-pending-approval) state (unable to sign in) until they are approved by an administrator. | `true`. If you set the value to `false`, make sure you define providers that you can control, like SAML or Google. Otherwise, any user on the internet can sign in to GitLab without an administrator's approval.
+`block_auto_created_users` | `blockAutoCreatedUsers` | Places automatically-created users in a [Pending approval](../administration/moderate_users.md#users-pending-approval) state (unable to sign in) until they are approved by an administrator. | `true`. If you set the value to `false`, make sure you define providers that you can control, like SAML or Google. Otherwise, any user on the internet can sign in to GitLab without an administrator's approval.
### Configure initial settings
diff --git a/doc/security/responding_to_security_incidents.md b/doc/security/responding_to_security_incidents.md
index 5c00c53c5bf..c3f8d6026d4 100644
--- a/doc/security/responding_to_security_incidents.md
+++ b/doc/security/responding_to_security_incidents.md
@@ -14,7 +14,7 @@ additional steps. These suggestions are intended to supplement existing security
If you suspect that a user account or bot account has been compromised, consider taking the following steps:
-- [Block the user](../user/admin_area/moderate_users.md#block-a-user) to mitigate any current risk.
+- [Block the user](../administration/moderate_users.md#block-a-user) to mitigate any current risk.
- [Review the audit events](../administration/audit_events.md) available to you to identify any suspicious account behavior. For
example:
- Suspicious sign-in events.
@@ -44,7 +44,7 @@ hosts in accordance with vendor guidance.
If you suspect that your GitLab instance has been compromised, consider taking the following steps:
- [Review the audit events](../administration/audit_events.md) available to you for suspicious account behavior.
-- [Review all users](../user/admin_area/moderate_users.md) (including the Administrative root user), and follow the steps in [Suspected compromised user account](#suspected-compromised-user-account) if necessary.
+- [Review all users](../administration/moderate_users.md) (including the Administrative root user), and follow the steps in [Suspected compromised user account](#suspected-compromised-user-account) if necessary.
- Review the [Credentials Inventory](../user/admin_area/credentials_inventory.md), if available to you.
- Change any sensitive credentials, variables, tokens, and secrets. For example, those located in instance configuration, database,
CI/CD pipelines, or elsewhere.
diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md
index 05194db8781..8366e9a701c 100644
--- a/doc/subscriptions/self_managed/index.md
+++ b/doc/subscriptions/self_managed/index.md
@@ -47,10 +47,10 @@ The lists of users are displayed.
A _billable user_ counts against the number of subscription seats. Every user is considered a
billable user, with the following exceptions:
-- [Deactivated users](../../user/admin_area/moderate_users.md#deactivate-a-user) and
- [blocked users](../../user/admin_area/moderate_users.md#block-a-user) don't count as billable users in the current subscription. When they are either deactivated or blocked they release a _billable user_ seat. However, they may
+- [Deactivated users](../../administration/moderate_users.md#deactivate-a-user) and
+ [blocked users](../../administration/moderate_users.md#block-a-user) don't count as billable users in the current subscription. When they are either deactivated or blocked they release a _billable user_ seat. However, they may
count toward overages in the subscribed seat count.
-- Users who are [pending approval](../../user/admin_area/moderate_users.md#users-pending-approval).
+- Users who are [pending approval](../../administration/moderate_users.md#users-pending-approval).
- Users with only the [Minimal Access role](../../user/permissions.md#users-with-minimal-access) on self-managed Ultimate subscriptions or any GitLab.com subscriptions.
- Users with only the [Guest or Minimal Access roles on an Ultimate subscription](#free-guest-users).
- Users without project or group memberships on an Ultimate subscription.
@@ -354,7 +354,7 @@ Starting 30 days before a subscription expires, a banner with the expiry date di
You should follow these steps during renewal:
-1. Prior to the renewal date, prune any inactive or unwanted users by [blocking them](../../user/admin_area/moderate_users.md#block-a-user).
+1. Prior to the renewal date, prune any inactive or unwanted users by [blocking them](../../administration/moderate_users.md#block-a-user).
1. Determine if you have a need for user growth in the upcoming subscription.
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) and select the **Renew** button beneath your existing subscription.
The **Renew** button remains disabled (grayed-out) until 15 days before a subscription expires.
diff --git a/doc/user/admin_area/moderate_users.md b/doc/user/admin_area/moderate_users.md
index 4e3faeee8d3..3390c4791be 100644
--- a/doc/user/admin_area/moderate_users.md
+++ b/doc/user/admin_area/moderate_users.md
@@ -1,393 +1,11 @@
---
-stage: Manage
-group: Authentication and Authorization
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-type: howto
+redirect_to: '../../administration/moderate_users.md'
+remove_date: '2023-10-12'
---
-# Moderate users (administration) **(FREE SELF)**
+This document was moved to [another location](../../administration/moderate_users.md).
-This is the administration documentation. For information about moderating users at the group level, see the [group-level documentation](../group/moderate_users.md).
-
-GitLab administrators can moderate user access by approving, blocking, banning, or deactivating
-users.
-
-## Users pending approval
-
-A user in _pending approval_ state requires action by an administrator. A user sign up can be in a
-pending approval state because an administrator has enabled any of the following options:
-
-- [Require administrator approval for new sign-ups](../../administration/settings/sign_up_restrictions.md#require-administrator-approval-for-new-sign-ups) setting.
-- [User cap](../../administration/settings/sign_up_restrictions.md#user-cap).
-- [Block auto-created users (OmniAuth)](../../integration/omniauth.md#configure-common-settings)
-- [Block auto-created users (LDAP)](../../administration/auth/ldap/index.md#basic-configuration-settings)
-
-When a user registers for an account while this setting is enabled:
-
-- The user is placed in a **Pending approval** state.
-- The user sees a message telling them their account is awaiting approval by an administrator.
-
-A user pending approval:
-
-- Is functionally identical to a [blocked](#block-a-user) user.
-- Cannot sign in.
-- Cannot access Git repositories or the GitLab API.
-- Does not receive any notifications from GitLab.
-- Does not consume a [seat](../../subscriptions/self_managed/index.md#billable-users).
-
-An administrator must [approve their sign up](#approve-or-reject-a-user-sign-up) to allow them to
-sign in.
-
-### View user sign ups pending approval
-
-To view user sign ups pending approval:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Pending approval** tab.
-
-### Approve or reject a user sign up
-
-A user sign up pending approval can be approved or rejected from the Admin Area.
-
-To approve or reject a user sign up:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Pending approval** tab.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Approve** or **Reject**.
-
-Approving a user:
-
-- Activates their account.
-- Changes the user's state to active.
-- Consumes a subscription [seat](../../subscriptions/self_managed/index.md#billable-users).
-
-## Block and unblock users
-
-GitLab administrators can block and unblock users.
-
-### Block a user
-
-To completely prevent access of a user to the GitLab instance,
-administrators can choose to block the user.
-
-Users can be blocked [via an abuse report](../../administration/review_abuse_reports.md#blocking-users),
-by removing them in LDAP, or directly from the Admin Area. To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Block**.
-
-A blocked user:
-
-- Cannot sign in.
-- Cannot access Git repositories or the API.
-- Does not receive any notifications from GitLab.
-- Cannot use [slash commands](../../user/project/integrations/gitlab_slack_application.md#slash-commands).
-- Does not consume a [seat](../../subscriptions/self_managed/index.md#billable-users).
-
-Personal projects, and group and user history of the blocked user are left intact.
-
-NOTE:
-Users can also be blocked using the [GitLab API](../../api/users.md#block-user).
-
-### Unblock a user
-
-A blocked user can be unblocked from the Admin Area. To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Blocked** tab.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Unblock**.
-
-The user's state is set to active and they consume a
-[seat](../../subscriptions/self_managed/index.md#billable-users).
-
-NOTE:
-Users can also be unblocked using the [GitLab API](../../api/users.md#unblock-user).
-
-The unblock option may be unavailable for LDAP users. To enable the unblock option,
-the LDAP identity first needs to be deleted:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Blocked** tab.
-1. Select a user.
-1. Select the **Identities** tab.
-1. Find the LDAP provider and select **Delete**.
-
-## Activate and deactivate users
-
-GitLab administrators can deactivate and activate users.
-
-### Deactivate a user
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22257) in GitLab 12.4.
-
-To temporarily prevent access by a GitLab user that has no recent activity,
-administrators can choose to deactivate the user.
-
-Deactivating a user is functionally identical to [blocking a user](#block-and-unblock-users),
-with the following differences:
-
-- It does not prohibit the user from logging back in via the UI.
-- Once a deactivated user logs back into the GitLab UI, their account is set to active.
-
-A deactivated user:
-
-- Cannot access Git repositories or the API.
-- Does not receive any notifications from GitLab.
-- Cannot use [slash commands](../../user/project/integrations/gitlab_slack_application.md#slash-commands).
-- Does not consume a [seat](../../subscriptions/self_managed/index.md#billable-users).
-
-Personal projects, and group and user history of the deactivated user are left intact.
-
-NOTE:
-Users are notified about account deactivation if
-[user deactivation emails](settings/email.md#user-deactivation-emails) are enabled.
-
-A user can be deactivated from the Admin Area. To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Deactivate**.
-
-For the deactivation option to be visible to an administrator, the user:
-
-- Must have a state of active.
-- Must be [dormant](#automatically-deactivate-dormant-users).
-
-NOTE:
-Users can also be deactivated using the [GitLab API](../../api/users.md#deactivate-user).
-
-### Automatically deactivate dormant users
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/320875) in GitLab 14.0.
-> - Exclusion of GitLab generate bots [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340346) in GitLab 14.5
-> - Customizable time period [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336747) in GitLab 15.4
-> - The lower limit for inactive period set to 90 days [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100793) in GitLab 15.5
-
-Administrators can enable automatic deactivation of users who either:
-
-- Were created more than a week ago and have not signed in.
-- Have no activity for a specified period of time (default and minimum is 90 days).
-
-To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > General**.
-1. Expand the **Account and limit** section.
-1. Under **Dormant users**, check **Deactivate dormant users after a period of inactivity**.
-1. Under **Days of inactivity before deactivation**, enter the number of days before deactivation. Minimum value is 90 days.
-1. Select **Save changes**.
-
-When this feature is enabled, GitLab runs a job once a day to deactivate the dormant users.
-
-A maximum of 100,000 users can be deactivated per day.
-
-NOTE:
-GitLab generated bots are excluded from the automatic deactivation of dormant users.
-
-### Automatically delete unconfirmed users **(PREMIUM SELF)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352514) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `delete_unconfirmed_users_setting`. Disabled by default.
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/124982) in GitLab 16.2.
-
-Prerequisites:
-
-- You must be an administrator.
-
-You can enable automatic deletion of users who both:
-
-- Never confirmed their email address.
-- Signed up for GitLab more than a specified number of days in the past.
-
-You can configure these settings using either the [Settings API](../../api/settings.md) or in a Rails console:
-
-```ruby
- Gitlab::CurrentSettings.update(delete_unconfirmed_users: true)
- Gitlab::CurrentSettings.update(unconfirmed_users_delete_after_days: 365)
-```
-
-When the `delete_unconfirmed_users` setting is enabled, GitLab runs a job once an hour to delete the unconfirmed users.
-The job only deletes users who signed up more than `unconfirmed_users_delete_after_days` days in the past.
-
-This job only runs when the `email_confirmation_setting` is set to `soft` or `hard`.
-
-A maximum of 240,000 users can be deleted per day.
-
-### Activate a user
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22257) in GitLab 12.4.
-
-A deactivated user can be activated from the Admin Area.
-
-To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Deactivated** tab.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Activate**.
-
-The user's state is set to active and they consume a
-[seat](../../subscriptions/self_managed/index.md#billable-users).
-
-NOTE:
-A deactivated user can also activate their account themselves by logging back in via the UI.
-Users can also be activated using the [GitLab API](../../api/users.md#activate-user).
-
-## Ban and unban users
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327353) in GitLab 14.2 [with a flag](../../administration/feature_flags.md) named `ban_user_feature_flag`. Disabled by default.
-> - Ban and unban users [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/327353) in GitLab 14.8. Feature flag `ban_user_feature_flag` removed.
-> - Hiding merge requests of banned users [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107836) in GitLab 15.8 [with a flag](../../administration/feature_flags.md) named `hide_merge_requests_from_banned_users`. Disabled by default.
-> - Hiding comments of banned users [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/112973) in GitLab 15.11 [with a flag](../../administration/feature_flags.md) named `hidden_notes`. Disabled by default.
-> - Hiding projects of banned users [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121488) in GitLab 16.2 [with a flag](../../administration/feature_flags.md) named `hide_projects_of_banned_users`. Disabled by default.
-
-GitLab administrators can ban and unban users. Banned users are blocked, and their projects, issues, merge requests, and comments are hidden.
-
-### Ban a user
-
-To block a user and hide their contributions, administrators can ban the user.
-
-Users can be banned using the Admin Area. To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Ban user**.
-
-The banned user does not consume a [seat](../../subscriptions/self_managed/index.md#billable-users).
-
-### Unban a user
-
-A banned user can be unbanned using the Admin Area. To do this:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Banned** tab.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Unban user**.
-
-The user's state is set to active and they consume a
-[seat](../../subscriptions/self_managed/index.md#billable-users).
-
-### Delete a user
-
-Use the Admin Area to delete users.
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Banned** tab.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Delete user**.
-1. Type the username.
-1. Select **Delete user**.
-
-NOTE:
-You can only delete a user if there are inherited or direct owners of a group. You cannot delete a user if they are the only group owner.
-
-You can also delete a user and their contributions, such as merge requests, issues, and groups of which they are the only group owner.
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Overview > Users**.
-1. Select the **Banned** tab.
-1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown list.
-1. Select **Delete user and contributions**.
-1. Type the username.
-1. Select **Delete user and contributions**.
-
-NOTE:
-Before 15.1, additionally groups of which deleted user were the only owner among direct members were deleted.
-
-## Troubleshooting
-
-When moderating users, you may need to perform bulk actions on them based on certain conditions. The following rails console scripts show some examples of this. You may [start a rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session) and use scripts similar to the following:
-
-### Deactivate users that have no recent activity
-
-Administrators can deactivate users that have no recent activity.
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-
-```ruby
-days_inactive = 90
-inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
-
-inactive_users.each do |user|
- puts "user '#{user.username}': #{user.last_activity_on}"
- user.deactivate!
-end
-```
-
-### Block users that have no recent activity
-
-Administrators can block users that have no recent activity.
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-
-```ruby
-days_inactive = 90
-inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
-
-inactive_users.each do |user|
- puts "user '#{user.username}': #{user.last_activity_on}"
- user.block!
-end
-```
-
-### Block or delete users that have no projects or groups
-
-Administrators can block or delete users that have no projects or groups.
-
-WARNING:
-Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
-
-```ruby
-users = User.where('id NOT IN (select distinct(user_id) from project_authorizations)')
-
-# How many users are removed?
-users.count
-
-# If that count looks sane:
-
-# You can either block the users:
-users.each { |user| user.blocked? ? nil : user.block! }
-
-# Or you can delete them:
- # need 'current user' (your user) for auditing purposes
-current_user = User.find_by(username: '<your username>')
-
-users.each do |user|
- DeleteUserWorker.perform_async(current_user.id, user.id)
-end
-```
+<!-- This redirect file can be deleted after <2023-10-12>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/admin_area/settings/user_and_ip_rate_limits.md b/doc/user/admin_area/settings/user_and_ip_rate_limits.md
index d145c351f3e..fae47358879 100644
--- a/doc/user/admin_area/settings/user_and_ip_rate_limits.md
+++ b/doc/user/admin_area/settings/user_and_ip_rate_limits.md
@@ -1,240 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-type: reference
+redirect_to: '../../../administration/settings/user_and_ip_rate_limits.md'
+remove_date: '2023-10-14'
---
-# User and IP rate limits **(FREE SELF)**
+This document was moved to [another location](../../../administration/settings/user_and_ip_rate_limits.md).
-Rate limiting is a common technique used to improve the security and durability
-of a web application. For more details, see
-[Rate limits](../../../security/rate_limits.md).
-
-The following limits are disabled by default:
-
-- [Unauthenticated API requests (per IP)](#enable-unauthenticated-api-request-rate-limit).
-- [Unauthenticated web requests (per IP)](#enable-unauthenticated-web-request-rate-limit).
-- [Authenticated API requests (per user)](#enable-authenticated-api-request-rate-limit).
-- [Authenticated web requests (per user)](#enable-authenticated-web-request-rate-limit).
-
-NOTE:
-By default, all Git operations are first tried unauthenticated. Because of this, HTTP Git operations
-may trigger the rate limits configured for unauthenticated requests.
-
-NOTE:
-[In GitLab 14.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/344807),
-the rate limits for API requests don't affect requests made by the frontend, as these are always
-counted as web traffic.
-
-## Enable unauthenticated API request rate limit
-
-To enable the unauthenticated request rate limit:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > Network**.
-1. Expand **User and IP rate limits**.
-1. Select **Enable unauthenticated API request rate limit**.
-
- - Optional. Update the **Maximum unauthenticated API requests per rate limit period per IP** value.
- Defaults to `3600`.
- - Optional. Update the **Unauthenticated rate limit period in seconds** value.
- Defaults to `3600`.
-
-## Enable unauthenticated web request rate limit
-
-To enable the unauthenticated request rate limit:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > Network**.
-1. Expand **User and IP rate limits**.
-1. Select **Enable unauthenticated web request rate limit**.
-
- - Optional. Update the **Maximum unauthenticated web requests per rate limit period per IP** value.
- Defaults to `3600`.
- - Optional. Update the **Unauthenticated rate limit period in seconds** value.
- Defaults to `3600`.
-
-## Enable authenticated API request rate limit
-
-To enable the authenticated API request rate limit:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > Network**.
-1. Expand **User and IP rate limits**.
-1. Select **Enable authenticated API request rate limit**.
-
- - Optional. Update the **Maximum authenticated API requests per rate limit period per user** value.
- Defaults to `7200`.
- - Optional. Update the **Authenticated API rate limit period in seconds** value.
- Defaults to `3600`.
-
-## Enable authenticated web request rate limit
-
-To enable the unauthenticated request rate limit:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > Network**.
-1. Expand **User and IP rate limits**.
-1. Select **Enable authenticated web request rate limit**.
-
- - Optional. Update the **Maximum authenticated web requests per rate limit period per user** value.
- Defaults to `7200`.
- - Optional. Update the **Authenticated web rate limit period in seconds** value.
- Defaults to `3600`.
-
-## Use a custom rate limit response
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50693) in GitLab 13.8.
-
-A request that exceeds a rate limit returns a `429` response code and a
-plain-text body, which by default is `Retry later`.
-
-To use a custom response:
-
-1. On the left sidebar, expand the top-most chevron (**{chevron-down}**).
-1. Select **Admin Area**.
-1. Select **Settings > Network**.
-1. Expand **User and IP rate limits**.
-1. In the **Plain-text response to send to clients that hit a rate limit** text box,
- add the plain-text response message.
-
-## Response headers
-
-> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/731) in GitLab 13.8, the `RateLimit` headers. `Retry-After` was introduced in an earlier version.
-
-When a client exceeds the associated rate limit, the following requests are
-blocked. The server may respond with rate-limiting information allowing the
-requester to retry after a specific period of time. These information are
-attached into the response headers.
-
-| Header | Example | Description |
-|:----------------------|:--------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `RateLimit-Limit` | `60` | The request quota for the client **each minute**. If the rate limit period set in the Admin Area is different from 1 minute, the value of this header is adjusted to approximately the nearest 60-minute period. |
-| `RateLimit-Name` | `throttle_authenticated_web` | Name of the throttle blocking the requests. |
-| `RateLimit-Observed` | `67` | Number of requests associated to the client in the time window. |
-| `RateLimit-Remaining` | `0` | Remaining quota in the time window. The result of `RateLimit-Limit` - `RateLimit-Observed`. |
-| `RateLimit-Reset` | `1609844400` | [Unix time](https://en.wikipedia.org/wiki/Unix_time)-formatted time when the request quota is reset. |
-| `RateLimit-ResetTime` | `Tue, 05 Jan 2021 11:00:00 GMT` | [RFC2616](https://www.rfc-editor.org/rfc/rfc2616#section-3.3.1)-formatted date and time when the request quota is reset. |
-| `Retry-After` | `30` | Remaining duration **in seconds** until the quota is reset. This is a [standard HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After). |
-
-## Use an HTTP header to bypass rate limiting
-
-> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/622) in GitLab 13.6.
-
-Depending on the needs of your organization, you may want to enable rate limiting
-but have some requests bypass the rate limiter.
-
-You can do this by marking requests that should bypass the rate limiter with a custom
-header. You must do this somewhere in a load balancer or reverse proxy in front of
-GitLab. For example:
-
-1. Pick a name for your bypass header. For example, `Gitlab-Bypass-Rate-Limiting`.
-1. Configure your load balancer to set `Gitlab-Bypass-Rate-Limiting: 1` on requests
- that should bypass GitLab rate limiting.
-1. Configure your load balancer to either:
- - Erase `Gitlab-Bypass-Rate-Limiting`.
- - Set `Gitlab-Bypass-Rate-Limiting` to a value other than `1` on all requests that
- should be affected by rate limiting.
-1. Set the environment variable `GITLAB_THROTTLE_BYPASS_HEADER`.
- - For [Linux package installations](https://docs.gitlab.com/omnibus/settings/environment-variables.html),
- set `'GITLAB_THROTTLE_BYPASS_HEADER' => 'Gitlab-Bypass-Rate-Limiting'` in `gitlab_rails['env']`.
- - For source installations, set `export GITLAB_THROTTLE_BYPASS_HEADER=Gitlab-Bypass-Rate-Limiting`
- in `/etc/default/gitlab`.
-
-It is important that your load balancer erases or overwrites the bypass
-header on all incoming traffic. Otherwise, you must trust your
-users to not set that header and bypass the GitLab rate limiter.
-
-The bypass works only if the header is set to `1`.
-
-Requests that bypassed the rate limiter because of the bypass header
-are marked with `"throttle_safelist":"throttle_bypass_header"` in
-[`production_json.log`](../../../administration/logs/index.md#production_jsonlog).
-
-To disable the bypass mechanism, make sure the environment variable
-`GITLAB_THROTTLE_BYPASS_HEADER` is unset or empty.
-
-## Allow specific users to bypass authenticated request rate limiting
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49127) in GitLab 13.7.
-
-Similarly to the bypass header described above, it is possible to allow
-a certain set of users to bypass the rate limiter. This only applies
-to authenticated requests: with unauthenticated requests, by definition
-GitLab does not know who the user is.
-
-The allowlist is configured as a comma-separated list of user IDs in
-the `GITLAB_THROTTLE_USER_ALLOWLIST` environment variable. If you want
-users 1, 53 and 217 to bypass the authenticated request rate limiter,
-the allowlist configuration would be `1,53,217`.
-
-- For [Linux package installations](https://docs.gitlab.com/omnibus/settings/environment-variables.html),
- set `'GITLAB_THROTTLE_USER_ALLOWLIST' => '1,53,217'` in `gitlab_rails['env']`.
-- For source installations, set `export GITLAB_THROTTLE_USER_ALLOWLIST=1,53,217`
- in `/etc/default/gitlab`.
-
-Requests that bypassed the rate limiter because of the user allowlist
-are marked with `"throttle_safelist":"throttle_user_allowlist"` in
-[`production_json.log`](../../../administration/logs/index.md#production_jsonlog).
-
-At application startup, the allowlist is logged in [`auth.log`](../../../administration/logs/index.md#authlog).
-
-## Try out throttling settings before enforcing them
-
-> [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/629) in GitLab 13.6.
-
-You can try out throttling settings by setting the `GITLAB_THROTTLE_DRY_RUN` environment variable to
-a comma-separated list of throttle names.
-
-The possible names are:
-
-- `throttle_unauthenticated`
- - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/335300) in GitLab 14.3. Use `throttle_unauthenticated_api` or `throttle_unauthenticated_web` instead.
- `throttle_unauthenticated` is still supported and selects both of them.
-- `throttle_unauthenticated_api`
-- `throttle_unauthenticated_web`
-- `throttle_authenticated_api`
-- `throttle_authenticated_web`
-- `throttle_unauthenticated_protected_paths`
-- `throttle_authenticated_protected_paths_api`
-- `throttle_authenticated_protected_paths_web`
-- `throttle_unauthenticated_packages_api`
-- `throttle_authenticated_packages_api`
-- `throttle_authenticated_git_lfs`
-- `throttle_unauthenticated_files_api`
-- `throttle_authenticated_files_api`
-- `throttle_unauthenticated_deprecated_api`
-- `throttle_authenticated_deprecated_api`
-
-For example, to try out throttles for all authenticated requests to
-non-protected paths can be done by setting
-`GITLAB_THROTTLE_DRY_RUN='throttle_authenticated_web,throttle_authenticated_api'`.
-
-To enable dry run mode for all throttles, the variable can be set to `*`.
-
-Setting a throttle to dry run mode logs a message to the
-[`auth.log`](../../../administration/logs/index.md#authlog) when it would hit the limit, while letting the
-request continue. The log message contains an `env` field set to `track`. The `matched`
-field contains the name of throttle that was hit.
-
-It is important to set the environment variable **before** enabling
-the rate limiting in the settings. The settings in the Admin Area
-take effect immediately, while setting the environment variable
-requires a restart of all the Puma processes.
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, for example `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+<!-- This redirect file can be deleted after <2023-10-14>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/ai_features.md b/doc/user/ai_features.md
index be4bfc5468c..b9bcaec8b57 100644
--- a/doc/user/ai_features.md
+++ b/doc/user/ai_features.md
@@ -46,20 +46,14 @@ The following feature is in Beta:
## Experiment AI features
-[Experiment features](../policy/experiment-beta-support.md#experiment) will soon require
-[Experiment features to be enabled](group/manage.md#enable-experiment-features).
-
-## Third-party AI features
-
-Third-party AI features require [third-party AI services to be enabled](group/manage.md#enable-third-party-ai-features).
-
-For Experiment third-party AI features, [Experiment features must be enabled](group/manage.md#enable-experiment-features) as well.
+[Experiment](../policy/experiment-beta-support.md#experiment) AI features require
+[Experiment features to be enabled](group/manage.md#enable-experiment-features) as well as [third-party AI services to be enabled](group/manage.md#enable-third-party-ai-features).
### Explain Selected Code in the Web UI **(ULTIMATE SAAS)**
> Introduced in GitLab 15.11 as an [Experiment](../policy/experiment-beta-support.md#experiment) on GitLab.com.
-This feature is an [Experiment](../policy/experiment-beta-support.md) on GitLab.com that is powered by OpenAI's GPT-3.
+This AI feature is an [Experiment](../policy/experiment-beta-support.md) on GitLab.com that is powered by Google's Codey for Code Chat (codechat-bison).
GitLab can help you get up to speed faster if you:
@@ -70,9 +64,11 @@ By using a large language model, GitLab can explain the code in natural language
Prerequisites:
-- The project must be a public project on GitLab.com.
+Additional prerequisites [beyond the two above](#experiment-ai-features).
+
+- The project must be on GitLab.com.
- You must have the GitLab Ultimate subscription tier.
-- You must be a member of the project.
+- You must be a member of the project with sufficient permissions to view the repository.
To explain your code:
diff --git a/doc/user/application_security/policies/index.md b/doc/user/application_security/policies/index.md
index 47d959a1f35..4e610d64ec9 100644
--- a/doc/user/application_security/policies/index.md
+++ b/doc/user/application_security/policies/index.md
@@ -141,7 +141,6 @@ The workaround is to amend your group or instance push rules to allow branches f
### Troubleshooting common issues configuring security policies
-- Confirm that projects contain a `.gitlab-ci.yml` file. This file is required for scan execution policies.
- Confirm that scanners are properly configured and producing results for the latest branch. Security Policies are designed to require approval when there are no results (no security report), as this ensures that no vulnerabilities are introduced. We cannot know if there are any vulnerabilities unless the scans enforced by the policy complete successfully and are evaluated.
- When running scan execution policies based on a SAST action, ensure target repositories contain proper code files. SAST runs different analyzers [based on the types of files in the repo](../sast/index.md#supported-languages-and-frameworks), and if no supported files are found it will not run any jobs. See the [SAST CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) for more details.
- Check for any branch configuration conflicts. If your policy is configured to enforce rules on `main` but some projects within the scope are using `master` as their default branch, the policy is not applied for the latter. Support for specifying the `default` branch in your policies is proposed in [epic 9468](https://gitlab.com/groups/gitlab-org/-/epics/9468).
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 37bc3e7348d..f1386687d7a 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -10,13 +10,28 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Group-level security policies [enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/356258) in GitLab 15.4.
> - Operational container scanning [introduced](https://gitlab.com/groups/gitlab-org/-/epics/3410) in GitLab 15.5
> - Support for custom CI variables in the Scan Execution Policies editor [introduced](https://gitlab.com/groups/gitlab-org/-/epics/9566) in GitLab 16.2.
+> - Enforcement of scan execution policies on projects with an existing GitLab CI/CD configuration [introduced](https://gitlab.com/groups/gitlab-org/-/epics/6880) in GitLab 16.2 [with a flag](../../../administration/feature_flags.md) named `scan_execution_policy_pipelines`. Enabled by default.
-Group, subgroup, or project owners can use scan execution policies to require that security scans run on a specified
-schedule or with the project pipeline. The security scan runs with multiple project pipelines if you define the policy
-at a group or subgroup level. GitLab injects the required scans into the CI pipeline as new jobs. In the event
-of a job name collision, GitLab adds a dash and a number to the job name. GitLab increments the number until the name
-no longer conflicts with existing job names. If you create a policy at the group level, it applies to every child project
-or subgroup. You cannot edit a group-level policy from a child project or subgroup.
+FLAG:
+On self-managed GitLab, this feature is enabled by default. To disable it, ask an
+administrator to [disable the feature flag](../../../administration/feature_flags.md) named
+`scan_execution_policy_pipelines`. On GitLab.com, this feature is enabled.
+
+Group, subgroup, or project owners can use scan execution policies to require that security scans
+run on a specified schedule or with the project pipeline. The security scan runs with multiple
+project pipelines if you define the policy at a group or subgroup level. GitLab injects the required
+scans into the CI/CD pipeline as new jobs.
+
+Scan execution policies are enforced for all applicable projects, even those without a GitLab
+CI/CD configuration file or where AutoDevOps is disabled. Security policies create the file
+implicitly so that the policies can be enforced. This ensures policies enabling execution of
+secret detection, static analysis, or other scanners that do not require a build in the
+project, are still able to execute and be enforced.
+
+In the event of a job name collision, GitLab appends a hyphen and a number to the job name. GitLab
+increments the number until the name no longer conflicts with existing job names. If you create a
+policy at the group level, it applies to every child project or subgroup. You cannot edit a
+group-level policy from a child project or subgroup.
This feature has some overlap with [compliance framework pipelines](../../group/compliance_frameworks.md#compliance-pipelines),
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 36971ddb713..446e3a9deb0 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -355,8 +355,8 @@ for GitLab.com, see
For information on rate limiting responses, see:
-- [List of headers on responses to blocked requests](../admin_area/settings/user_and_ip_rate_limits.md#response-headers).
-- [Customizable response text](../admin_area/settings/user_and_ip_rate_limits.md#use-a-custom-rate-limit-response).
+- [List of headers on responses to blocked requests](../../administration/settings/user_and_ip_rate_limits.md#response-headers).
+- [Customizable response text](../../administration/settings/user_and_ip_rate_limits.md#use-a-custom-rate-limit-response).
### Protected paths throttle
@@ -366,7 +366,7 @@ paths that exceed 10 requests per **minute** per IP address.
See the source below for which paths are protected. This includes user creation,
user confirmation, user sign in, and password reset.
-[User and IP rate limits](../admin_area/settings/user_and_ip_rate_limits.md#response-headers)
+[User and IP rate limits](../../administration/settings/user_and_ip_rate_limits.md#response-headers)
includes a list of the headers responded to blocked requests.
See [Protected Paths](../admin_area/settings/protected_paths.md) for more details.
diff --git a/doc/user/group/moderate_users.md b/doc/user/group/moderate_users.md
index 1dde36c5c70..85fdeeb25c7 100644
--- a/doc/user/group/moderate_users.md
+++ b/doc/user/group/moderate_users.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/modelops/anti-abuse/team-tasks/-/issues/155) in GitLab 15.8.
-This is the group-level documentation. For self-managed instances, see the [administration documentation](../admin_area/moderate_users.md).
+This is the group-level documentation. For self-managed instances, see the [administration documentation](../../administration/moderate_users.md).
A group Owner can moderate user access by banning and unbanning users.
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index 2243d68ede0..292be3ac2d7 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -30,7 +30,7 @@ As a user, to delete your own account:
1. Select **Delete account**.
NOTE:
-On GitLab.com, there is a seven day delay between a user deleting their own account and deletion of the user record. During this time, that user is [blocked](../../admin_area/moderate_users.md#block-a-user) and a new account with the same email address or username cannot be created. Unblocking the account does not undo the deletion because the account will still be in the deletion queue, and will be deleted. Accounts with no issues, comments, notes, merge requests, or snippets are deleted immediately. Accounts under paid namespaces are deleted immediately.
+On GitLab.com, there is a seven day delay between a user deleting their own account and deletion of the user record. During this time, that user is [blocked](../../../administration/moderate_users.md#block-a-user) and a new account with the same email address or username cannot be created. Unblocking the account does not undo the deletion because the account will still be in the deletion queue, and will be deleted. Accounts with no issues, comments, notes, merge requests, or snippets are deleted immediately. Accounts under paid namespaces are deleted immediately.
## Delete users and user contributions **(FREE SELF)**
@@ -69,7 +69,7 @@ When deleting users, you can either:
- Personal access tokens.
- Snippets.
-An alternative to deleting is [blocking a user](../../admin_area/moderate_users.md#block-a-user).
+An alternative to deleting is [blocking a user](../../../administration/moderate_users.md#block-a-user).
When a user is deleted from an [abuse report](../../../administration/review_abuse_reports.md) or spam log, these associated
records are always removed.
diff --git a/doc/user/upgrade_email_bypass.md b/doc/user/upgrade_email_bypass.md
index 99f2caf775d..ae47a9156c7 100644
--- a/doc/user/upgrade_email_bypass.md
+++ b/doc/user/upgrade_email_bypass.md
@@ -73,7 +73,7 @@ Your account has been blocked. Fatal: Could not read from remote repository
Your primary email address is not confirmed.
```
-You can assure your users that they have not been [Blocked](admin_area/moderate_users.md#block-and-unblock-users) by an administrator.
+You can assure your users that they have not been [Blocked](../administration/moderate_users.md#block-and-unblock-users) by an administrator.
When affected users see this message, they must confirm their email address before they can commit code.
## What do you need to know as an administrator of a GitLab self-managed Instance?
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a4b2190b4fc..62f4a2cee4e 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -15807,6 +15807,9 @@ msgstr ""
msgid "Descriptive label"
msgstr ""
+msgid "Deselect all"
+msgstr ""
+
msgid "Design"
msgstr ""
@@ -19377,6 +19380,9 @@ msgstr ""
msgid "Filter"
msgstr ""
+msgid "Filter activity"
+msgstr ""
+
msgid "Filter by"
msgstr ""
@@ -49936,9 +49942,6 @@ msgstr ""
msgid "UserList|created %{timeago}"
msgstr ""
-msgid "UserProfiles|No snippets found."
-msgstr ""
-
msgid "UserProfile|%{count} %{file}"
msgstr ""
@@ -49993,6 +49996,9 @@ msgstr ""
msgid "UserProfile|Following"
msgstr ""
+msgid "UserProfile|Get started with snippets"
+msgstr ""
+
msgid "UserProfile|Groups"
msgstr ""
@@ -50032,15 +50038,24 @@ msgstr ""
msgid "UserProfile|Starred projects"
msgstr ""
+msgid "UserProfile|Store, share, and embed bits of code and text."
+msgstr ""
+
msgid "UserProfile|Subscribe"
msgstr ""
msgid "UserProfile|There are no projects available to be displayed here."
msgstr ""
+msgid "UserProfile|This user doesn't have any followers"
+msgstr ""
+
msgid "UserProfile|This user doesn't have any followers."
msgstr ""
+msgid "UserProfile|This user doesn't have any snippets"
+msgstr ""
+
msgid "UserProfile|This user has a private profile"
msgstr ""
@@ -50053,6 +50068,9 @@ msgstr ""
msgid "UserProfile|This user is blocked"
msgstr ""
+msgid "UserProfile|This user isn't following other users"
+msgstr ""
+
msgid "UserProfile|This user isn't following other users."
msgstr ""
@@ -50074,12 +50092,18 @@ msgstr ""
msgid "UserProfile|View user in admin area"
msgstr ""
+msgid "UserProfile|You are not following other users"
+msgstr ""
+
msgid "UserProfile|You are not following other users."
msgstr ""
msgid "UserProfile|You can create a group for several dependent projects."
msgstr ""
+msgid "UserProfile|You do not have any followers"
+msgstr ""
+
msgid "UserProfile|You do not have any followers."
msgstr ""
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb
index 8b75a13606a..ac85795b2bb 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_group_spec.rb
@@ -39,11 +39,7 @@ module QA
it(
'successfully imports groups and labels',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347674',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415270"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347674'
) do
expect_group_import_finished_successfully
@@ -80,11 +76,7 @@ module QA
it(
'successfully imports group milestones and badges',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347628',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415270"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347628'
) do
expect_group_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
index 477f7b42dad..bff1837f51b 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb
@@ -43,11 +43,7 @@ module QA
it(
'successfully imports issue',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347608',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415247"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347608'
) do
expect_project_import_finished_successfully
expect(imported_issues.count).to eq(1)
@@ -71,11 +67,7 @@ module QA
it(
'preserves related merge request',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415247"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305'
) do
expect_project_import_finished_successfully
expect(imported_related_mrs).to eq([source_mr.iid])
@@ -99,11 +91,7 @@ module QA
it(
'successfully imports design',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366449',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415247"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366449'
) do
expect_project_import_finished_successfully
expect(imported_issues.count).to eq(1)
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
index bd03f35953a..ed79281b328 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
@@ -33,11 +33,7 @@ module QA
it(
'member retains indirect membership in imported project',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354416',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415271"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354416'
) do
expect_project_import_finished_successfully
@@ -55,11 +51,7 @@ module QA
it(
'member retains direct membership in imported project',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354417',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415271"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354417'
) do
expect_project_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
index e4fd424b69f..307d0493b2a 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
@@ -72,8 +72,8 @@ module QA
'successfully imports merge request',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348478',
quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415245"
+ type: :bug,
+ issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/414859"
}
) do
expect_project_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb
index c031550c86a..2f80f4c07ed 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb
@@ -45,11 +45,7 @@ module QA
it(
'successfully imports ci pipeline',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354650',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415272"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354650'
) do
expect_project_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
index e1f3ef26be3..7cbccf9be44 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_project_spec.rb
@@ -35,11 +35,7 @@ module QA
it(
'successfully imports project',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383351',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415672"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383351'
) do
expect_project_import_finished_successfully
@@ -50,11 +46,7 @@ module QA
context 'with uninitialized project' do
it(
'successfully imports project',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347610',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415246"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347610'
) do
expect_project_import_finished_successfully
@@ -103,11 +95,7 @@ module QA
it(
'successfully imports repository',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347570',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415246"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347570'
) do
expect_project_import_finished_successfully
@@ -126,11 +114,7 @@ module QA
it(
'successfully imports project wiki',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347567',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415246"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347567'
) do
expect_project_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
index 3237dfca107..fcf15b66c11 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
@@ -34,10 +34,10 @@ module QA
commit_path: release[:commit_path].split("/-/").last,
tag_path: release[:tag_path].split("/-/").last,
assets: release[:assets].merge({
- sources: release.dig(:assets, :sources).map do |source|
- source.merge({ url: source[:url].split("/-/").last })
- end
- }),
+ sources: release.dig(:assets, :sources).map do |source|
+ source.merge({ url: source[:url].split("/-/").last })
+ end
+ }),
milestones: release[:milestones].map do |milestone|
milestone.except(:id, :project_id).merge({ web_url: milestone[:web_url].split("/-/").last })
end,
@@ -58,11 +58,7 @@ module QA
it(
'successfully imports project release',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360243',
- quarantine: {
- type: :investigating,
- issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415292"
- }
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360243'
) do
expect_project_import_finished_successfully
diff --git a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
index 86fc154c1cf..d3b702a658c 100644
--- a/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/rate_limits_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: 'review-qa-*' } do
+ RSpec.describe 'Manage', :requires_admin, :skip_live_env, except: { job: %w[review-qa-* gdk-qa-*] } do
describe 'rate limits', :reliable, product_group: :import_and_integrate do
let(:rate_limited_user) { Resource::User.fabricate_via_api! }
let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) }
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index b4ec00ab766..444d4a96f9c 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -1140,4 +1140,38 @@ describe('common_utils', () => {
expect(result).toEqual([{ hello: '' }, { helloWorld: '' }]);
});
});
+
+ describe('isCurrentUser', () => {
+ describe('when user is not signed in', () => {
+ it('returns `false`', () => {
+ window.gon.current_user_id = null;
+
+ expect(commonUtils.isCurrentUser(1)).toBe(false);
+ });
+ });
+
+ describe('when current user id does not match the provided user id', () => {
+ it('returns `false`', () => {
+ window.gon.current_user_id = 2;
+
+ expect(commonUtils.isCurrentUser(1)).toBe(false);
+ });
+ });
+
+ describe('when current user id matches the provided user id', () => {
+ it('returns `true`', () => {
+ window.gon.current_user_id = 1;
+
+ expect(commonUtils.isCurrentUser(1)).toBe(true);
+ });
+ });
+
+ describe('when provided user id is a string and it matches current user id', () => {
+ it('returns `true`', () => {
+ window.gon.current_user_id = 1;
+
+ expect(commonUtils.isCurrentUser('1')).toBe(true);
+ });
+ });
+ });
});
diff --git a/spec/frontend/notes/components/mr_discussion_filter_spec.js b/spec/frontend/notes/components/mr_discussion_filter_spec.js
index beb25c30af6..2bb47fd3c9e 100644
--- a/spec/frontend/notes/components/mr_discussion_filter_spec.js
+++ b/spec/frontend/notes/components/mr_discussion_filter_spec.js
@@ -67,7 +67,7 @@ describe('Merge request discussion filter component', () => {
it('lists current filters', () => {
createComponent();
- expect(wrapper.findAllComponents(GlListboxItem).length).toBe(MR_FILTER_OPTIONS.length);
+ expect(wrapper.findAllComponents(GlListboxItem)).toHaveLength(MR_FILTER_OPTIONS.length);
});
it('updates store when selecting filter', async () => {
@@ -107,4 +107,30 @@ describe('Merge request discussion filter component', () => {
expect(wrapper.findComponent(GlButton).text()).toBe(expectedText);
});
+
+ it('when clicking de-select it de-selects all options', async () => {
+ createComponent();
+
+ wrapper.find('[data-testid="listbox-reset-button"]').vm.$emit('click');
+
+ await nextTick();
+
+ expect(wrapper.findAll('[aria-selected="true"]')).toHaveLength(0);
+ });
+
+ it('when clicking select all it selects all options', async () => {
+ createComponent();
+
+ wrapper.find('[data-testid="listbox-item-approval"]').vm.$emit('select', false);
+
+ await nextTick();
+
+ expect(wrapper.findAll('[aria-selected="true"]')).toHaveLength(9);
+
+ wrapper.find('[data-testid="listbox-select-all-button"]').vm.$emit('click');
+
+ await nextTick();
+
+ expect(wrapper.findAll('[aria-selected="true"]')).toHaveLength(10);
+ });
});
diff --git a/spec/frontend/profile/components/follow_spec.js b/spec/frontend/profile/components/follow_spec.js
index 2555e41257f..a2e8d065a46 100644
--- a/spec/frontend/profile/components/follow_spec.js
+++ b/spec/frontend/profile/components/follow_spec.js
@@ -1,11 +1,19 @@
-import { GlAvatarLabeled, GlAvatarLink, GlLoadingIcon, GlPagination } from '@gitlab/ui';
+import {
+ GlAvatarLabeled,
+ GlAvatarLink,
+ GlEmptyState,
+ GlLoadingIcon,
+ GlPagination,
+} from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import users from 'test_fixtures/api/users/followers/get.json';
import Follow from '~/profile/components/follow.vue';
import { DEFAULT_PER_PAGE } from '~/api';
+import { isCurrentUser } from '~/lib/utils/common_utils';
jest.mock('~/rest_api');
+jest.mock('~/lib/utils/common_utils');
describe('FollowersTab', () => {
let wrapper;
@@ -15,6 +23,13 @@ describe('FollowersTab', () => {
loading: false,
page: 1,
totalItems: 50,
+ currentUserEmptyStateTitle: 'UserProfile|You do not have any followers.',
+ visitorEmptyStateTitle: "UserProfile|This user doesn't have any followers.",
+ };
+
+ const defaultProvide = {
+ followEmptyState: '/illustrations/empty-state/empty-friends-md.svg',
+ userId: '1',
};
const createComponent = ({ propsData = {} } = {}) => {
@@ -23,11 +38,13 @@ describe('FollowersTab', () => {
...defaultPropsData,
...propsData,
},
+ provide: defaultProvide,
});
};
const findPagination = () => wrapper.findComponent(GlPagination);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
describe('when `loading` prop is `true`', () => {
it('renders loading icon', () => {
@@ -95,5 +112,35 @@ describe('FollowersTab', () => {
expect(wrapper.emitted('pagination-input')).toEqual([[nextPage]]);
});
});
+
+ describe('when the users prop is empty', () => {
+ describe('when user is the current user', () => {
+ beforeEach(() => {
+ isCurrentUser.mockImplementation(() => true);
+ createComponent({ propsData: { users: [] } });
+ });
+
+ it('displays empty state with correct message', () => {
+ expect(findEmptyState().props()).toMatchObject({
+ svgPath: defaultProvide.followEmptyState,
+ title: defaultPropsData.currentUserEmptyStateTitle,
+ });
+ });
+ });
+
+ describe('when user is a visitor', () => {
+ beforeEach(() => {
+ isCurrentUser.mockImplementation(() => false);
+ createComponent({ propsData: { users: [] } });
+ });
+
+ it('displays empty state with correct message', () => {
+ expect(findEmptyState().props()).toMatchObject({
+ svgPath: defaultProvide.followEmptyState,
+ title: defaultPropsData.visitorEmptyStateTitle,
+ });
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/profile/components/followers_tab_spec.js b/spec/frontend/profile/components/followers_tab_spec.js
index 0370005d0a4..75586a2c9ea 100644
--- a/spec/frontend/profile/components/followers_tab_spec.js
+++ b/spec/frontend/profile/components/followers_tab_spec.js
@@ -75,6 +75,8 @@ describe('FollowersTab', () => {
loading: false,
page: 1,
totalItems: 6,
+ currentUserEmptyStateTitle: FollowersTab.i18n.currentUserEmptyStateTitle,
+ visitorEmptyStateTitle: FollowersTab.i18n.visitorEmptyStateTitle,
});
});
diff --git a/spec/frontend/profile/components/following_tab_spec.js b/spec/frontend/profile/components/following_tab_spec.js
index 1eadb2c7388..48d84187739 100644
--- a/spec/frontend/profile/components/following_tab_spec.js
+++ b/spec/frontend/profile/components/following_tab_spec.js
@@ -68,6 +68,8 @@ describe('FollowingTab', () => {
loading: false,
page: MOCK_PAGE,
totalItems: MOCK_TOTAL_FOLLOWING,
+ currentUserEmptyStateTitle: FollowingTab.i18n.currentUserEmptyStateTitle,
+ visitorEmptyStateTitle: FollowingTab.i18n.visitorEmptyStateTitle,
});
});
diff --git a/spec/frontend/profile/components/snippets/snippets_tab_spec.js b/spec/frontend/profile/components/snippets/snippets_tab_spec.js
index 47e2fbcf2c0..5992bb03e4d 100644
--- a/spec/frontend/profile/components/snippets/snippets_tab_spec.js
+++ b/spec/frontend/profile/components/snippets/snippets_tab_spec.js
@@ -7,6 +7,7 @@ import { SNIPPET_MAX_LIST_COUNT } from '~/profile/constants';
import SnippetsTab from '~/profile/components/snippets/snippets_tab.vue';
import SnippetRow from '~/profile/components/snippets/snippet_row.vue';
import getUserSnippets from '~/profile/components/graphql/get_user_snippets.query.graphql';
+import { isCurrentUser } from '~/lib/utils/common_utils';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import {
@@ -15,8 +16,14 @@ import {
MOCK_USER_SNIPPETS_RES,
MOCK_USER_SNIPPETS_PAGINATION_RES,
MOCK_USER_SNIPPETS_EMPTY_RES,
+ MOCK_NEW_SNIPPET_PATH,
} from 'jest/profile/mock_data';
+jest.mock('~/lib/utils/common_utils');
+jest.mock('~/helpers/help_page_helper', () => ({
+ helpPagePath: jest.fn().mockImplementation(() => 'http://127.0.0.1:3000/help/user/snippets'),
+}));
+
Vue.use(VueApollo);
describe('UserProfileSnippetsTab', () => {
@@ -32,6 +39,7 @@ describe('UserProfileSnippetsTab', () => {
provide: {
userId: MOCK_USER.id,
snippetsEmptyState: MOCK_SNIPPETS_EMPTY_STATE,
+ newSnippetPath: MOCK_NEW_SNIPPET_PATH,
},
});
};
@@ -52,9 +60,38 @@ describe('UserProfileSnippetsTab', () => {
expect(findSnippetRows().exists()).toBe(false);
});
- it('does render empty state with correct svg', () => {
- expect(findGlEmptyState().exists()).toBe(true);
- expect(findGlEmptyState().attributes('svgpath')).toBe(MOCK_SNIPPETS_EMPTY_STATE);
+ describe('when user is the current user', () => {
+ beforeEach(() => {
+ isCurrentUser.mockImplementation(() => true);
+ createComponent();
+ });
+
+ it('displays empty state with correct message', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ svgPath: MOCK_SNIPPETS_EMPTY_STATE,
+ title: SnippetsTab.i18n.currentUserEmptyStateTitle,
+ description: SnippetsTab.i18n.emptyStateDescription,
+ primaryButtonLink: MOCK_NEW_SNIPPET_PATH,
+ primaryButtonText: SnippetsTab.i18n.newSnippet,
+ secondaryButtonLink: 'http://127.0.0.1:3000/help/user/snippets',
+ secondaryButtonText: SnippetsTab.i18n.learnMore,
+ });
+ });
+ });
+
+ describe('when user is a visitor', () => {
+ beforeEach(() => {
+ isCurrentUser.mockImplementation(() => false);
+ createComponent();
+ });
+
+ it('displays empty state with correct message', () => {
+ expect(findGlEmptyState().props()).toMatchObject({
+ svgPath: MOCK_SNIPPETS_EMPTY_STATE,
+ title: SnippetsTab.i18n.visitorEmptyStateTitle,
+ description: null,
+ });
+ });
});
});
diff --git a/spec/frontend/profile/mock_data.js b/spec/frontend/profile/mock_data.js
index 856534aebd3..6c4ff0a84f9 100644
--- a/spec/frontend/profile/mock_data.js
+++ b/spec/frontend/profile/mock_data.js
@@ -22,6 +22,7 @@ export const userCalendarResponse = {
};
export const MOCK_SNIPPETS_EMPTY_STATE = 'illustrations/empty-state/empty-snippets-md.svg';
+export const MOCK_NEW_SNIPPET_PATH = '/-/snippets/new';
export const MOCK_USER = {
id: '1',
diff --git a/spec/frontend/work_items/components/notes/work_item_note_spec.js b/spec/frontend/work_items/components/notes/work_item_note_spec.js
index 94e3b3ccc81..c5d1decfb42 100644
--- a/spec/frontend/work_items/components/notes/work_item_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_note_spec.js
@@ -95,14 +95,10 @@ describe('Work Item Note', () => {
updateWorkItemMutationHandler = updateWorkItemMutationSuccessHandler,
assignees = mockAssignees,
workItemByIidResponseHandler = workItemResponseHandler,
- workItemsMvc2 = false,
} = {}) => {
wrapper = shallowMount(WorkItemNote, {
provide: {
fullPath: 'test-project-path',
- glFeatures: {
- workItemsMvc2,
- },
},
propsData: {
workItemId,
@@ -432,12 +428,6 @@ describe('Work Item Note', () => {
});
});
- it('does not show awards when feature flag disabled', () => {
- createComponent();
-
- expect(findAwardsList().exists()).toBe(false);
- });
-
it('passes note props to awards list', () => {
createComponent({ note: mockWorkItemCommentNote, workItemsMvc2: true });
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index 6ee208dfd15..c0d3c31a36d 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -496,13 +496,17 @@ RSpec.describe UsersHelper do
describe '#user_profile_tabs_app_data' do
before do
+ allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:user_calendar_path).with(user, :json).and_return('/users/root/calendar.json')
allow(helper).to receive(:user_activity_path).with(user, :json).and_return('/users/root/activity.json')
+ allow(helper).to receive(:new_snippet_path).and_return('/-/snippets/new')
allow(user).to receive_message_chain(:followers, :count).and_return(2)
allow(user).to receive_message_chain(:followees, :count).and_return(3)
end
it 'returns expected hash' do
+ allow(helper).to receive(:can?).with(user, :create_snippet).and_return(true)
+
expect(helper.user_profile_tabs_app_data(user)).to match({
followees_count: 3,
followers_count: 2,
@@ -510,9 +514,21 @@ RSpec.describe UsersHelper do
user_activity_path: '/users/root/activity.json',
utc_offset: 0,
user_id: user.id,
- snippets_empty_state: match_asset_path('illustrations/empty-state/empty-snippets-md.svg')
+ new_snippet_path: '/-/snippets/new',
+ snippets_empty_state: match_asset_path('illustrations/empty-state/empty-snippets-md.svg'),
+ follow_empty_state: match_asset_path('illustrations/empty-state/empty-friends-md.svg')
})
end
+
+ context 'when user does not have create_snippet permissions' do
+ before do
+ allow(helper).to receive(:can?).with(user, :create_snippet).and_return(false)
+ end
+
+ it 'returns nil for new_snippet_path property' do
+ expect(helper.user_profile_tabs_app_data(user)[:new_snippet_path]).to be_nil
+ end
+ end
end
describe '#load_max_project_member_accesses' do