Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
2aea9a0c91
commit
3da283df31
|
@ -1103,7 +1103,6 @@ lib/gitlab/checks/**
|
||||||
/ee/app/assets/javascripts/access_tokens/
|
/ee/app/assets/javascripts/access_tokens/
|
||||||
/ee/app/assets/javascripts/audit_events/components/tokens/
|
/ee/app/assets/javascripts/audit_events/components/tokens/
|
||||||
/ee/app/assets/javascripts/audit_events/token_utils.js
|
/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/groups/settings/components/
|
||||||
/ee/app/assets/javascripts/pages/admin/application_settings/general/components/
|
/ee/app/assets/javascripts/pages/admin/application_settings/general/components/
|
||||||
/ee/app/assets/javascripts/pages/groups/omniauth_callbacks/
|
/ee/app/assets/javascripts/pages/groups/omniauth_callbacks/
|
||||||
|
|
|
@ -613,6 +613,8 @@
|
||||||
|
|
||||||
.as-if-jh-default-exclusion-rules:
|
.as-if-jh-default-exclusion-rules:
|
||||||
rules:
|
rules:
|
||||||
|
- if: '$ADD_JH_FILES_TOKEN == null'
|
||||||
|
when: never
|
||||||
- <<: *if-security-merge-request
|
- <<: *if-security-merge-request
|
||||||
when: never
|
when: never
|
||||||
- <<: *if-merge-request-targeting-stable-branch
|
- <<: *if-merge-request-targeting-stable-branch
|
||||||
|
|
|
@ -134,12 +134,12 @@ gdk-qa-smoke-with-load-balancer:
|
||||||
variables:
|
variables:
|
||||||
QA_SCENARIO: Test::Instance::Smoke
|
QA_SCENARIO: Test::Instance::Smoke
|
||||||
QA_RUN_TYPE: gdk-qa-smoke
|
QA_RUN_TYPE: gdk-qa-smoke
|
||||||
|
allow_failure: true
|
||||||
rules:
|
rules:
|
||||||
- changes:
|
- changes:
|
||||||
- ".gitlab/ci/test-on-gdk/**"
|
- ".gitlab/ci/test-on-gdk/**"
|
||||||
- "lib/gitlab/database/load_balancing/**/*"
|
- "lib/gitlab/database/load_balancing/**/*"
|
||||||
|
|
||||||
# TODO: set non manual once smoke tests prove to be stable
|
|
||||||
gdk-qa-reliable:
|
gdk-qa-reliable:
|
||||||
extends:
|
extends:
|
||||||
- .gdk-qa-base
|
- .gdk-qa-base
|
||||||
|
@ -149,7 +149,7 @@ gdk-qa-reliable:
|
||||||
QA_RUN_TYPE: gdk-qa-blocking
|
QA_RUN_TYPE: gdk-qa-blocking
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
rules:
|
rules:
|
||||||
- when: manual
|
- when: always
|
||||||
|
|
||||||
gdk-qa-reliable-with-load-balancer:
|
gdk-qa-reliable-with-load-balancer:
|
||||||
extends:
|
extends:
|
||||||
|
|
|
@ -92,7 +92,7 @@ tasks:
|
||||||
# Give Gitpod a few more seconds to set up everything ...
|
# Give Gitpod a few more seconds to set up everything ...
|
||||||
sleep 5
|
sleep 5
|
||||||
printf "$(date) – GitLab is up (took ~%.1f minutes)\n" "$((10*$SECONDS/60))e-1" | tee -a /workspace/startup.log
|
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-*)
|
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")"
|
[[ -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")"
|
||||||
)
|
)
|
||||||
|
|
|
@ -1818,6 +1818,10 @@ entry.
|
||||||
- [Add index to group_group_links table](gitlab-org/gitlab@9a3f2c1a90b54074e61d0abf07101ce664198e81) ([merge request](gitlab-org/gitlab!117386))
|
- [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))
|
- [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)
|
## 15.11.11 (2023-07-04)
|
||||||
|
|
||||||
### Security (1 change)
|
### Security (1 change)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
4c314694734330f910ce5d1409c0d462a02628ff
|
6f26cab11ed6ade703ad23809b5fa053989b7ff3
|
||||||
|
|
|
@ -721,3 +721,13 @@ export const getFirstPropertyValue = (data) => {
|
||||||
|
|
||||||
return data[key];
|
return data[key];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isCurrentUser = (userId) => {
|
||||||
|
const currentUserId = window.gon?.current_user_id;
|
||||||
|
|
||||||
|
if (!currentUserId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number(userId) === currentUserId;
|
||||||
|
};
|
||||||
|
|
|
@ -62,6 +62,12 @@ export default {
|
||||||
this.updateMergeRequestFilters(filters);
|
this.updateMergeRequestFilters(filters);
|
||||||
this.selectedFilters = filters;
|
this.selectedFilters = filters;
|
||||||
},
|
},
|
||||||
|
deselectAll() {
|
||||||
|
this.selectedFilters = [];
|
||||||
|
},
|
||||||
|
selectAll() {
|
||||||
|
this.selectedFilters = MR_FILTER_OPTIONS.map((f) => f.value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
MR_FILTER_OPTIONS,
|
MR_FILTER_OPTIONS,
|
||||||
};
|
};
|
||||||
|
@ -84,9 +90,14 @@ export default {
|
||||||
<gl-collapsible-listbox
|
<gl-collapsible-listbox
|
||||||
v-model="selectedFilters"
|
v-model="selectedFilters"
|
||||||
:items="$options.MR_FILTER_OPTIONS"
|
:items="$options.MR_FILTER_OPTIONS"
|
||||||
|
:header-text="__('Filter activity')"
|
||||||
|
:show-select-all-button-label="__('Select all')"
|
||||||
|
:reset-button-label="__('Deselect all')"
|
||||||
multiple
|
multiple
|
||||||
placement="right"
|
placement="right"
|
||||||
@hidden="applyFilters"
|
@hidden="applyFilters"
|
||||||
|
@reset="deselectAll"
|
||||||
|
@select-all="selectAll"
|
||||||
>
|
>
|
||||||
<template #toggle>
|
<template #toggle>
|
||||||
<gl-button class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!">
|
<gl-button class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!">
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
<script>
|
<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 { DEFAULT_PER_PAGE } from '~/api';
|
||||||
import { NEXT, PREV } from '~/vue_shared/components/pagination/constants';
|
import { NEXT, PREV } from '~/vue_shared/components/pagination/constants';
|
||||||
|
import { isCurrentUser } from '~/lib/utils/common_utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
i18n: {
|
i18n: {
|
||||||
|
@ -13,7 +20,9 @@ export default {
|
||||||
GlAvatarLink,
|
GlAvatarLink,
|
||||||
GlLoadingIcon,
|
GlLoadingIcon,
|
||||||
GlPagination,
|
GlPagination,
|
||||||
|
GlEmptyState,
|
||||||
},
|
},
|
||||||
|
inject: ['followEmptyState', 'userId'],
|
||||||
props: {
|
props: {
|
||||||
/**
|
/**
|
||||||
* Expected format:
|
* Expected format:
|
||||||
|
@ -48,12 +57,34 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
default: DEFAULT_PER_PAGE,
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<gl-loading-icon v-if="loading" class="gl-mt-5" size="md" />
|
<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 v-else>
|
||||||
<div class="gl-my-n3 gl-mx-n3 gl-display-flex gl-flex-wrap">
|
<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">
|
<div v-for="user in users" :key="user.id" class="gl-p-3 gl-w-full gl-md-w-half gl-lg-w-25p">
|
||||||
|
|
|
@ -12,6 +12,8 @@ export default {
|
||||||
errorMessage: s__(
|
errorMessage: s__(
|
||||||
'UserProfile|An error occurred loading the followers. Please refresh the page to try again.',
|
'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: {
|
components: {
|
||||||
GlBadge,
|
GlBadge,
|
||||||
|
@ -68,6 +70,8 @@ export default {
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:page="page"
|
:page="page"
|
||||||
:total-items="totalItems"
|
:total-items="totalItems"
|
||||||
|
:current-user-empty-state-title="$options.i18n.currentUserEmptyStateTitle"
|
||||||
|
:visitor-empty-state-title="$options.i18n.visitorEmptyStateTitle"
|
||||||
@pagination-input="onPaginationInput"
|
@pagination-input="onPaginationInput"
|
||||||
/>
|
/>
|
||||||
</gl-tab>
|
</gl-tab>
|
||||||
|
|
|
@ -12,6 +12,8 @@ export default {
|
||||||
errorMessage: s__(
|
errorMessage: s__(
|
||||||
'UserProfile|An error occurred loading the following. Please refresh the page to try again.',
|
'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: {
|
components: {
|
||||||
GlBadge,
|
GlBadge,
|
||||||
|
@ -69,6 +71,8 @@ export default {
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:page="page"
|
:page="page"
|
||||||
:total-items="totalItems"
|
:total-items="totalItems"
|
||||||
|
:current-user-empty-state-title="$options.i18n.currentUserEmptyStateTitle"
|
||||||
|
:visitor-empty-state-title="$options.i18n.visitorEmptyStateTitle"
|
||||||
@pagination-input="onPaginationInput"
|
@pagination-input="onPaginationInput"
|
||||||
/>
|
/>
|
||||||
</gl-tab>
|
</gl-tab>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlTab, GlKeysetPagination, GlEmptyState } from '@gitlab/ui';
|
import { GlTab, GlKeysetPagination, GlEmptyState } from '@gitlab/ui';
|
||||||
import { s__ } from '~/locale';
|
import { s__, __ } from '~/locale';
|
||||||
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
import { convertToGraphQLId } from '~/graphql_shared/utils';
|
||||||
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
import { TYPENAME_USER } from '~/graphql_shared/constants';
|
||||||
import { SNIPPET_MAX_LIST_COUNT } from '~/profile/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 getUserSnippets from '../graphql/get_user_snippets.query.graphql';
|
||||||
import SnippetRow from './snippet_row.vue';
|
import SnippetRow from './snippet_row.vue';
|
||||||
|
|
||||||
|
@ -11,7 +13,11 @@ export default {
|
||||||
name: 'SnippetsTab',
|
name: 'SnippetsTab',
|
||||||
i18n: {
|
i18n: {
|
||||||
title: s__('UserProfile|Snippets'),
|
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: {
|
components: {
|
||||||
GlTab,
|
GlTab,
|
||||||
|
@ -19,7 +25,7 @@ export default {
|
||||||
GlEmptyState,
|
GlEmptyState,
|
||||||
SnippetRow,
|
SnippetRow,
|
||||||
},
|
},
|
||||||
inject: ['userId', 'snippetsEmptyState'],
|
inject: ['userId', 'snippetsEmptyState', 'newSnippetPath'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
userInfo: {},
|
userInfo: {},
|
||||||
|
@ -57,6 +63,14 @@ export default {
|
||||||
hasSnippets() {
|
hasSnippets() {
|
||||||
return this.userSnippets?.length;
|
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: {
|
methods: {
|
||||||
isLastSnippet(index) {
|
isLastSnippet(index) {
|
||||||
|
@ -76,6 +90,7 @@ export default {
|
||||||
beforeToken: this.pageInfo.startCursor,
|
beforeToken: this.pageInfo.startCursor,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
helpPagePath,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -100,11 +115,17 @@ export default {
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!hasSnippets">
|
<template v-if="!hasSnippets">
|
||||||
<gl-empty-state class="gl-mt-5" :svg-height="75" :svg-path="snippetsEmptyState">
|
<gl-empty-state
|
||||||
<template #title>
|
class="gl-mt-5"
|
||||||
<p class="gl-font-weight-bold gl-mt-n5">{{ $options.i18n.noSnippets }}</p>
|
:svg-path="snippetsEmptyState"
|
||||||
</template>
|
:svg-height="144"
|
||||||
</gl-empty-state>
|
: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>
|
</template>
|
||||||
</gl-tab>
|
</gl-tab>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -21,6 +21,8 @@ export const initProfileTabs = () => {
|
||||||
utcOffset,
|
utcOffset,
|
||||||
userId,
|
userId,
|
||||||
snippetsEmptyState,
|
snippetsEmptyState,
|
||||||
|
newSnippetPath,
|
||||||
|
followEmptyState,
|
||||||
} = el.dataset;
|
} = el.dataset;
|
||||||
|
|
||||||
const apolloProvider = new VueApollo({
|
const apolloProvider = new VueApollo({
|
||||||
|
@ -39,6 +41,8 @@ export const initProfileTabs = () => {
|
||||||
utcOffset,
|
utcOffset,
|
||||||
userId,
|
userId,
|
||||||
snippetsEmptyState,
|
snippetsEmptyState,
|
||||||
|
newSnippetPath,
|
||||||
|
followEmptyState,
|
||||||
},
|
},
|
||||||
render(createElement) {
|
render(createElement) {
|
||||||
return createElement(ProfileTabs);
|
return createElement(ProfileTabs);
|
||||||
|
|
|
@ -11,7 +11,6 @@ import { getLocationHash } from '~/lib/utils/url_utility';
|
||||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||||
import EditedAt from '~/issues/show/components/edited.vue';
|
import EditedAt from '~/issues/show/components/edited.vue';
|
||||||
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.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 NoteBody from '~/work_items/components/notes/work_item_note_body.vue';
|
||||||
import NoteHeader from '~/notes/components/note_header.vue';
|
import NoteHeader from '~/notes/components/note_header.vue';
|
||||||
import NoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
|
import NoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
|
||||||
|
@ -34,7 +33,7 @@ export default {
|
||||||
WorkItemCommentForm,
|
WorkItemCommentForm,
|
||||||
EditedAt,
|
EditedAt,
|
||||||
},
|
},
|
||||||
mixins: [Tracking.mixin(), glFeatureFlagsMixin()],
|
mixins: [Tracking.mixin()],
|
||||||
inject: ['fullPath'],
|
inject: ['fullPath'],
|
||||||
props: {
|
props: {
|
||||||
workItemId: {
|
workItemId: {
|
||||||
|
@ -370,12 +369,7 @@ export default {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="note-awards" :class="isFirstNote ? '' : 'gl-pl-7'">
|
<div class="note-awards" :class="isFirstNote ? '' : 'gl-pl-7'">
|
||||||
<work-item-note-awards-list
|
<work-item-note-awards-list :note="note" :work-item-iid="workItemIid" :is-modal="isModal" />
|
||||||
v-if="glFeatures.workItemsMvc2"
|
|
||||||
:note="note"
|
|
||||||
:work-item-iid="workItemIid"
|
|
||||||
:is-modal="isModal"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</timeline-entry-item>
|
</timeline-entry-item>
|
||||||
|
|
|
@ -10,7 +10,6 @@ import * as Sentry from '@sentry/browser';
|
||||||
import { __, sprintf } from '~/locale';
|
import { __, sprintf } from '~/locale';
|
||||||
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
|
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
|
||||||
import ReplyButton from '~/notes/components/note_actions/reply_button.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';
|
import { getMutation, optimisticAwardUpdate } from '../../notes/award_utils';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -36,7 +35,6 @@ export default {
|
||||||
directives: {
|
directives: {
|
||||||
GlTooltip: GlTooltipDirective,
|
GlTooltip: GlTooltipDirective,
|
||||||
},
|
},
|
||||||
mixins: [glFeatureFlagsMixin()],
|
|
||||||
inject: ['fullPath'],
|
inject: ['fullPath'],
|
||||||
props: {
|
props: {
|
||||||
workItemIid: {
|
workItemIid: {
|
||||||
|
@ -199,7 +197,7 @@ export default {
|
||||||
{{ __('Contributor') }}
|
{{ __('Contributor') }}
|
||||||
</user-access-role-badge>
|
</user-access-role-badge>
|
||||||
<emoji-picker
|
<emoji-picker
|
||||||
v-if="showAwardEmoji && glFeatures.workItemsMvc2"
|
v-if="showAwardEmoji"
|
||||||
toggle-class="note-action-button note-emoji-button btn-icon btn-default-tertiary"
|
toggle-class="note-action-button note-emoji-button btn-icon btn-default-tertiary"
|
||||||
data-testid="note-emoji-button"
|
data-testid="note-emoji-button"
|
||||||
@click="setAwardEmoji"
|
@click="setAwardEmoji"
|
||||||
|
|
|
@ -190,7 +190,9 @@ module UsersHelper
|
||||||
user_activity_path: user_activity_path(user, :json),
|
user_activity_path: user_activity_path(user, :json),
|
||||||
utc_offset: local_timezone_instance(user.timezone).now.utc_offset,
|
utc_offset: local_timezone_instance(user.timezone).now.utc_offset,
|
||||||
user_id: user.id,
|
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
|
end
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,11 @@ module Groups
|
||||||
return if @new_parent_group
|
return if @new_parent_group
|
||||||
return unless @group.owners.empty?
|
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)
|
@group.add_owner(current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -34,16 +34,7 @@ module Members
|
||||||
# @param sources [Group, Project, Array<Group>, Array<Project>, Group::ActiveRecord_Relation,
|
# @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.
|
# Project::ActiveRecord_Relation] - Can't be an array of source ids because we don't know the type of source.
|
||||||
# @return Array<Member>
|
# @return Array<Member>
|
||||||
def add_members(
|
def add_members(sources, invitees, access_level, **args)
|
||||||
sources,
|
|
||||||
invitees,
|
|
||||||
access_level,
|
|
||||||
current_user: nil,
|
|
||||||
expires_at: nil,
|
|
||||||
tasks_to_be_done: [],
|
|
||||||
tasks_project_id: nil,
|
|
||||||
ldap: nil
|
|
||||||
) # rubocop:disable Metrics/ParameterLists
|
|
||||||
return [] unless invitees.present?
|
return [] unless invitees.present?
|
||||||
|
|
||||||
sources = Array.wrap(sources) if sources.is_a?(ApplicationRecord) # For single source
|
sources = Array.wrap(sources) if sources.is_a?(ApplicationRecord) # For single source
|
||||||
|
@ -51,7 +42,9 @@ module Members
|
||||||
Member.transaction do
|
Member.transaction do
|
||||||
sources.flat_map do |source|
|
sources.flat_map do |source|
|
||||||
# If this user is attempting to manage Owner members and doesn't have permission, do not allow
|
# 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)
|
emails, users, existing_members = parse_users_list(source, invitees)
|
||||||
|
|
||||||
|
@ -59,12 +52,8 @@ module Members
|
||||||
source: source,
|
source: source,
|
||||||
access_level: access_level,
|
access_level: access_level,
|
||||||
existing_members: existing_members,
|
existing_members: existing_members,
|
||||||
current_user: current_user,
|
tasks_to_be_done: args[:tasks_to_be_done] || []
|
||||||
expires_at: expires_at,
|
}.merge(parsed_args(args))
|
||||||
tasks_to_be_done: tasks_to_be_done,
|
|
||||||
tasks_project_id: tasks_project_id,
|
|
||||||
ldap: ldap
|
|
||||||
}
|
|
||||||
|
|
||||||
members = emails.map do |email|
|
members = emails.map do |email|
|
||||||
new(invitee: email, builder: InviteMemberBuilder, **common_arguments).execute
|
new(invitee: email, builder: InviteMemberBuilder, **common_arguments).execute
|
||||||
|
@ -79,26 +68,21 @@ module Members
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_member(
|
def add_member(source, invitee, access_level, **args)
|
||||||
source,
|
add_members(source, [invitee], access_level, **args).first
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
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)
|
def managing_owners?(current_user, access_level)
|
||||||
current_user && Gitlab::Access.sym_options_with_owner[access_level] == Gitlab::Access::OWNER
|
current_user && Gitlab::Access.sym_options_with_owner[access_level] == Gitlab::Access::OWNER
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,3 +21,5 @@ module Members
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Members::Groups::CreatorService.prepend_mod_with('Members::Groups::CreatorService')
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
- unless Gitlab.com?
|
- unless Gitlab.com?
|
||||||
.form-group
|
.form-group
|
||||||
= f.label :deactivate_dormant_users, _('Dormant users'), class: 'label-bold'
|
= 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 }
|
- 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 }
|
= 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
|
.form-group
|
||||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415607
|
||||||
milestone: '16.1'
|
milestone: '16.1'
|
||||||
type: development
|
type: development
|
||||||
group: group::security policies
|
group: group::security policies
|
||||||
default_enabled: false
|
default_enabled: true
|
||||||
|
|
|
@ -85,8 +85,8 @@ To list users matching a specific criteria, select one of the following tabs on
|
||||||
- **2FA Enabled**
|
- **2FA Enabled**
|
||||||
- **2FA Disabled**
|
- **2FA Disabled**
|
||||||
- **External**
|
- **External**
|
||||||
- **[Blocked](../user/admin_area/moderate_users.md#block-a-user)**
|
- **[Blocked](../administration/moderate_users.md#block-a-user)**
|
||||||
- **[Deactivated](../user/admin_area/moderate_users.md#deactivate-a-user)**
|
- **[Deactivated](../administration/moderate_users.md#deactivate-a-user)**
|
||||||
- **Without projects**
|
- **Without projects**
|
||||||
|
|
||||||
For each user, the following are listed:
|
For each user, the following are listed:
|
||||||
|
|
|
@ -1000,13 +1000,13 @@ authenticated with the TLS protocol.
|
||||||
Users deleted from the LDAP server:
|
Users deleted from the LDAP server:
|
||||||
|
|
||||||
- Are immediately blocked from signing in to GitLab.
|
- 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
|
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).
|
[LDAP check cache runs](ldap_synchronization.md#adjust-ldap-user-sync-schedule).
|
||||||
|
|
||||||
To delete the account immediately, you can manually
|
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
|
## Update user email addresses
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
```
|
|
@ -837,7 +837,7 @@ Read more about the data returned by the replica
|
||||||
|
|
||||||
### Selecting the appropriate Patroni replication method
|
### 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
|
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)
|
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.
|
configured determines the amount of tolerable data loss.
|
||||||
|
|
|
@ -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).
|
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).
|
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).
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ After 10 requests, the client must wait 60 seconds before it can try again.
|
||||||
See also:
|
See also:
|
||||||
|
|
||||||
- List of paths [protected by default](../instance_limits.md#by-protected-path).
|
- 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.
|
for the headers returned to blocked requests.
|
||||||
|
|
||||||
## Configure protected paths
|
## Configure protected paths
|
||||||
|
|
|
@ -34,7 +34,7 @@ To disable sign ups:
|
||||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/267568) in GitLab 13.6.
|
> - [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
|
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
|
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.
|
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.
|
> - [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
|
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.
|
their account.
|
||||||
|
|
||||||
If an administrator [increases](#set-the-user-cap-number) or [removes](#remove-the-user-cap) the
|
If an administrator [increases](#set-the-user-cap-number) or [removes](#remove-the-user-cap) the
|
||||||
|
|
|
@ -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. -->
|
|
@ -16604,6 +16604,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
||||||
| <a id="groupprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
|
| <a id="groupprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
|
||||||
| <a id="groupprojectsincludesubgroups"></a>`includeSubgroups` | [`Boolean`](#boolean) | Include also subgroup projects. |
|
| <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="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="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="groupprojectssort"></a>`sort` | [`NamespaceProjectSort`](#namespaceprojectsort) | Sort projects by this criteria. |
|
||||||
| <a id="groupprojectswithissuesenabled"></a>`withIssuesEnabled` | [`Boolean`](#boolean) | Return only projects with issues enabled. |
|
| <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="namespaceprojectsids"></a>`ids` | [`[ID!]`](#id) | Filter projects by IDs. |
|
||||||
| <a id="namespaceprojectsincludesubgroups"></a>`includeSubgroups` | [`Boolean`](#boolean) | Include also subgroup projects. |
|
| <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="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="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="namespaceprojectssort"></a>`sort` | [`NamespaceProjectSort`](#namespaceprojectsort) | Sort projects by this criteria. |
|
||||||
| <a id="namespaceprojectswithissuesenabled"></a>`withIssuesEnabled` | [`Boolean`](#boolean) | Return only projects with issues enabled. |
|
| <a id="namespaceprojectswithissuesenabled"></a>`withIssuesEnabled` | [`Boolean`](#boolean) | Return only projects with issues enabled. |
|
||||||
|
|
|
@ -152,6 +152,11 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
|
||||||
- Token with the specified ID does not exist.
|
- 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.
|
- `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
|
## Revoke a group access token
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77236) in GitLab 14.7.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77236) in GitLab 14.7.
|
||||||
|
|
|
@ -235,6 +235,21 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
|
||||||
- Token with the specified ID does not exist.
|
- 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.
|
- `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
|
||||||
|
|
||||||
Revoke a personal access token by either:
|
Revoke a personal access token by either:
|
||||||
|
|
|
@ -161,6 +161,11 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
|
||||||
- Token with the specified ID does not exist.
|
- 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.
|
- `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
|
## Revoke a project access token
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238991) in GitLab 13.9.
|
||||||
|
|
|
@ -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_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. |
|
| `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. |
|
| `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. |
|
| `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_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. |
|
| `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_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_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. |
|
| `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. |
|
| `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. |
|
| `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. |
|
| `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. |
|
||||||
|
|
|
@ -1755,7 +1755,7 @@ Returns:
|
||||||
- `404 User Not Found` if user cannot be found.
|
- `404 User Not Found` if user cannot be found.
|
||||||
- `403 Forbidden` when trying to deactivate a user that is:
|
- `403 Forbidden` when trying to deactivate a user that is:
|
||||||
- Blocked by administrator or by LDAP synchronization.
|
- 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.
|
- Internal.
|
||||||
|
|
||||||
## Activate user **(FREE SELF)**
|
## Activate user **(FREE SELF)**
|
||||||
|
@ -1924,7 +1924,7 @@ Example Responses:
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339925) in GitLab 14.3.
|
> [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
|
```plaintext
|
||||||
POST /users/:id/reject
|
POST /users/:id/reject
|
||||||
|
|
|
@ -74,7 +74,7 @@ All Work Item types share the same pool of predefined widgets and are customized
|
||||||
| start and due date | |
|
| start and due date | |
|
||||||
| status\* | |
|
| status\* | |
|
||||||
| weight | |
|
| 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
|
\* status is not currently a widget, but a part of the root work item, similar to title
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ In contrast to a typical Snowplow pipeline, after enrichment, GitLab Snowplow ev
|
||||||
#### Why events need to be pseudonymized
|
#### 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/)
|
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
|
GitLab must provide valuable insights for business decisions, and there is a need
|
||||||
for a better understanding of different users' behavior patterns. The
|
for a better understanding of different users' behavior patterns. The
|
||||||
|
|
|
@ -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
|
If reviewing the corresponding JH file is needed, it should be found at
|
||||||
[JH repository](https://jihulab.com/gitlab-cn/gitlab).
|
[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
|
### General guidance for writing JH extensions
|
||||||
|
|
||||||
See [Guidelines for implementing Enterprise Edition features](ee_features.md)
|
See [Guidelines for implementing Enterprise Edition features](ee_features.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.
|
`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`
|
`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
|
### Configure initial settings
|
||||||
|
|
||||||
|
|
|
@ -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:
|
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
|
- [Review the audit events](../administration/audit_events.md) available to you to identify any suspicious account behavior. For
|
||||||
example:
|
example:
|
||||||
- Suspicious sign-in events.
|
- 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:
|
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 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.
|
- 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,
|
- Change any sensitive credentials, variables, tokens, and secrets. For example, those located in instance configuration, database,
|
||||||
CI/CD pipelines, or elsewhere.
|
CI/CD pipelines, or elsewhere.
|
||||||
|
|
|
@ -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
|
A _billable user_ counts against the number of subscription seats. Every user is considered a
|
||||||
billable user, with the following exceptions:
|
billable user, with the following exceptions:
|
||||||
|
|
||||||
- [Deactivated users](../../user/admin_area/moderate_users.md#deactivate-a-user) and
|
- [Deactivated users](../../administration/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
|
[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.
|
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 [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 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.
|
- 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:
|
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. 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.
|
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.
|
The **Renew** button remains disabled (grayed-out) until 15 days before a subscription expires.
|
||||||
|
|
|
@ -1,393 +1,11 @@
|
||||||
---
|
---
|
||||||
stage: Manage
|
redirect_to: '../../administration/moderate_users.md'
|
||||||
group: Authentication and Authorization
|
remove_date: '2023-10-12'
|
||||||
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 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).
|
<!-- This redirect file can be deleted after <2023-10-12>. -->
|
||||||
|
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||||
GitLab administrators can moderate user access by approving, blocking, banning, or deactivating
|
<!-- 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. -->
|
||||||
users.
|
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||||
|
|
||||||
## 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
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,240 +1,11 @@
|
||||||
---
|
---
|
||||||
stage: none
|
redirect_to: '../../../administration/settings/user_and_ip_rate_limits.md'
|
||||||
group: unassigned
|
remove_date: '2023-10-14'
|
||||||
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)**
|
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
|
<!-- This redirect file can be deleted after <2023-10-14>. -->
|
||||||
of a web application. For more details, see
|
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||||
[Rate limits](../../../security/rate_limits.md).
|
<!-- 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 -->
|
||||||
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. -->
|
|
||||||
|
|
|
@ -46,20 +46,14 @@ The following feature is in Beta:
|
||||||
|
|
||||||
## Experiment AI features
|
## Experiment AI features
|
||||||
|
|
||||||
[Experiment features](../policy/experiment-beta-support.md#experiment) will soon require
|
[Experiment](../policy/experiment-beta-support.md#experiment) AI features require
|
||||||
[Experiment features to be enabled](group/manage.md#enable-experiment-features).
|
[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).
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
### Explain Selected Code in the Web UI **(ULTIMATE SAAS)**
|
### 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.
|
> 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:
|
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:
|
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 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:
|
To explain your code:
|
||||||
|
|
||||||
|
|
|
@ -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
|
### 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.
|
- 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.
|
- 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).
|
- 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).
|
||||||
|
|
|
@ -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.
|
> - 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
|
> - 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.
|
> - 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
|
FLAG:
|
||||||
schedule or with the project pipeline. The security scan runs with multiple project pipelines if you define the policy
|
On self-managed GitLab, this feature is enabled by default. To disable it, ask an
|
||||||
at a group or subgroup level. GitLab injects the required scans into the CI pipeline as new jobs. In the event
|
administrator to [disable the feature flag](../../../administration/feature_flags.md) named
|
||||||
of a job name collision, GitLab adds a dash and a number to the job name. GitLab increments the number until the name
|
`scan_execution_policy_pipelines`. On GitLab.com, this feature is enabled.
|
||||||
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.
|
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),
|
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).
|
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
|
||||||
|
|
|
@ -355,8 +355,8 @@ for GitLab.com, see
|
||||||
|
|
||||||
For information on rate limiting responses, 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).
|
- [List of headers on responses to blocked requests](../../administration/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).
|
- [Customizable response text](../../administration/settings/user_and_ip_rate_limits.md#use-a-custom-rate-limit-response).
|
||||||
|
|
||||||
### Protected paths throttle
|
### 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,
|
See the source below for which paths are protected. This includes user creation,
|
||||||
user confirmation, user sign in, and password reset.
|
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.
|
includes a list of the headers responded to blocked requests.
|
||||||
|
|
||||||
See [Protected Paths](../admin_area/settings/protected_paths.md) for more details.
|
See [Protected Paths](../admin_area/settings/protected_paths.md) for more details.
|
||||||
|
|
|
@ -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.
|
> [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.
|
A group Owner can moderate user access by banning and unbanning users.
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ As a user, to delete your own account:
|
||||||
1. Select **Delete account**.
|
1. Select **Delete account**.
|
||||||
|
|
||||||
NOTE:
|
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)**
|
## Delete users and user contributions **(FREE SELF)**
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ When deleting users, you can either:
|
||||||
- Personal access tokens.
|
- Personal access tokens.
|
||||||
- Snippets.
|
- 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
|
When a user is deleted from an [abuse report](../../../administration/review_abuse_reports.md) or spam log, these associated
|
||||||
records are always removed.
|
records are always removed.
|
||||||
|
|
|
@ -73,7 +73,7 @@ Your account has been blocked. Fatal: Could not read from remote repository
|
||||||
Your primary email address is not confirmed.
|
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.
|
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?
|
## What do you need to know as an administrator of a GitLab self-managed Instance?
|
||||||
|
|
|
@ -15807,6 +15807,9 @@ msgstr ""
|
||||||
msgid "Descriptive label"
|
msgid "Descriptive label"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Deselect all"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Design"
|
msgid "Design"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -19377,6 +19380,9 @@ msgstr ""
|
||||||
msgid "Filter"
|
msgid "Filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Filter activity"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Filter by"
|
msgid "Filter by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -49936,9 +49942,6 @@ msgstr ""
|
||||||
msgid "UserList|created %{timeago}"
|
msgid "UserList|created %{timeago}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfiles|No snippets found."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "UserProfile|%{count} %{file}"
|
msgid "UserProfile|%{count} %{file}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -49993,6 +49996,9 @@ msgstr ""
|
||||||
msgid "UserProfile|Following"
|
msgid "UserProfile|Following"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|Get started with snippets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|Groups"
|
msgid "UserProfile|Groups"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -50032,15 +50038,24 @@ msgstr ""
|
||||||
msgid "UserProfile|Starred projects"
|
msgid "UserProfile|Starred projects"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|Store, share, and embed bits of code and text."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|Subscribe"
|
msgid "UserProfile|Subscribe"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|There are no projects available to be displayed here."
|
msgid "UserProfile|There are no projects available to be displayed here."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|This user doesn't have any followers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|This user doesn't have any followers."
|
msgid "UserProfile|This user doesn't have any followers."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|This user doesn't have any snippets"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|This user has a private profile"
|
msgid "UserProfile|This user has a private profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -50053,6 +50068,9 @@ msgstr ""
|
||||||
msgid "UserProfile|This user is blocked"
|
msgid "UserProfile|This user is blocked"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|This user isn't following other users"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|This user isn't following other users."
|
msgid "UserProfile|This user isn't following other users."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -50074,12 +50092,18 @@ msgstr ""
|
||||||
msgid "UserProfile|View user in admin area"
|
msgid "UserProfile|View user in admin area"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|You are not following other users"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|You are not following other users."
|
msgid "UserProfile|You are not following other users."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|You can create a group for several dependent projects."
|
msgid "UserProfile|You can create a group for several dependent projects."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "UserProfile|You do not have any followers"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "UserProfile|You do not have any followers."
|
msgid "UserProfile|You do not have any followers."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports groups and labels',
|
'successfully imports groups and labels',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347674',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347674'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415270"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_group_import_finished_successfully
|
expect_group_import_finished_successfully
|
||||||
|
|
||||||
|
@ -80,11 +76,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports group milestones and badges',
|
'successfully imports group milestones and badges',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347628',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347628'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415270"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_group_import_finished_successfully
|
expect_group_import_finished_successfully
|
||||||
|
|
||||||
|
|
|
@ -43,11 +43,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports issue',
|
'successfully imports issue',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347608',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347608'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415247"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
expect(imported_issues.count).to eq(1)
|
expect(imported_issues.count).to eq(1)
|
||||||
|
@ -71,11 +67,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'preserves related merge request',
|
'preserves related merge request',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/386305'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415247"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
expect(imported_related_mrs).to eq([source_mr.iid])
|
expect(imported_related_mrs).to eq([source_mr.iid])
|
||||||
|
@ -99,11 +91,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports design',
|
'successfully imports design',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366449',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366449'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415247"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
expect(imported_issues.count).to eq(1)
|
expect(imported_issues.count).to eq(1)
|
||||||
|
|
|
@ -33,11 +33,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'member retains indirect membership in imported project',
|
'member retains indirect membership in imported project',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354416',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354416'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415271"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
@ -55,11 +51,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'member retains direct membership in imported project',
|
'member retains direct membership in imported project',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354417',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354417'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415271"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,8 @@ module QA
|
||||||
'successfully imports merge request',
|
'successfully imports merge request',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348478',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348478',
|
||||||
quarantine: {
|
quarantine: {
|
||||||
type: :investigating,
|
type: :bug,
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415245"
|
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/414859"
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
|
@ -45,11 +45,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports ci pipeline',
|
'successfully imports ci pipeline',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354650',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354650'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415272"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
|
|
@ -35,11 +35,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports project',
|
'successfully imports project',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383351',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383351'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415672"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
@ -50,11 +46,7 @@ module QA
|
||||||
context 'with uninitialized project' do
|
context 'with uninitialized project' do
|
||||||
it(
|
it(
|
||||||
'successfully imports project',
|
'successfully imports project',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347610',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347610'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415246"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
@ -103,11 +95,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports repository',
|
'successfully imports repository',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347570',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347570'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415246"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
@ -126,11 +114,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports project wiki',
|
'successfully imports project wiki',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347567',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347567'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415246"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,10 @@ module QA
|
||||||
commit_path: release[:commit_path].split("/-/").last,
|
commit_path: release[:commit_path].split("/-/").last,
|
||||||
tag_path: release[:tag_path].split("/-/").last,
|
tag_path: release[:tag_path].split("/-/").last,
|
||||||
assets: release[:assets].merge({
|
assets: release[:assets].merge({
|
||||||
sources: release.dig(:assets, :sources).map do |source|
|
sources: release.dig(:assets, :sources).map do |source|
|
||||||
source.merge({ url: source[:url].split("/-/").last })
|
source.merge({ url: source[:url].split("/-/").last })
|
||||||
end
|
end
|
||||||
}),
|
}),
|
||||||
milestones: release[:milestones].map do |milestone|
|
milestones: release[:milestones].map do |milestone|
|
||||||
milestone.except(:id, :project_id).merge({ web_url: milestone[:web_url].split("/-/").last })
|
milestone.except(:id, :project_id).merge({ web_url: milestone[:web_url].split("/-/").last })
|
||||||
end,
|
end,
|
||||||
|
@ -58,11 +58,7 @@ module QA
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'successfully imports project release',
|
'successfully imports project release',
|
||||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360243',
|
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360243'
|
||||||
quarantine: {
|
|
||||||
type: :investigating,
|
|
||||||
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/415292"
|
|
||||||
}
|
|
||||||
) do
|
) do
|
||||||
expect_project_import_finished_successfully
|
expect_project_import_finished_successfully
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module QA
|
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
|
describe 'rate limits', :reliable, product_group: :import_and_integrate do
|
||||||
let(:rate_limited_user) { Resource::User.fabricate_via_api! }
|
let(:rate_limited_user) { Resource::User.fabricate_via_api! }
|
||||||
let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) }
|
let(:api_client) { Runtime::API::Client.new(:gitlab, user: rate_limited_user) }
|
||||||
|
|
|
@ -1140,4 +1140,38 @@ describe('common_utils', () => {
|
||||||
expect(result).toEqual([{ hello: '' }, { helloWorld: '' }]);
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -67,7 +67,7 @@ describe('Merge request discussion filter component', () => {
|
||||||
it('lists current filters', () => {
|
it('lists current filters', () => {
|
||||||
createComponent();
|
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 () => {
|
it('updates store when selecting filter', async () => {
|
||||||
|
@ -107,4 +107,30 @@ describe('Merge request discussion filter component', () => {
|
||||||
|
|
||||||
expect(wrapper.findComponent(GlButton).text()).toBe(expectedText);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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 { shallowMount } from '@vue/test-utils';
|
||||||
|
|
||||||
import users from 'test_fixtures/api/users/followers/get.json';
|
import users from 'test_fixtures/api/users/followers/get.json';
|
||||||
import Follow from '~/profile/components/follow.vue';
|
import Follow from '~/profile/components/follow.vue';
|
||||||
import { DEFAULT_PER_PAGE } from '~/api';
|
import { DEFAULT_PER_PAGE } from '~/api';
|
||||||
|
import { isCurrentUser } from '~/lib/utils/common_utils';
|
||||||
|
|
||||||
jest.mock('~/rest_api');
|
jest.mock('~/rest_api');
|
||||||
|
jest.mock('~/lib/utils/common_utils');
|
||||||
|
|
||||||
describe('FollowersTab', () => {
|
describe('FollowersTab', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
@ -15,6 +23,13 @@ describe('FollowersTab', () => {
|
||||||
loading: false,
|
loading: false,
|
||||||
page: 1,
|
page: 1,
|
||||||
totalItems: 50,
|
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 = {} } = {}) => {
|
const createComponent = ({ propsData = {} } = {}) => {
|
||||||
|
@ -23,11 +38,13 @@ describe('FollowersTab', () => {
|
||||||
...defaultPropsData,
|
...defaultPropsData,
|
||||||
...propsData,
|
...propsData,
|
||||||
},
|
},
|
||||||
|
provide: defaultProvide,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const findPagination = () => wrapper.findComponent(GlPagination);
|
const findPagination = () => wrapper.findComponent(GlPagination);
|
||||||
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||||
|
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||||
|
|
||||||
describe('when `loading` prop is `true`', () => {
|
describe('when `loading` prop is `true`', () => {
|
||||||
it('renders loading icon', () => {
|
it('renders loading icon', () => {
|
||||||
|
@ -95,5 +112,35 @@ describe('FollowersTab', () => {
|
||||||
expect(wrapper.emitted('pagination-input')).toEqual([[nextPage]]);
|
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,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -75,6 +75,8 @@ describe('FollowersTab', () => {
|
||||||
loading: false,
|
loading: false,
|
||||||
page: 1,
|
page: 1,
|
||||||
totalItems: 6,
|
totalItems: 6,
|
||||||
|
currentUserEmptyStateTitle: FollowersTab.i18n.currentUserEmptyStateTitle,
|
||||||
|
visitorEmptyStateTitle: FollowersTab.i18n.visitorEmptyStateTitle,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ describe('FollowingTab', () => {
|
||||||
loading: false,
|
loading: false,
|
||||||
page: MOCK_PAGE,
|
page: MOCK_PAGE,
|
||||||
totalItems: MOCK_TOTAL_FOLLOWING,
|
totalItems: MOCK_TOTAL_FOLLOWING,
|
||||||
|
currentUserEmptyStateTitle: FollowingTab.i18n.currentUserEmptyStateTitle,
|
||||||
|
visitorEmptyStateTitle: FollowingTab.i18n.visitorEmptyStateTitle,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { SNIPPET_MAX_LIST_COUNT } from '~/profile/constants';
|
||||||
import SnippetsTab from '~/profile/components/snippets/snippets_tab.vue';
|
import SnippetsTab from '~/profile/components/snippets/snippets_tab.vue';
|
||||||
import SnippetRow from '~/profile/components/snippets/snippet_row.vue';
|
import SnippetRow from '~/profile/components/snippets/snippet_row.vue';
|
||||||
import getUserSnippets from '~/profile/components/graphql/get_user_snippets.query.graphql';
|
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 { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
import {
|
import {
|
||||||
|
@ -15,8 +16,14 @@ import {
|
||||||
MOCK_USER_SNIPPETS_RES,
|
MOCK_USER_SNIPPETS_RES,
|
||||||
MOCK_USER_SNIPPETS_PAGINATION_RES,
|
MOCK_USER_SNIPPETS_PAGINATION_RES,
|
||||||
MOCK_USER_SNIPPETS_EMPTY_RES,
|
MOCK_USER_SNIPPETS_EMPTY_RES,
|
||||||
|
MOCK_NEW_SNIPPET_PATH,
|
||||||
} from 'jest/profile/mock_data';
|
} 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);
|
Vue.use(VueApollo);
|
||||||
|
|
||||||
describe('UserProfileSnippetsTab', () => {
|
describe('UserProfileSnippetsTab', () => {
|
||||||
|
@ -32,6 +39,7 @@ describe('UserProfileSnippetsTab', () => {
|
||||||
provide: {
|
provide: {
|
||||||
userId: MOCK_USER.id,
|
userId: MOCK_USER.id,
|
||||||
snippetsEmptyState: MOCK_SNIPPETS_EMPTY_STATE,
|
snippetsEmptyState: MOCK_SNIPPETS_EMPTY_STATE,
|
||||||
|
newSnippetPath: MOCK_NEW_SNIPPET_PATH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -52,9 +60,38 @@ describe('UserProfileSnippetsTab', () => {
|
||||||
expect(findSnippetRows().exists()).toBe(false);
|
expect(findSnippetRows().exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does render empty state with correct svg', () => {
|
describe('when user is the current user', () => {
|
||||||
expect(findGlEmptyState().exists()).toBe(true);
|
beforeEach(() => {
|
||||||
expect(findGlEmptyState().attributes('svgpath')).toBe(MOCK_SNIPPETS_EMPTY_STATE);
|
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,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const userCalendarResponse = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MOCK_SNIPPETS_EMPTY_STATE = 'illustrations/empty-state/empty-snippets-md.svg';
|
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 = {
|
export const MOCK_USER = {
|
||||||
id: '1',
|
id: '1',
|
||||||
|
|
|
@ -95,14 +95,10 @@ describe('Work Item Note', () => {
|
||||||
updateWorkItemMutationHandler = updateWorkItemMutationSuccessHandler,
|
updateWorkItemMutationHandler = updateWorkItemMutationSuccessHandler,
|
||||||
assignees = mockAssignees,
|
assignees = mockAssignees,
|
||||||
workItemByIidResponseHandler = workItemResponseHandler,
|
workItemByIidResponseHandler = workItemResponseHandler,
|
||||||
workItemsMvc2 = false,
|
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
wrapper = shallowMount(WorkItemNote, {
|
wrapper = shallowMount(WorkItemNote, {
|
||||||
provide: {
|
provide: {
|
||||||
fullPath: 'test-project-path',
|
fullPath: 'test-project-path',
|
||||||
glFeatures: {
|
|
||||||
workItemsMvc2,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
propsData: {
|
propsData: {
|
||||||
workItemId,
|
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', () => {
|
it('passes note props to awards list', () => {
|
||||||
createComponent({ note: mockWorkItemCommentNote, workItemsMvc2: true });
|
createComponent({ note: mockWorkItemCommentNote, workItemsMvc2: true });
|
||||||
|
|
||||||
|
|
|
@ -496,13 +496,17 @@ RSpec.describe UsersHelper do
|
||||||
|
|
||||||
describe '#user_profile_tabs_app_data' do
|
describe '#user_profile_tabs_app_data' do
|
||||||
before 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_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(: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(:followers, :count).and_return(2)
|
||||||
allow(user).to receive_message_chain(:followees, :count).and_return(3)
|
allow(user).to receive_message_chain(:followees, :count).and_return(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns expected hash' do
|
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({
|
expect(helper.user_profile_tabs_app_data(user)).to match({
|
||||||
followees_count: 3,
|
followees_count: 3,
|
||||||
followers_count: 2,
|
followers_count: 2,
|
||||||
|
@ -510,9 +514,21 @@ RSpec.describe UsersHelper do
|
||||||
user_activity_path: '/users/root/activity.json',
|
user_activity_path: '/users/root/activity.json',
|
||||||
utc_offset: 0,
|
utc_offset: 0,
|
||||||
user_id: user.id,
|
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
|
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
|
end
|
||||||
|
|
||||||
describe '#load_max_project_member_accesses' do
|
describe '#load_max_project_member_accesses' do
|
||||||
|
|
Loading…
Reference in New Issue