Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d00599dae8
commit
a3796779c9
|
|
@ -81,7 +81,6 @@ export default {
|
|||
'app/assets/javascripts/emoji/components/picker.vue',
|
||||
'app/assets/javascripts/error_tracking/components/error_details.vue',
|
||||
'app/assets/javascripts/error_tracking/components/error_tracking_list.vue',
|
||||
'app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue',
|
||||
'app/assets/javascripts/feature_flags/components/empty_state.vue',
|
||||
'app/assets/javascripts/feature_flags/components/environments_dropdown.vue',
|
||||
'app/assets/javascripts/feature_flags/components/feature_flags.vue',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ include:
|
|||
inputs:
|
||||
job_name: "e2e-test-report"
|
||||
job_stage: "report"
|
||||
report_title: "E2E Test Result Summary"
|
||||
report_title: '<a href="https://handbook.gitlab.com/handbook/engineering/testing/end-to-end-pipeline-monitoring/#allure-report">E2E Test Result Summary</a>'
|
||||
aws_access_key_id_variable_name: "QA_ALLURE_AWS_ACCESS_KEY_ID"
|
||||
aws_secret_access_key_variable_name: "QA_ALLURE_AWS_SECRET_ACCESS_KEY"
|
||||
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
|
||||
|
|
|
|||
|
|
@ -1225,9 +1225,8 @@
|
|||
- <<: *if-schedule-maintenance
|
||||
- <<: *if-dot-com-gitlab-org-default-branch
|
||||
changes: *assets-compilation-patterns
|
||||
# push assets for stable branches (canonical & security)
|
||||
- <<: *if-tag
|
||||
- <<: *if-sync-changes-on-stable-branches
|
||||
changes: *assets-compilation-patterns
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
changes:
|
||||
- ".gitlab/ci/caching.gitlab-ci.yml"
|
||||
|
|
@ -1238,6 +1237,7 @@
|
|||
- if: '$ENABLE_CACHE_ASSETS == "true"'
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- !reference [".releases:rules:canonical-dot-com-security-gitlab-stable-branch-only", rules]
|
||||
|
||||
.caching:rules:packages-cleanup:
|
||||
rules:
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
<script>
|
||||
import { GlCard, GlLoadingIcon } from '@gitlab/ui';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { mapState, mapGetters, mapActions } from 'vuex';
|
||||
import CrudComponent from '~/vue_shared/components/crud_component.vue';
|
||||
import statisticsLabels from '../constants';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlCard,
|
||||
GlLoadingIcon,
|
||||
CrudComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -28,24 +27,18 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<gl-card class="gl-h-full" body-class="gl-h-full gl-py-0">
|
||||
<template #header>
|
||||
<h3 class="gl-m-0 gl-inline-flex gl-items-center gl-gap-2 gl-self-center gl-text-base">
|
||||
{{ __('Statistics') }}
|
||||
</h3>
|
||||
</template>
|
||||
<template #default>
|
||||
<gl-loading-icon v-if="isLoading" size="md" class="my-3" />
|
||||
<template v-else>
|
||||
<p
|
||||
v-for="statistic in getStatistics(statisticsLabels)"
|
||||
:key="statistic.key"
|
||||
:class="['js-stats', 'gl-py-4', 'gl-m-0', 'gl-border-b', 'last:gl-border-b-0']"
|
||||
>
|
||||
{{ statistic.label }}
|
||||
<span class="light gl-float-right">{{ statistic.value }}</span>
|
||||
</p>
|
||||
</template>
|
||||
</template>
|
||||
</gl-card>
|
||||
<crud-component
|
||||
:is-loading="isLoading"
|
||||
:title="__('Statistics')"
|
||||
:body-class="{ '!gl-mt-0': !isLoading }"
|
||||
>
|
||||
<p
|
||||
v-for="statistic in getStatistics(statisticsLabels)"
|
||||
:key="statistic.key"
|
||||
:class="['js-stats', 'gl-py-4', 'gl-m-0', 'gl-border-b', 'last:gl-border-b-0']"
|
||||
>
|
||||
{{ statistic.label }}
|
||||
<span class="light gl-float-right">{{ statistic.value }}</span>
|
||||
</p>
|
||||
</crud-component>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -87,14 +87,7 @@ export default {
|
|||
'isProjectInvalid',
|
||||
'projectSelectionLabel',
|
||||
]),
|
||||
...mapState([
|
||||
'enabled',
|
||||
'integrated',
|
||||
'projects',
|
||||
'selectedProject',
|
||||
'settingsLoading',
|
||||
'token',
|
||||
]),
|
||||
...mapState(['enabled', 'integrated', 'projects', 'selectedProject', 'settingsLoading']),
|
||||
showGitlabDsnSetting() {
|
||||
return this.integrated && this.enabled && this.gitlabDsn;
|
||||
},
|
||||
|
|
@ -218,7 +211,6 @@ export default {
|
|||
:project-selection-label="projectSelectionLabel"
|
||||
:projects="projects"
|
||||
:selected-project="selectedProject"
|
||||
:token="token"
|
||||
@select-project="updateSelectedProject"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
token: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
listboxItems() {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ export default {
|
|||
<work-item-attribute
|
||||
v-if="datesText"
|
||||
anchor-id="issuable-due-date"
|
||||
wrapper-component-class="issuable-due-date"
|
||||
wrapper-component="button"
|
||||
wrapper-component-class="issuable-due-date !gl-cursor-help gl-text-subtle gl-bg-transparent gl-border-0 gl-p-0 focus-visible:gl-focus-inset"
|
||||
:title="datesText"
|
||||
title-component-class="gl-mr-3"
|
||||
:tooltip-text="datesTooltipTitle"
|
||||
|
|
|
|||
|
|
@ -68,12 +68,13 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<component :is="isLink ? 'gl-link' : 'span'" :href="href">
|
||||
<component :is="isLink ? 'gl-link' : 'span'" :href="isLink ? href : null">
|
||||
<!-- wrapper -->
|
||||
<component
|
||||
:is="wrapperComponent"
|
||||
ref="wrapperRef"
|
||||
:class="wrapperComponentClass"
|
||||
:href="!isLink ? href : null"
|
||||
:data-testid="anchorId"
|
||||
>
|
||||
<!-- icon -->
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ export default {
|
|||
<work-item-attribute
|
||||
anchor-id="issuable-milestone"
|
||||
:title="milestone.title"
|
||||
wrapper-component-class="gl-text-sm !gl-text-subtle"
|
||||
wrapper-component="a"
|
||||
wrapper-component-class="!gl-text-subtle !gl-cursor-help gl-bg-transparent gl-border-0 gl-p-0 focus-visible:gl-focus-inset"
|
||||
:tooltip-text="milestoneDate"
|
||||
tooltip-placement="top"
|
||||
class="issuable-milestone gl-mr-3"
|
||||
is-link
|
||||
:href="milestoneLink"
|
||||
>
|
||||
<template #icon>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import WorkItemBulkEditAssignee from './work_item_bulk_edit_assignee.vue';
|
|||
import WorkItemBulkEditDropdown from './work_item_bulk_edit_dropdown.vue';
|
||||
import WorkItemBulkEditLabels from './work_item_bulk_edit_labels.vue';
|
||||
|
||||
const WorkItemBulkEditIteration = () =>
|
||||
import('ee_component/work_items/components/list/work_item_bulk_edit_iteration.vue');
|
||||
|
||||
export default {
|
||||
name: 'WorkItemBulkEditSidebar',
|
||||
confidentialityItems: [
|
||||
|
|
@ -37,9 +40,10 @@ export default {
|
|||
WorkItemBulkEditAssignee,
|
||||
WorkItemBulkEditDropdown,
|
||||
WorkItemBulkEditLabels,
|
||||
WorkItemBulkEditIteration,
|
||||
},
|
||||
mixins: [glFeatureFlagsMixin()],
|
||||
inject: ['hasIssuableHealthStatusFeature'],
|
||||
inject: ['hasIssuableHealthStatusFeature', 'hasIterationsFeature'],
|
||||
props: {
|
||||
checkedItems: {
|
||||
type: Array,
|
||||
|
|
@ -70,6 +74,7 @@ export default {
|
|||
removeLabelIds: [],
|
||||
state: undefined,
|
||||
subscription: undefined,
|
||||
iteration: undefined,
|
||||
};
|
||||
},
|
||||
apollo: {
|
||||
|
|
@ -155,6 +160,7 @@ export default {
|
|||
healthStatus: camelCase(this.healthStatus),
|
||||
}
|
||||
: undefined,
|
||||
iterationWidget: this.iteration ? { iterationId: this.iteration } : undefined,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -239,5 +245,11 @@ export default {
|
|||
:label="__('Confidentiality')"
|
||||
data-testid="bulk-edit-confidentiality"
|
||||
/>
|
||||
<work-item-bulk-edit-iteration
|
||||
v-if="shouldUseGraphQLBulkEdit && !isEpicsList && hasIterationsFeature"
|
||||
v-model="iteration"
|
||||
:full-path="fullPath"
|
||||
:is-group="isGroup"
|
||||
/>
|
||||
</gl-form>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -256,39 +256,48 @@ export default {
|
|||
await this.updateLabels({ addLabelIds, removeLabelIds });
|
||||
}
|
||||
},
|
||||
updateDraftCache() {
|
||||
updateDraftCache(removeLabelIds = []) {
|
||||
let labels = this.labelsCache.filter(({ id }) => this.selectedLabelsIds.includes(id));
|
||||
if (removeLabelIds.length) {
|
||||
labels = labels.filter(({ id }) => !removeLabelIds.includes(id));
|
||||
}
|
||||
|
||||
this.$emit('updateWidgetDraft', {
|
||||
workItemType: this.workItemType,
|
||||
fullPath: this.fullPath,
|
||||
labels: this.labelsCache.filter(({ id }) => this.selectedLabelsIds.includes(id)),
|
||||
labels,
|
||||
});
|
||||
},
|
||||
async updateLabels({ addLabelIds = [], removeLabelIds = [] }) {
|
||||
try {
|
||||
this.updateInProgress = true;
|
||||
|
||||
const {
|
||||
data: {
|
||||
workItemUpdate: { errors },
|
||||
},
|
||||
} = await this.$apollo.mutate({
|
||||
mutation: updateWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.workItemId,
|
||||
labelsWidget: {
|
||||
addLabelIds,
|
||||
removeLabelIds,
|
||||
if (this.isCreateFlow) {
|
||||
this.updateDraftCache(removeLabelIds);
|
||||
} else {
|
||||
const {
|
||||
data: {
|
||||
workItemUpdate: { errors },
|
||||
},
|
||||
} = await this.$apollo.mutate({
|
||||
mutation: updateWorkItemMutation,
|
||||
variables: {
|
||||
input: {
|
||||
id: this.workItemId,
|
||||
labelsWidget: {
|
||||
addLabelIds,
|
||||
removeLabelIds,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new Error();
|
||||
if (errors.length > 0) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
this.track('updated_labels');
|
||||
}
|
||||
|
||||
this.track('updated_labels');
|
||||
this.$emit('labelsUpdated', [...addLabelIds, ...removeLabelIds]);
|
||||
} catch {
|
||||
this.$emit('error', i18n.updateError);
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ module ProjectsHelper
|
|||
return unless current_user
|
||||
return if project.empty_repo?
|
||||
|
||||
if current_user.already_forked?(project) && !current_user.has_forkable_groups?
|
||||
if current_user.already_forked?(project) && !current_user.has_groups_allowing_project_creation?
|
||||
user_fork_url = namespace_project_path(current_user, current_user.fork_of(project))
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1572,7 +1572,7 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def can_select_namespace?
|
||||
several_namespaces? || admin
|
||||
has_groups_allowing_project_creation? || admin
|
||||
end
|
||||
|
||||
def can?(action, subject = :global, **opts)
|
||||
|
|
@ -1617,15 +1617,6 @@ class User < ApplicationRecord
|
|||
end
|
||||
# rubocop: enable CodeReuse/ServiceClass
|
||||
|
||||
def several_namespaces?
|
||||
union_sql = ::Gitlab::SQL::Union.new(
|
||||
[owned_groups,
|
||||
maintainers_groups,
|
||||
groups_with_developer_project_access]).to_sql
|
||||
|
||||
::Group.from("(#{union_sql}) #{::Group.table_name}").any?
|
||||
end
|
||||
|
||||
def namespace_id
|
||||
namespace.try :id
|
||||
end
|
||||
|
|
@ -2011,14 +2002,13 @@ class User < ApplicationRecord
|
|||
enabled_following && user.enabled_following
|
||||
end
|
||||
|
||||
def has_forkable_groups?
|
||||
Groups::AcceptingProjectCreationsFinder.new(self).execute.exists?
|
||||
def has_groups_allowing_project_creation?
|
||||
groups_allowing_project_creation.exists?
|
||||
end
|
||||
|
||||
def forkable_namespaces
|
||||
strong_memoize(:forkable_namespaces) do
|
||||
personal_namespace = Namespace.where(id: namespace_id)
|
||||
groups_allowing_project_creation = Groups::AcceptingProjectCreationsFinder.new(self).execute
|
||||
|
||||
Namespace.from_union(
|
||||
[
|
||||
|
|
@ -2899,9 +2889,7 @@ class User < ApplicationRecord
|
|||
def ci_owned_project_runners_from_project_members
|
||||
project_ids = ci_project_ids_for_project_members(Gitlab::Access::MAINTAINER)
|
||||
|
||||
Ci::Runner
|
||||
.joins(:runner_projects)
|
||||
.where(runner_projects: { project: project_ids })
|
||||
Ci::Runner.belonging_to_project(project_ids)
|
||||
end
|
||||
|
||||
def ci_owned_project_runners_from_group_members
|
||||
|
|
@ -2989,6 +2977,10 @@ class User < ApplicationRecord
|
|||
errors.add(:username, _('has already been taken'))
|
||||
end
|
||||
end
|
||||
|
||||
def groups_allowing_project_creation
|
||||
Groups::AcceptingProjectCreationsFinder.new(self).execute
|
||||
end
|
||||
end
|
||||
|
||||
User.prepend_mod_with('User')
|
||||
|
|
|
|||
|
|
@ -30,78 +30,59 @@
|
|||
.admin-dashboard.gl-mt-3{ data: { event_tracking_load: 'true', event_tracking: 'view_admin_dashboard_pageload' } }
|
||||
%h2.gl-heading-2= _('Instance overview')
|
||||
.gl-grid.md:gl-grid-cols-2.lg:gl-grid-cols-3.gl-gap-5
|
||||
- component_params = { card_options: { class: 'gl-h-full' }, header_options: { class: 'gl-flex gl-justify-between gl-items-start' }, body_options: { class: 'gl-h-full gl-pt-0' } }
|
||||
- component_params = { options: { class: 'gl-flex gl-flex-col gl-h-full' }, body_options: { class: 'gl-h-full gl-mt-0' } }
|
||||
- if current_user.can_admin_all_resources?
|
||||
= render Pajamas::CardComponent.new(**component_params) do |c|
|
||||
- c.with_header do
|
||||
%h3.gl-self-center.gl-text-base.gl-inline-flex.gl-gap-2.gl-items-center.gl-m-0
|
||||
- approximate_projects_count = approximate_count_with_delimiters(@counts, Project)
|
||||
= s_('AdminArea|Projects')
|
||||
= render Pajamas::BadgeComponent.new(approximate_projects_count, variant: :muted, aria: { hidden: "true" })
|
||||
= render ::Layouts::CrudComponent.new(s_('AdminArea|Projects'), count: approximate_count_with_delimiters(@counts, Project), **component_params) do |c|
|
||||
- c.with_actions do
|
||||
- if current_user.can_create_project?
|
||||
= render Pajamas::ButtonComponent.new(href: new_project_path, size: :small) do
|
||||
= s_('AdminArea|New project')
|
||||
- c.with_body do
|
||||
.gl-flex.gl-flex-col.gl-h-full
|
||||
- @projects.each do |project|
|
||||
.gl-flex.gl-py-4{ class: ('gl-border-b' if @projects.last != project) }
|
||||
.gl-mr-auto
|
||||
= link_to project.full_name, admin_project_path(project)
|
||||
%span.gl-whitespace-nowrap.gl-text-right.gl-text-sm.gl-text-subtle
|
||||
#{time_ago_with_tooltip(project.created_at)}
|
||||
.gl-grow
|
||||
.gl-pt-4
|
||||
= render Pajamas::ButtonComponent.new(href: admin_projects_path(sort: 'created_desc'), block: true) do
|
||||
= s_('AdminArea|View latest projects')
|
||||
= render Pajamas::CardComponent.new(**component_params) do |c|
|
||||
- c.with_header do
|
||||
%h3.gl-self-center.gl-text-base.gl-inline-flex.gl-gap-2.gl-items-center.gl-m-0
|
||||
= s_('AdminArea|Total Users')
|
||||
= render Pajamas::BadgeComponent.new(approximate_count_with_delimiters(@counts, User), variant: :muted, aria: { hidden: "true" })
|
||||
- @projects.each do |project|
|
||||
.gl-flex.gl-py-4{ class: ('gl-border-b' if @projects.last != project) }
|
||||
.gl-mr-auto
|
||||
= link_to project.full_name, admin_project_path(project)
|
||||
%span.gl-whitespace-nowrap.gl-text-right.gl-text-sm.gl-text-subtle
|
||||
#{time_ago_with_tooltip(project.created_at)}
|
||||
- c.with_footer do
|
||||
= render Pajamas::ButtonComponent.new(href: admin_projects_path(sort: 'created_desc'), block: true) do
|
||||
= s_('AdminArea|View latest projects')
|
||||
= render ::Layouts::CrudComponent.new(s_('AdminArea|Total Users'), count: approximate_count_with_delimiters(@counts, User), **component_params) do |c|
|
||||
- c.with_actions do
|
||||
= render Pajamas::ButtonComponent.new(href: new_admin_user_path, size: :small) do
|
||||
= s_('AdminArea|New user')
|
||||
- c.with_body do
|
||||
.gl-flex.gl-flex-col.gl-h-full
|
||||
- @users.each do |user|
|
||||
.gl-flex.gl-py-4{ class: ('gl-border-b' if @users.last != user) }
|
||||
.gl-mr-auto
|
||||
= link_to [:admin, user] do
|
||||
= user.name
|
||||
%span.gl-whitespace-nowrap.gl-text-right.gl-text-sm.gl-text-subtle
|
||||
#{time_ago_with_tooltip(user.created_at)}
|
||||
.gl-grow
|
||||
.gl-flex.gl-pt-4.gl-gap-3
|
||||
= render Pajamas::ButtonComponent.new(href: admin_users_path(sort: 'created_desc'), block: true) do
|
||||
= s_('AdminArea|View latest users')
|
||||
= render Pajamas::ButtonComponent.new(href: admin_dashboard_stats_path, block: true, button_options: { class: '!gl-mt-0'}) do
|
||||
= s_('AdminArea|Users statistics')
|
||||
= render Pajamas::CardComponent.new(**component_params) do |c|
|
||||
- c.with_header do
|
||||
%h3.gl-self-center.gl-text-base.gl-inline-flex.gl-gap-2.gl-items-center.gl-m-0
|
||||
- approximate_groups_count = approximate_count_with_delimiters(@counts, Group)
|
||||
= s_('AdminArea|Groups')
|
||||
= render Pajamas::BadgeComponent.new(approximate_groups_count, variant: :muted, aria: { hidden: "true" })
|
||||
- @users.each do |user|
|
||||
.gl-flex.gl-py-4{ class: ('gl-border-b' if @users.last != user) }
|
||||
.gl-mr-auto
|
||||
= link_to [:admin, user] do
|
||||
= user.name
|
||||
%span.gl-whitespace-nowrap.gl-text-right.gl-text-sm.gl-text-subtle
|
||||
#{time_ago_with_tooltip(user.created_at)}
|
||||
- c.with_footer do
|
||||
.gl-flex.gl-gap-3
|
||||
= render Pajamas::ButtonComponent.new(href: admin_users_path(sort: 'created_desc'), block: true) do
|
||||
= s_('AdminArea|View latest users')
|
||||
= render Pajamas::ButtonComponent.new(href: admin_dashboard_stats_path, block: true, button_options: { class: '!gl-mt-0'}) do
|
||||
= s_('AdminArea|Users statistics')
|
||||
= render ::Layouts::CrudComponent.new(s_('AdminArea|Groups'), count: approximate_count_with_delimiters(@counts, Group), **component_params) do |c|
|
||||
- c.with_actions do
|
||||
= render Pajamas::ButtonComponent.new(href: new_admin_group_path, size: :small) do
|
||||
= s_('AdminArea|New group')
|
||||
- c.with_body do
|
||||
.gl-flex.gl-flex-col.gl-h-full
|
||||
- @groups.each do |group|
|
||||
.gl-flex.gl-py-4{ class: ('gl-border-b' if @groups.last != group) }
|
||||
.gl-mr-auto
|
||||
= link_to [:admin, group] do
|
||||
= group.full_name
|
||||
%span.gl-whitespace-nowrap.gl-text-right.gl-text-sm.gl-text-subtle
|
||||
#{time_ago_with_tooltip(group.created_at)}
|
||||
.gl-grow
|
||||
.gl-pt-4
|
||||
= render Pajamas::ButtonComponent.new(href: admin_groups_path(sort: 'created_desc'), block: true) do
|
||||
= s_('AdminArea|View latest groups')
|
||||
- @groups.each do |group|
|
||||
.gl-flex.gl-py-4{ class: ('gl-border-b' if @groups.last != group) }
|
||||
.gl-mr-auto
|
||||
= link_to [:admin, group] do
|
||||
= group.full_name
|
||||
%span.gl-whitespace-nowrap.gl-text-right.gl-text-sm.gl-text-subtle
|
||||
#{time_ago_with_tooltip(group.created_at)}
|
||||
- c.with_footer do
|
||||
= render Pajamas::ButtonComponent.new(href: admin_groups_path(sort: 'created_desc'), block: true) do
|
||||
= s_('AdminArea|View latest groups')
|
||||
|
||||
#js-admin-statistics-container
|
||||
= render Pajamas::CardComponent.new(card_options: { class: 'gl-h-full' }, body_options: { class: 'gl-h-full gl-py-0' }) do |c|
|
||||
- c.with_header do
|
||||
%h3.gl-self-center.gl-text-base.gl-inline-flex.gl-gap-2.gl-items-center.gl-m-0
|
||||
= s_('AdminArea|Features')
|
||||
= render ::Layouts::CrudComponent.new(s_('AdminArea|Features'), options: { class: 'gl-h-full' }, body_options: { class: 'gl-h-full gl-py-0' }) do |c|
|
||||
- c.with_body do
|
||||
= feature_entry(_('Sign up'),
|
||||
href: general_admin_application_settings_path(anchor: 'js-signup-settings'),
|
||||
|
|
@ -137,10 +118,7 @@
|
|||
href: admin_runners_path,
|
||||
enabled: Gitlab.config.gitlab_ci.shared_runners_enabled,
|
||||
last: true)
|
||||
= render Pajamas::CardComponent.new(card_options: { class: 'gl-h-full' }, body_options: { class: 'gl-h-full gl-py-0' }) do |c|
|
||||
- c.with_header do
|
||||
%h3.gl-m-0.gl-inline-flex.gl-items-center.gl-gap-2.gl-self-center.gl-text-base
|
||||
= s_('AdminArea|Components')
|
||||
= render ::Layouts::CrudComponent.new(s_('AdminArea|Components'), options: { class: 'gl-h-full' }, body_options: { class: 'gl-h-full gl-py-0' }) do |c|
|
||||
- c.with_body do
|
||||
- if show_version_check?
|
||||
.gl-min-h-9.gl-py-4.gl-border-b
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: merge_request_merged_with_policy_violations
|
||||
description: A merge request merged with security policy violations
|
||||
introduced_by_issue: https://gitlab.com/gitlab-org/gitlab/-/work_items/549813
|
||||
introduced_by_mr: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/195775
|
||||
feature_category: security_policy_management
|
||||
milestone: '18.2'
|
||||
saved_to_database: true
|
||||
streamed: true
|
||||
scope: [Project]
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
migration_job_name: MigrateScimIdentities
|
||||
description: Migrate Group scoped scim identities to new table
|
||||
feature_category: system_access
|
||||
introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170565'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/170565
|
||||
milestone: '17.8'
|
||||
queued_migration_version: 20250106175246
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
finalized_by: '20250609233305'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeHkMigrateScimIdentities < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.2'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'MigrateScimIdentities',
|
||||
table_name: :scim_identities,
|
||||
column_name: :id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
4b66de59dfc5c2cf10047a57a9c2d13e18af615638221cd76e5eb7a2ac633415
|
||||
|
|
@ -12899,9 +12899,9 @@ CREATE TABLE compliance_management_frameworks (
|
|||
color text NOT NULL,
|
||||
namespace_id bigint NOT NULL,
|
||||
pipeline_configuration_full_path text,
|
||||
source_id bigint,
|
||||
created_at timestamp with time zone,
|
||||
updated_at timestamp with time zone,
|
||||
source_id bigint,
|
||||
CONSTRAINT check_08cd34b2c2 CHECK ((char_length(color) <= 10)),
|
||||
CONSTRAINT check_1617e0b87e CHECK ((char_length(description) <= 255)),
|
||||
CONSTRAINT check_ab00bc2193 CHECK ((char_length(name) <= 255)),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ The **Overview** page displays:
|
|||
- Instance details
|
||||
- Maintenance windows
|
||||
- Hosted runners
|
||||
- Customer communication
|
||||
|
||||
## Tenant overview
|
||||
|
||||
|
|
@ -79,3 +80,15 @@ To view the current NAT gateway IP addresses for your GitLab Dedicated instance:
|
|||
1. Select your tenant.
|
||||
1. Select the **Configuration** tab.
|
||||
1. Under **Tenant Details**, find your **NAT gateways**.
|
||||
|
||||
## Customer communication
|
||||
|
||||
The **Customer communication** section shows the **Operational email addresses** configured for your GitLab Dedicated instance. These email addresses receive notifications about your instance, including:
|
||||
|
||||
- Emergency maintenance
|
||||
- Incidents
|
||||
- Other critical updates
|
||||
|
||||
You cannot turn off notifications for operational email addresses.
|
||||
|
||||
To update your customer communication information, [submit a support ticket](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=4414917877650).
|
||||
|
|
|
|||
|
|
@ -225,6 +225,34 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
|
|||
|
||||
If successful, returns a [`204 No Content`](rest/troubleshooting.md#status-codes) status code.
|
||||
|
||||
### Delete cache entries for a virtual registry
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/538327) in GitLab 18.2 [with a flag](../administration/feature_flags/_index.md) named `maven_virtual_registry`. Disabled by default.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
Schedule all cache entries for deletion in all exclusive upstream registries for a Maven virtual registry. Cache entries are not scheduled for deletion for upstream registries that are associated with other virtual registries.
|
||||
|
||||
```plaintext
|
||||
DELETE /virtual_registries/packages/maven/registries/:id/cache
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer | yes | The ID of the Maven virtual registry. |
|
||||
|
||||
Example request:
|
||||
|
||||
```shell
|
||||
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--header "Accept: application/json" \
|
||||
--url "https://gitlab.example.com/api/v4/virtual_registries/packages/maven/registries/1/cache"
|
||||
```
|
||||
|
||||
If successful, returns a [`204 No Content`](rest/troubleshooting.md#status-codes) status code.
|
||||
|
||||
## Manage upstream registries
|
||||
|
||||
Use the following endpoints to configure and manage upstream Maven registries.
|
||||
|
|
@ -579,7 +607,7 @@ curl --request DELETE \
|
|||
|
||||
If successful, returns a [`204 No Content`](rest/troubleshooting.md#status-codes) status code.
|
||||
|
||||
### Purge cache entries for an upstream registry
|
||||
### Delete cache entries for an upstream registry
|
||||
|
||||
{{< history >}}
|
||||
|
||||
|
|
@ -587,7 +615,7 @@ If successful, returns a [`204 No Content`](rest/troubleshooting.md#status-codes
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
Purges all cache entries for a specific upstream registry in a Maven virtual registry.
|
||||
Schedules all cache entries for deletion for a specific upstream registry in a Maven virtual registry.
|
||||
|
||||
```plaintext
|
||||
DELETE /virtual_registries/packages/maven/upstreams/:id/cache
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ You can find all those directories listed in the [Linux package configuration do
|
|||
- [Review Runner security considerations and recommendations](https://docs.gitlab.com/runner/security/).
|
||||
- [Review CI/CD variables security considerations](../ci/variables/_index.md#cicd-variable-security).
|
||||
- [Review pipeline security for usage and protection of secrets in CI/CD Pipelines](../ci/pipelines/pipeline_security.md).
|
||||
- [Instance-wide compliance and security policy management](compliance_security_policy_management.md).
|
||||
|
||||
### Patching
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
---
|
||||
stage: Security Risk Management
|
||||
group: Security Policies
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Learn how to apply security policies and compliance frameworks across multiple groups and projects from a single, centralized location.
|
||||
title: Instance-wide compliance and security policy management
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab Self-Managed
|
||||
- Status: Beta
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/15864) in GitLab 18.2 [with a feature flag](../administration/feature_flags/_index.md) named `security_policies_csp`. Disabled by default.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
This feature is subject to change and may not ready for production use.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
To apply security policies across multiple groups and projects from a single and centralized location, instance administrators can designate a compliance and security policy (CSP) group. This allows the instance administrators to:
|
||||
|
||||
- Create and configure security policies that automatically apply across your instance.
|
||||
- Create compliance frameworks to make them available for other top-level groups.
|
||||
- Scope policies to apply to compliance frameworks, groups, projects, or your entire instance.
|
||||
- View comprehensive policy coverage to understand which policies are active and where they're active.
|
||||
- Maintain centralized control while allowing teams to create their own additional policies.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GitLab Self-Managed.
|
||||
- GitLab 18.2 or later.
|
||||
- You must be instance administrator.
|
||||
- You must have an existing top-level group to serve as the CSP group.
|
||||
- To use the REST API (optional), you must have a token with administrator access.
|
||||
|
||||
## Set up instance-wide compliance and security policy management
|
||||
|
||||
To set up instance-wide compliance and security policy management, you designate a CSP group and then create policies and compliance frameworks in the group.
|
||||
|
||||
### Designate a CSP group
|
||||
|
||||
You can designate a CSP group using either the GitLab UI or the REST API.
|
||||
|
||||
#### Using the GitLab UI
|
||||
|
||||
1. Go to **Admin Area** > **Settings** > **Security and Compliance**.
|
||||
1. In the **Designate CSP Group** section, select an existing top-level group from the dropdown list.
|
||||
1. Select **Save changes**.
|
||||
|
||||
#### Using the REST API
|
||||
|
||||
You can also designate a CSP group programmatically using the REST API. The API is useful for automation or when managing multiple instances.
|
||||
|
||||
To set a CSP group:
|
||||
|
||||
```shell
|
||||
curl --request PUT \
|
||||
--header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data '{"csp_namespace_id": 123456}' \
|
||||
--url "https://gitlab.example.com/api/v4/admin/security/policy_settings"
|
||||
```
|
||||
|
||||
To clear the CSP group:
|
||||
|
||||
```shell
|
||||
curl --request PUT \
|
||||
--header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data '{"csp_namespace_id": null}' \
|
||||
--url "https://gitlab.example.com/api/v4/admin/security/policy_settings"
|
||||
```
|
||||
|
||||
To get the current CSP settings:
|
||||
|
||||
```shell
|
||||
curl --request GET \
|
||||
--header "PRIVATE-TOKEN: <your_access_token>" \
|
||||
--url "https://gitlab.example.com/api/v4/admin/security/policy_settings"
|
||||
```
|
||||
|
||||
For more information, see the [policy settings API documentation](../api/policy_settings.md).
|
||||
|
||||
The selected group becomes your compliance and security policy (CSP) group, serving as the central place to manage security policies and compliance frameworks across your instance.
|
||||
|
||||
### Security policy management in the CSP group
|
||||
|
||||
See the [centralized security policy management](../user/application_security/policies/centralized_security_policy_management.md) documentation.
|
||||
|
||||
## User workflows
|
||||
|
||||
### Instance administrators
|
||||
|
||||
Instance administrators can:
|
||||
|
||||
1. **Designate a CSP group** from your existing top-level groups
|
||||
1. **Create CSP security policies** in the designated group
|
||||
1. **Configure policy scope** to determine where policies apply
|
||||
1. **View policy coverage** to understand which policies are active across groups and projects
|
||||
1. **Edit and manage** centralized policies as needed
|
||||
|
||||
### Group administrators and owners
|
||||
|
||||
Group administrators and owners can:
|
||||
|
||||
- View all applicable policies in **Secure** > **Policies**, including both locally-defined and centrally-managed policies.
|
||||
- Create team-specific policies in addition to centrally-managed ones.
|
||||
- Understand policy sources with clear indicators that show whether policies come from your team or central administration.
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
||||
The **Policies** page displays only the policies from the CSP that are currently applied to your group.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
### Project administrators and owners
|
||||
|
||||
Project administrators and owners can:
|
||||
|
||||
- View all applicable policies in **Secure** > **Policies**, including both locally-defined and centrally-managed policies.
|
||||
- Create project-specific policies in addition to centrally-managed ones.
|
||||
- Understand policy sources with clear indicators that show whether policies come from your project, group, or central administration.
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
||||
The **Policies** page displays only the policies from the CSP that are currently applied to your group.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
### Developers
|
||||
|
||||
Developers can:
|
||||
|
||||
- View all security policies that apply to your work in the **Secure** > **Policies**.
|
||||
- Understand security and compliance requirements with clear visibility into centrally-mandated policies.
|
||||
|
||||
## Beta considerations
|
||||
|
||||
- Performance testing: While using a CSP in not expected to impact performance, comprehensive performance testing is ongoing.
|
||||
- Mixed permission scenarios: Some edge cases with mixed permissions may require additional validation
|
||||
- User experience: Some UI elements may not be fully polished and could change in future releases
|
||||
- Compliance framework scoping: Scoping policies to compliance frameworks is not supported in the Beta release.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Unable to designate CSP group**
|
||||
|
||||
- Verify that you have instance administrator privileges.
|
||||
- Verify that the group is a top-level group (not a subgroup).
|
||||
- Verify that the group exists and is accessible.
|
||||
|
||||
## Feedback and support
|
||||
|
||||
As this is a Beta release, we actively seek feedback from users. Share your experience, suggestions, and any issues through:
|
||||
|
||||
- [GitLab Issues](https://gitlab.com/gitlab-org/gitlab/-/issues).
|
||||
- Your regular GitLab support channels.
|
||||
|
|
@ -292,7 +292,9 @@ build:
|
|||
|
||||
##### pip
|
||||
|
||||
If your project provides a `requirements.txt` lock file generated by the [pip-compile command line tool](https://pip-tools.readthedocs.io/en/latest/cli/pip-compile/), the Dependency Scanning analyzer can extract the list of components and the dependency graph information, which provides support for the [dependency path](../../dependency_list/_index.md#dependency-paths) feature.
|
||||
If your project provides a `requirements.txt` lock file generated by the [pip-compile command line tool](https://pip-tools.readthedocs.io/en/latest/cli/pip-compile/),
|
||||
the Dependency Scanning analyzer can extract the list of components and the dependency graph information,
|
||||
which provides support for the [dependency path](../../dependency_list/_index.md#dependency-paths) feature.
|
||||
|
||||
Alternatively, your project can provide a `pipdeptree.json` dependency graph export generated by the [`pipdeptree --json` command line utility](https://pypi.org/project/pipdeptree/).
|
||||
|
||||
|
|
@ -322,6 +324,11 @@ build:
|
|||
paths: ["**/pipdeptree.json"]
|
||||
```
|
||||
|
||||
Because of a [known issue](https://github.com/tox-dev/pipdeptree/issues/107), `pipdeptree` does not mark
|
||||
[optional dependencies](https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#optional-dependencies)
|
||||
as dependencies of the parent package. As a result, Dependency Scanning marks them as direct dependencies of the project,
|
||||
instead of as transitive dependencies.
|
||||
|
||||
##### Pipenv
|
||||
|
||||
If your project provides only a `Pipfile.lock` file, the Dependency Scanning analyzer can still extract the list of components. However, [dependency path](../../dependency_list/_index.md#dependency-paths) information is not available.
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ title: Static reachability analysis
|
|||
|
||||
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/14177) as an [experiment](../../../policy/development_stages_support.md) in GitLab 17.5.
|
||||
- [Changed](https://gitlab.com/groups/gitlab-org/-/epics/15781) from experiment to beta in GitLab 17.11.
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/502334) support for JavaScript and TypeScript in GitLab 18.2 and Dependency Scanning Analyzer v0.32.0.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
@ -32,20 +33,23 @@ project.
|
|||
|
||||
Prerequisites:
|
||||
|
||||
- Only Python projects are supported.
|
||||
- Only Python, JavaScript, and TypeScript projects are supported.
|
||||
- [Dependency Scanning analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/dependency-scanning)
|
||||
version 0.23.0 and later.
|
||||
version 0.32.0 and later.
|
||||
- Enable [Dependency Scanning by using SBOM](dependency_scanning_sbom/_index.md#getting-started).
|
||||
[Gemnasium](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium) analyzers are not
|
||||
supported.
|
||||
|
||||
Follow the [pip](dependency_scanning_sbom/_index.md#pip) or
|
||||
For Python, follow the [pip](dependency_scanning_sbom/_index.md#pip) or
|
||||
[pipenv](dependency_scanning_sbom/_index.md#pipenv)
|
||||
related instructions for dependency scanning using SBOM. You can also use any other Python package
|
||||
manager that is
|
||||
[supported](https://gitlab.com/gitlab-org/security-products/analyzers/dependency-scanning#supported-files)
|
||||
by the DS analyzer.
|
||||
|
||||
For JavaScript and TypeScript, ensure your repository has the [supported](https://gitlab.com/gitlab-org/security-products/analyzers/dependency-scanning#supported-files)
|
||||
lock files by the DS analyzer.
|
||||
|
||||
Exclusions:
|
||||
|
||||
- SRA cannot be used together with either a scan execution policy or pipeline execution policy.
|
||||
|
|
@ -104,12 +108,24 @@ When a direct dependency is marked as **in use**, all its transitive dependencie
|
|||
|
||||
## Supported languages and package managers
|
||||
|
||||
Static reachability analysis is available only for Python projects. SRA uses the new dependency
|
||||
scanning analyzer to generate SBOMs and so supports the same package managers as the analyzer.
|
||||
Static reachability analysis is available for Python, JavaScript, and TypeScript projects. SRA uses the new dependency
|
||||
scanning analyzer to generate SBOMs and supports the same package managers as the analyzer.
|
||||
|
||||
| Language | Supported Package Managers |
|
||||
|----------|----------------------------|
|
||||
| Python | `pip`, `pipenv`, `poetry`, `uv` |
|
||||
| Language | Supported package managers | Supported file suffix |
|
||||
|----------|----------------------------|-----------------------|
|
||||
| Python | `pip`, `pipenv`, `poetry`, `uv` | `.py` |
|
||||
| JavaScript/TypeScript | `npm`, `pnpm`, `yarn` | `.js`, `.ts` |
|
||||
|
||||
For Python `pipenv`, static reachability doesn't support `Pipfile.lock` files. Support is available only for `pipenv.graph.json` because it has support for a dependency graph.
|
||||
|
||||
If a package manager without dependency graph support is used, all indirect dependencies are marked as not in use.
|
||||
|
||||
Because of a [known issue](dependency_scanning_sbom/_index.md#pip) in Dependency Scanning with `pipdeptree`,
|
||||
[optional dependencies](https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#optional-dependencies)
|
||||
are marked as direct dependencies instead of as transitive dependencies. Static Reachability might not
|
||||
identify those packages as in use.
|
||||
|
||||
For example, requiring `passlib[bcrypt]` may result in `passlib` being marked as `in_use` whilst `bcrypt` is marked as `not_found`.
|
||||
|
||||
## Running SRA in an offline environment
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ To enforce policies to meet your requirements, consider the following factors:
|
|||
- **Inheritance**: By default, a policy is enforced on the organizational units it's linked to, and
|
||||
all their descendent subgroups and their projects.
|
||||
- **Scope**: To customize policy enforcement, you can define a policy's scope to match your needs.
|
||||
- **Centralized security policy management**: To apply security policies across multiple groups and projects from a single, centralized location, GitLab Self-Managed instance administrators can designate a compliance and security policy (CSP) group. For more information, see [centralized security policy management](centralized_security_policy_management.md).
|
||||
|
||||
#### Inheritance
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
---
|
||||
stage: Security Risk Management
|
||||
group: Security Policies
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Learn how to apply security policies across multiple groups and projects from a single, centralized location.
|
||||
title: Centralized security policy management
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab Self-Managed
|
||||
- Status: Beta
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/7622) in GitLab 18.2 [with a feature flag](../../../administration/feature_flags/_index.md) named `security_policies_csp`. Disabled by default.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
This feature is subject to change and may not ready for production use.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
Centralized security policy management allows instance administrators to designate a compliance and security policy (CSP) group and apply security policies across multiple groups and projects from a single, centralized location.
|
||||
|
||||
When you create or edit a security policy in the CSP group, you can scope it to:
|
||||
|
||||
- **Specific groups and subgroups**: Apply the policy only to selected groups and their subgroups.
|
||||
- **Specific projects**: Apply the policy to individual projects.
|
||||
- **All projects in the instance**: Apply the policy across your entire GitLab instance.
|
||||
- **All projects with exceptions**: Apply to all projects except those you specify.
|
||||
|
||||
When you designate a CSP group to serve as your centralized policy management hub, you can:
|
||||
|
||||
- Create and configure security policies that automatically apply across your instance.
|
||||
- Scope policies to specific groups, projects, or your entire instance.
|
||||
- View comprehensive policy coverage to understand which policies are active and where they're active.
|
||||
- Maintain centralized control while allowing teams to create their own additional policies.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- GitLab Self-Managed.
|
||||
- GitLab 18.2 or later.
|
||||
- You must be instance administrator.
|
||||
- You must have an existing top-level group to serve as the CSP group.
|
||||
- To use the REST API (optional), you must have a token with administrator access.
|
||||
|
||||
## Set up centralized security policy management
|
||||
|
||||
To set up centralized security policy management, you designate a CSP group and then create policies in the group.
|
||||
|
||||
For more information, see [instance-wide compliance and security policy management](../../../security/compliance_security_policy_management.md).
|
||||
|
||||
### Create security policies in the CSP group
|
||||
|
||||
To create the policies:
|
||||
|
||||
1. Go to your designated CSP group.
|
||||
1. Go to **Secure** > **Policies**.
|
||||
1. Create one or more security policies as you typically would. Before you save each policy:
|
||||
- In the **Policy scope** section, select a scope to apply the policy to:
|
||||
- **Groups**: Apply the policy to specific groups and subgroups.
|
||||
- **Projects**: Apply the policy individual projects.
|
||||
- **All projects**: Apply to the entire instance.
|
||||
- **All projects except**: Apply to all projects with specified exceptions.
|
||||
1. Save your policy configuration.
|
||||
|
||||
## Policy storage and configuration
|
||||
|
||||
CSP policies are stored in a `policy.yml` file in the designated CSP group, similar to how group policies are managed. CSP policies use the same configuration format as existing security policies.
|
||||
|
||||
## Policy synchronization
|
||||
|
||||
- Depending on the number of groups and projects in scope, policy changes may take some time to apply across your instance.
|
||||
- The synchronization process uses background jobs that are automatically queued when you designate a CSP group, create policies, or update policies.
|
||||
- Instance administrators can monitor background job processing in **Admin Area** > **Monitoring** > **Background jobs**.
|
||||
- To verify that policies are successfully applied in a target group or project, go to **Secure** > **Policies** in the group or project.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Policy does not appear in the target group or project**
|
||||
|
||||
- Verify that the policy scope includes the target group or project.
|
||||
- Verify that the CSP group is properly designated in the admin settings.
|
||||
- Verify that the policy is enabled in the CSP group.
|
||||
- Policy changes may take time to be applied. See [policy synchronization](#policy-synchronization) for more information.
|
||||
|
||||
**Performance concerns**
|
||||
|
||||
- Monitor policy propagation times, especially with large scope configurations.
|
||||
- Consider scoping policies to specific groups or projects instead of applying the policies to all projects.
|
||||
|
||||
## Feedback and support
|
||||
|
||||
As this is a Beta release, we actively seek feedback from users. Share your experience, suggestions, and any issues through:
|
||||
|
||||
- [GitLab Issues](https://gitlab.com/gitlab-org/gitlab/-/issues).
|
||||
- Your regular GitLab support channels.
|
||||
|
|
@ -539,6 +539,7 @@ Audit event types belong to the following product categories.
|
|||
| [`security_policy_delete`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/192797) | A security policy is deleted | {{< icon name="check-circle" >}} Yes | GitLab [18.1](https://gitlab.com/gitlab-org/gitlab/-/issues/539230) | Project |
|
||||
| [`security_policy_update`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/192797) | A security policy is updated | {{< icon name="check-circle" >}} Yes | GitLab [18.1](https://gitlab.com/gitlab-org/gitlab/-/issues/539230) | Project |
|
||||
| [`merge_request_branch_bypassed_by_security_policy`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/195942) | The merge request's approval is bypassed by the branches configured in the security policy | {{< icon name="check-circle" >}} Yes | GitLab [18.2](https://gitlab.com/gitlab-org/gitlab/-/issues/549646) | Project |
|
||||
| [`merge_request_merged_with_policy_violations`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/195775) | A merge request merged with security policy violations | {{< icon name="check-circle" >}} Yes | GitLab [18.2](https://gitlab.com/gitlab-org/gitlab/-/work_items/549813) | Project |
|
||||
| [`policy_violations_detected`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/193482) | Security policy violation is detected in the merge request | {{< icon name="dotted-circle" >}} No | GitLab [18.2](https://gitlab.com/gitlab-org/gitlab/-/work_items/549811) | Project |
|
||||
| [`policy_violations_resolved`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/193482) | Security policy violations are resolved in the merge request | {{< icon name="dotted-circle" >}} No | GitLab [18.2](https://gitlab.com/gitlab-org/gitlab/-/issues/549812) | Project |
|
||||
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ To link the SAML groups:
|
|||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/480766) for GitLab.com in GitLab 17.8 [with a flag](../../../administration/feature_flags/_index.md) named `saml_groups_duo_pro_add_on_assignment`. Disabled by default.
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/512141) for Self-Managed in GitLab 17.11.
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/512141) for Self-Managed in GitLab 18.0.
|
||||
{{< /history >}}
|
||||
|
||||
Prerequisites:
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ You can use Docker commands to build and push container images to your container
|
|||
|
||||
## Use GitLab CI/CD
|
||||
|
||||
You can use [GitLab CI/CD](../../../ci/_index.md) to build and push container images to the
|
||||
Container Registry. You can use CI/CD to test, build, and deploy your project from the container
|
||||
image you created.
|
||||
Use [GitLab CI/CD](../../../ci/_index.md) to build, push, test, and deploy container images from the container registry.
|
||||
|
||||
### Configure your `.gitlab-ci.yml` file
|
||||
|
||||
|
|
@ -72,6 +70,8 @@ Prerequisites:
|
|||
|
||||
{{< tab title="From the container registry" >}}
|
||||
|
||||
Use this approach when you want to use images stored in your GitLab container registry.
|
||||
|
||||
In your `.gitlab-ci.yml` file:
|
||||
|
||||
- Update `image` and `services` to point to your registry.
|
||||
|
|
@ -95,9 +95,11 @@ build:
|
|||
|
||||
{{< tab title="With the Dependency Proxy" >}}
|
||||
|
||||
Use this approach to cache images from external registries like Docker Hub for faster builds and to avoid rate limits.
|
||||
|
||||
In your `.gitlab-ci.yml` file:
|
||||
|
||||
- Update `image` and `services` to point to your dependency proxy.
|
||||
- Update `image` and `services` to use the Dependency Proxy prefix.
|
||||
- Add a service [alias](../../../ci/services/_index.md#available-settings-for-services).
|
||||
|
||||
Your `.gitlab-ci.yml` should look similar to this:
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ When they are imported, supported GitHub branch protection rules are mapped to e
|
|||
|:----------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|
|
||||
| **Require conversation resolution before merging** for the project's default branch | **All threads must be resolved** [project setting](../merge_requests/_index.md#prevent-merge-unless-all-threads-are-resolved) | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/371110) |
|
||||
| **Require a pull request before merging** | **No one** option in the **Allowed to push and merge** list of [branch protection settings](../repository/branches/protected.md#protect-a-branch) | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/370951) |
|
||||
| **Require signed commits** for the project's default branch | **Reject unsigned commits** GitLab [push rule](../repository/push_rules.md#prevent-unintended-consequences) | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/370949) |
|
||||
| **Require signed commits** for the project's default branch | **Reject unsigned commits** GitLab [push rule](../repository/push_rules.md#require-signed-commits) | [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/370949) |
|
||||
| **Allow force pushes - Everyone** | **Allowed to force push** [branch protection setting](../repository/branches/protected.md#allow-force-push) | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/370943) |
|
||||
| **Require a pull request before merging - Require review from Code Owners** | **Require approval from code owners** [branch protection setting](../repository/branches/protected.md#require-code-owner-approval) | [GitLab 15.6](https://gitlab.com/gitlab-org/gitlab/-/issues/376683) |
|
||||
| **Require a pull request before merging - Allow specified actors to bypass required pull requests** | List of users in the **Allowed to push and merge** list of [branch protection settings](../repository/branches/protected.md#protect-a-branch). Without a **Premium** subscription, the list of users that are allowed to push and merge is limited to roles. | [GitLab 15.8](https://gitlab.com/gitlab-org/gitlab/-/issues/384939) |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
---
|
||||
stage: Create
|
||||
group: Source Code
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: View information about a repository's commit history.
|
||||
title: Commits
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Free, Premium, Ultimate
|
||||
- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
The **Commits** list displays the commit history for your repository. Use it to browse
|
||||
code changes, view commit details, and verify commit signatures. You can filter the commit list by
|
||||
Git revision to see the changes for a specific revision.
|
||||
|
||||
The list shows:
|
||||
|
||||
- Commit hash: Unique identifier (SHA) for each commit.
|
||||
- Commit message: Title and description of the commit.
|
||||
- Author: Name and avatar of the user who made the commit.
|
||||
- Timestamp: When the commit was created.
|
||||
- Pipeline status: CI/CD pipeline results, if configured.
|
||||
- Signature verification: GPG, SSH, or X.509 signature status.
|
||||
- Tags: Any tags pointing to this commit.
|
||||
|
||||

|
||||
|
||||
## View commits
|
||||
|
||||
To view your repository's commit history:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
|
||||
To view a commit's summary, select the **Toggle commit description** icon ({{< icon name="ellipsis_h">}}).
|
||||
This summary does not display file changes or statistics.
|
||||
|
||||
## View commit details
|
||||
|
||||
Examine the specific changes made in any commit, including file modifications, additions, and deletions.
|
||||
|
||||
To view a commit's details:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. Select the commit to open the commit's details page.
|
||||
|
||||
The commit's details page shows:
|
||||
|
||||
- Commit information: Commit hash, author, committer, parent commits, and timestamp.
|
||||
- Commit message: Title and description of the commit.
|
||||
- File changes: All modified files with diff view.
|
||||
- Statistics: Number of lines changed, added, and removed.
|
||||
- Pipeline details: Associated CI/CD pipeline status and details.
|
||||
- References: Branches and tags containing this commit.
|
||||
- Related merge requests: Links to merge requests associated with the commit.
|
||||
|
||||
## Filter and search commits
|
||||
|
||||
Filter and search the commit history to find specific changes or track work by particular authors.
|
||||
|
||||
### Filter by author
|
||||
|
||||
To filter commits by a specific author:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. In the **Author** dropdown list, select or search for the author's name or username.
|
||||
|
||||
If author filtering doesn't work for names with special characters, use the URL parameter format.
|
||||
For example, append `?author=Elliot%20Stevens` to the URL.
|
||||
|
||||
### Filter by Git revision
|
||||
|
||||
To filter commits by Git revision, such as branch, tag, or commit SHA:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. In the dropdown list, select or search for a Git revision.
|
||||
For example, branch name, tag, or commit SHA.
|
||||
1. Select the Git revision to view the list of filtered commits.
|
||||
|
||||
### Search by commit message
|
||||
|
||||
To search for commits by message content:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. In the **Search by message** field, enter your search terms.
|
||||
|
||||
You can also search by commit SHA, full or partial, to find a specific commit directly.
|
||||
|
||||
## Cherry-pick a commit
|
||||
|
||||
Apply changes from a specific commit to another.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have at least the Developer role for the project.
|
||||
- The target branch must exist.
|
||||
|
||||
To cherry-pick a commit:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. Select the commit you want to cherry-pick.
|
||||
1. In the upper-right corner, select **Options** and then **Cherry-pick**.
|
||||
1. In the dialog:
|
||||
- From the dropdown lists, select the target project and branch.
|
||||
- Optional: Select **Start a new merge request** to create a merge request with the changes.
|
||||
- Select **Cherry-pick**.
|
||||
|
||||
GitLab creates a new commit on the target branch with the cherry-picked changes.
|
||||
If the branch is [protected](../branches/protected.md) or you don't have the correct permissions,
|
||||
GitLab prompts you to [create a new merge request](../../merge_requests/_index.md#create-a-merge-request).
|
||||
|
||||
## Revert a commit
|
||||
|
||||
Create a new commit that undoes changes from a previous commit.
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have at least the Developer role for the project.
|
||||
|
||||
To revert a commit:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. Select the commit you want to revert.
|
||||
1. In the upper-right corner, select **Options** and then **Revert**.
|
||||
1. In the dialog:
|
||||
- Select the target branch for the revert commit.
|
||||
- Optional: Select **Start a new merge request** to create a merge request.
|
||||
- Select **Revert**.
|
||||
|
||||
GitLab creates a new commit that reverses the changes from the selected commit.
|
||||
If the branch is [protected](../branches/protected.md) or you don't have the correct permissions,
|
||||
GitLab prompts you to [create a new merge request](../../merge_requests/_index.md#create-a-merge-request).
|
||||
|
||||
## Download commit contents
|
||||
|
||||
To download a commit's diff contents:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. Select the commit you want to download.
|
||||
1. In the upper-right corner, select **Options**.
|
||||
1. Under **Downloads**, select **Plain Diff**.
|
||||
|
||||
## Verify commit signatures
|
||||
|
||||
GitLab verifies GPG, SSH, and X.509 signatures to ensure commit authenticity.
|
||||
Verified commits show a **Verified** badge.
|
||||
|
||||
For more information, see [signed commits](../signed_commits/_index.md).
|
||||
|
||||
### View signature details
|
||||
|
||||
To view signature information:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. Find a commit with a **Verified** or **Unverified** badge.
|
||||
1. Select the badge to view signature details including:
|
||||
- Signature type (GPG, SSH, or X.509)
|
||||
- Key fingerprint
|
||||
- Verification status
|
||||
- Signer identity
|
||||
|
||||
## View pipeline status and details
|
||||
|
||||
The commit list includes a CI/CD pipeline status icon next to each commit. To view the pipeline details:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Code > Commits**.
|
||||
1. Select the pipeline status icon next to any commit.
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Signed commits](../signed_commits/_index.md)
|
||||
- [Git file history](../files/git_history.md)
|
||||
- [Tags](../tags/_index.md)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
|
|
@ -29,6 +29,7 @@ can and can't be pushed to your repository. While GitLab offers
|
|||
- Enforcing [branch name rules](branches/_index.md#name-your-branch).
|
||||
- Evaluating the details of files.
|
||||
- Preventing Git tag removal.
|
||||
- Requiring signed commits.
|
||||
|
||||
GitLab uses [RE2 syntax](https://github.com/google/re2/wiki/Syntax) for regular expressions
|
||||
in push rules. You can test them at the [regex101 regex tester](https://regex101.com/).
|
||||
|
|
@ -118,13 +119,6 @@ Use these rules for your commit messages.
|
|||
the expression. To allow any commit message, leave empty.
|
||||
Uses multiline mode, which can be disabled by using `(?-m)`.
|
||||
|
||||
## Reject commits that aren't DCO certified
|
||||
|
||||
Commits signed with the [Developer Certificate of Origin](https://developercertificate.org/) (DCO)
|
||||
certify the contributor wrote, or has the right to submit, the code contributed in that commit.
|
||||
You can require all commits to your project to comply with the DCO. This push rule requires a
|
||||
`Signed-off-by:` trailer in every commit message, and rejects any commits that lack it.
|
||||
|
||||
## Validate branch names
|
||||
|
||||
To validate your branch names, enter a regular expression for **Branch name**.
|
||||
|
|
@ -160,9 +154,8 @@ Use these rules to prevent unintended consequences.
|
|||
|
||||
- **Reject unsigned commits**: Commit [must be signed](signed_commits/_index.md). This rule
|
||||
can block some legitimate commits [created in the Web IDE](#reject-unsigned-commits-push-rule-disables-web-ide),
|
||||
and allow [unsigned commits created in the GitLab UI](#unsigned-commits-created-in-the-gitlab-ui).
|
||||
and allow [unsigned commits to appear in commit history](#unsigned-commits-appear-in-commit-history).
|
||||
- **Do not allow users to remove Git tags with `git push`**: Users cannot use `git push` to remove Git tags.
|
||||
Users can still delete tags in the UI.
|
||||
|
||||
## Validate files
|
||||
|
||||
|
|
@ -268,7 +261,7 @@ The regular expression can:
|
|||
- Exclude specific file types by extension.
|
||||
- Combine multiple expressions to exclude several patterns.
|
||||
|
||||
#### Regular expression examples
|
||||
### Regular expression examples
|
||||
|
||||
These examples use common regex string boundary patterns:
|
||||
|
||||
|
|
@ -277,7 +270,7 @@ These examples use common regex string boundary patterns:
|
|||
- `\.`: Matches a literal period character. The backslash escapes the period.
|
||||
- `\/`: Matches a literal forward slash. The backslash escapes the forward slash.
|
||||
|
||||
##### Prevent specific file types
|
||||
#### Prevent specific file types
|
||||
|
||||
- To prevent pushing `.exe` files to any location in the repository:
|
||||
|
||||
|
|
@ -285,7 +278,7 @@ These examples use common regex string boundary patterns:
|
|||
\.exe$
|
||||
```
|
||||
|
||||
##### Prevent specific files
|
||||
#### Prevent specific files
|
||||
|
||||
- To prevent pushing a specific configuration file:
|
||||
|
||||
|
|
@ -307,7 +300,7 @@ These examples use common regex string boundary patterns:
|
|||
(^|\/)install\.exe$
|
||||
```
|
||||
|
||||
##### Combine patterns
|
||||
#### Combine patterns
|
||||
|
||||
You can combine multiple patterns into one expression. This example combines all the previous expressions:
|
||||
|
||||
|
|
@ -315,12 +308,37 @@ You can combine multiple patterns into one expression. This example combines all
|
|||
(\.exe|^config\.yml|^directory-name\/config\.yml|(^|\/)install\.exe)$
|
||||
```
|
||||
|
||||
## Require signed commits
|
||||
|
||||
[Signed commits](signed_commits/_index.md) are digital signatures used to verify authenticity.
|
||||
Use the **Reject unsigned commits** push rule to require all commits to have cryptographic signatures.
|
||||
|
||||
When you enable this rule:
|
||||
|
||||
- All new commits pushed to the repository must contain a valid cryptographic signature.
|
||||
- The signature must be created using a supported signing method (GPG, SSH, or X.509).
|
||||
- Commits without any signature are rejected at push time.
|
||||
- Commits with invalid or corrupted signatures are rejected.
|
||||
|
||||
To enable the **Reject unsigned commits** push rule:
|
||||
|
||||
1. On the left sidebar, select **Search or go to** and find your project.
|
||||
1. Select **Settings > Repository**.
|
||||
1. Expand **Push rules**.
|
||||
1. Select **Reject unsigned commits**.
|
||||
1. Select **Save push rules**.
|
||||
|
||||
## Reject commits that aren't DCO certified
|
||||
|
||||
Commits signed with the [Developer Certificate of Origin](https://developercertificate.org/) (DCO)
|
||||
certify the contributor wrote, or has the right to submit, the code contributed in that commit.
|
||||
You can require all commits to your project to comply with the DCO. This push rule requires a
|
||||
`Signed-off-by:` trailer in every commit message, and rejects any commits that lack it.
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Git server hooks](../../../administration/server_hooks.md) (previously called server hooks), to create complex custom push rules
|
||||
- [Signing commits with GPG](signed_commits/gpg.md)
|
||||
- [Signing commits with SSH](signed_commits/ssh.md)
|
||||
- [Signing commits with X.509](signed_commits/x509.md)
|
||||
- [Signed commits](signed_commits/_index.md)
|
||||
- [Protected branches](branches/protected.md)
|
||||
- [Secret detection](../../application_security/secret_detection/_index.md)
|
||||
|
||||
|
|
@ -338,14 +356,14 @@ must disable the feature flag `reject_unsigned_commits_by_gitlab` [with a flag](
|
|||
Feature.disable(:reject_unsigned_commits_by_gitlab)
|
||||
```
|
||||
|
||||
### Unsigned commits created in the GitLab UI
|
||||
### Unsigned commits appear in commit history
|
||||
|
||||
The **Reject unsigned commits** push rule ignores commits that are authenticated
|
||||
and created by GitLab (either through the UI or API). When this push rule is
|
||||
enabled, unsigned commits may still appear in the commit history if a commit was
|
||||
created in GitLab itself. As expected, commits created outside GitLab and
|
||||
pushed to the repository are rejected. For more information about this issue,
|
||||
read [issue #19185](https://gitlab.com/gitlab-org/gitlab/-/issues/19185).
|
||||
The **Reject unsigned commits** push rule ignores commits that are authenticated and created by
|
||||
GitLab (either through the UI or API). When this push rule is enabled, unsigned commits might still
|
||||
appear in the commit history if a commit was created in GitLab itself.
|
||||
|
||||
As expected, commits created outside GitLab and pushed to the repository are rejected.
|
||||
For more information, see [issue #5361](https://gitlab.com/gitlab-org/gitaly/-/issues/5361).
|
||||
|
||||
### Bulk update push rules for all projects
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,15 @@ When you add a digital signature to your commit, you provide extra assurance tha
|
|||
originated from you, rather than an impersonator. A digital signature is a cryptographic output
|
||||
used to verify authenticity.
|
||||
|
||||
If GitLab can verify the committer's identity with a public [GPG key](gpg.md), the commit is
|
||||
marked **Verified** in the GitLab UI.
|
||||
You can then configure [push rules](../push_rules.md) for your project to:
|
||||
It's important to understand the difference between signed and verified commits:
|
||||
|
||||
- Reject individual unsigned commits.
|
||||
- Reject all commits from unverified users.
|
||||
- Signed commits have a cryptographic signature attached that proves the commit's
|
||||
integrity and authenticity. The signature is created using a private key.
|
||||
- Verified commits have signatures that GitLab can validate against a known public key
|
||||
stored in a user's GitLab profile.
|
||||
|
||||
If GitLab can verify the committer's identity with a public key, the commit is
|
||||
marked **Verified** in the GitLab UI.
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
||||
|
|
@ -31,11 +34,11 @@ applies it. Commit signing verifies only the committer's identity.
|
|||
|
||||
{{< /alert >}}
|
||||
|
||||
Sign commits with your:
|
||||
GitLab supports the following commit signing methods:
|
||||
|
||||
- [SSH key](ssh.md).
|
||||
- [GPG key](gpg.md).
|
||||
- [Personal x.509 certificate](x509.md).
|
||||
- [SSH key](ssh.md)
|
||||
- [GPG key](gpg.md)
|
||||
- [Personal X.509 certificate](x509.md)
|
||||
|
||||
## Verify commits
|
||||
|
||||
|
|
@ -64,13 +67,13 @@ To review commits for a merge request, or for an entire project, and verify they
|
|||
You can also [use the Commits API](../../../../api/commits.md#get-signature-of-a-commit)
|
||||
to check a commit's signature.
|
||||
|
||||
### Verify commits made in the web UI
|
||||
### Verify web UI commits
|
||||
|
||||
GitLab uses SSH to sign commits created through the web UI.
|
||||
To verify these commits locally, obtain the GitLab public key for signing web commits
|
||||
using the [Web Commits API](../../../../api/web_commits.md#get-public-signing-key).
|
||||
|
||||
### Use gitmailmap with verified commits
|
||||
### Use `gitmailmap` with verified commits
|
||||
|
||||
{{< history >}}
|
||||
|
||||
|
|
@ -92,6 +95,14 @@ When using a `mailmap` author mapping, it's possible to have a verified commit w
|
|||
For SSH and UI signatures with `mailmap` author mappings, GitLab displays an orange verified label with a warning sign.
|
||||
To restore the green verified label, verify the mapped email address, or remove the `mailmap` entry.
|
||||
|
||||
## Enforce signed commits with push rules
|
||||
|
||||
You can require signed commits across your projects using push rules.
|
||||
The **Reject unsigned commits** push rule prevents any unsigned commits from being pushed
|
||||
to a repository, helping organizations maintain code integrity and meet compliance requirements.
|
||||
|
||||
For more information about how this rule works and its limitations, see [Require signed commits](../push_rules.md#require-signed-commits).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Fix verification problems with signed commits
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module API
|
|||
end
|
||||
|
||||
feature_category :webhooks
|
||||
urgency :low
|
||||
|
||||
helpers ::API::Helpers::WebHooksHelpers
|
||||
|
||||
|
|
|
|||
|
|
@ -26533,6 +26533,9 @@ msgstr ""
|
|||
msgid "Failed to load groups, users and deploy keys."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load iterations. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Failed to load labels. Please try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -66290,12 +66293,6 @@ msgstr ""
|
|||
msgid "Update %{sourcePath} file"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update Now"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update Scheduled…"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update appearance settings"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -66317,6 +66314,9 @@ msgstr ""
|
|||
msgid "Update password for %{current_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update scheduled…"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update selected"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import Vue from 'vue';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import CrudComponent from '~/vue_shared/components/crud_component.vue';
|
||||
import StatisticsPanelApp from '~/admin/statistics_panel/components/app.vue';
|
||||
import statisticsLabels from '~/admin/statistics_panel/constants';
|
||||
import createStore from '~/admin/statistics_panel/store';
|
||||
|
|
@ -22,6 +23,9 @@ describe('Admin statistics app', () => {
|
|||
const createComponent = () => {
|
||||
wrapper = shallowMount(StatisticsPanelApp, {
|
||||
store,
|
||||
stubs: {
|
||||
CrudComponent,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -35,11 +39,11 @@ describe('Admin statistics app', () => {
|
|||
|
||||
describe('template', () => {
|
||||
describe('when app is loading', () => {
|
||||
it('renders a loading indicator', () => {
|
||||
it('renders a skeleton loader', () => {
|
||||
store.dispatch('requestStatistics');
|
||||
createComponent();
|
||||
|
||||
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
|
||||
expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ describe('error tracking settings project dropdown', () => {
|
|||
'projects',
|
||||
'projectSelectionLabel',
|
||||
'selectedProject',
|
||||
'token',
|
||||
),
|
||||
hasProjects: false,
|
||||
isProjectInvalid: false,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ describe('WorkItemBulkEditSidebar component', () => {
|
|||
]),
|
||||
provide: {
|
||||
hasIssuableHealthStatusFeature: false,
|
||||
hasIterationsFeature: false,
|
||||
...provide,
|
||||
},
|
||||
propsData: {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { mockTracking } from 'helpers/tracking_helper';
|
||||
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
|
||||
import { newWorkItemId } from '~/work_items/utils';
|
||||
import DropdownContentsCreateView from '~/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue';
|
||||
import groupLabelsQuery from '~/sidebar/components/labels/labels_select_widget/graphql/group_labels.query.graphql';
|
||||
import projectLabelsQuery from '~/sidebar/components/labels/labels_select_widget/graphql/project_labels.query.graphql';
|
||||
|
|
@ -26,7 +27,9 @@ import {
|
|||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
const workItemId = 'gid://gitlab/WorkItem/1';
|
||||
const mockFullPath = 'test-project-path';
|
||||
const mockWorkItemId = 'gid://gitlab/WorkItem/1';
|
||||
const mockWorkItemType = 'Task';
|
||||
|
||||
describe('WorkItemLabels component', () => {
|
||||
/** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
|
||||
|
|
@ -69,7 +72,10 @@ describe('WorkItemLabels component', () => {
|
|||
workItemQueryHandler = workItemQuerySuccess,
|
||||
searchQueryHandler = projectLabelsQueryHandler,
|
||||
updateWorkItemMutationHandler = successUpdateWorkItemMutationHandler,
|
||||
fullPath = mockFullPath,
|
||||
workItemId = mockWorkItemId,
|
||||
workItemIid = '1',
|
||||
workItemType = mockWorkItemType,
|
||||
} = {}) => {
|
||||
wrapper = shallowMountExtended(WorkItemLabels, {
|
||||
apolloProvider: createMockApollo([
|
||||
|
|
@ -80,17 +86,17 @@ describe('WorkItemLabels component', () => {
|
|||
]),
|
||||
provide: {
|
||||
canAdminLabel: true,
|
||||
issuesListPath: 'test-project-path/issues',
|
||||
issuesListPath: `${fullPath}/issues`,
|
||||
epicsListPath: 'groups/some-group/-/epics',
|
||||
labelsManagePath: 'test-project-path/labels',
|
||||
labelsManagePath: `${fullPath}/labels`,
|
||||
},
|
||||
propsData: {
|
||||
workItemId,
|
||||
workItemIid,
|
||||
canUpdate,
|
||||
isGroup,
|
||||
fullPath: 'test-project-path',
|
||||
workItemType: 'Task',
|
||||
fullPath,
|
||||
workItemType,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -117,7 +123,7 @@ describe('WorkItemLabels component', () => {
|
|||
const getMutationInput = (addLabelIds, removeLabelIds) => {
|
||||
return {
|
||||
input: {
|
||||
id: workItemId,
|
||||
id: mockWorkItemId,
|
||||
labelsWidget: {
|
||||
addLabelIds,
|
||||
removeLabelIds,
|
||||
|
|
@ -208,7 +214,7 @@ describe('WorkItemLabels component', () => {
|
|||
|
||||
expect(findWorkItemSidebarDropdownWidget().props('listItems')).toHaveLength(result);
|
||||
expect(handler).toHaveBeenCalledWith({
|
||||
fullPath: 'test-project-path',
|
||||
fullPath: mockFullPath,
|
||||
searchTerm,
|
||||
});
|
||||
expect(groupLabelsQueryHandler).not.toHaveBeenCalled();
|
||||
|
|
@ -291,6 +297,31 @@ describe('WorkItemLabels component', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('update labels when labels are removed during create mode', async () => {
|
||||
createComponent({
|
||||
workItemId: newWorkItemId(mockWorkItemType),
|
||||
workItemQueryHandler: workItemQueryWithLabelsHandler,
|
||||
updateWorkItemMutationHandler: successRemoveLabelWorkItemMutationHandler,
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
findRegularLabel().vm.$emit('close', label1Id);
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(wrapper.emitted('updateWidgetDraft')).toEqual([
|
||||
[
|
||||
{
|
||||
workItemType: mockWorkItemType,
|
||||
fullPath: mockFullPath,
|
||||
labels: [mockLabels[1], mockLabels[2]],
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(successRemoveLabelWorkItemMutationHandler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('update labels when labels are added or removed at same time', async () => {
|
||||
createComponent({
|
||||
workItemQueryHandler: workItemQueryWithFewLabelsHandler,
|
||||
|
|
@ -500,8 +531,8 @@ describe('WorkItemLabels component', () => {
|
|||
toggleText: 'No labels',
|
||||
});
|
||||
expect(findDropdownContentsCreateView().props()).toEqual({
|
||||
attrWorkspacePath: 'test-project-path',
|
||||
fullPath: 'test-project-path',
|
||||
attrWorkspacePath: mockFullPath,
|
||||
fullPath: mockFullPath,
|
||||
labelCreateType: 'project',
|
||||
searchKey: '',
|
||||
workspaceType: 'project',
|
||||
|
|
|
|||
|
|
@ -1094,7 +1094,7 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
|
|||
|
||||
subject { helper.fork_button_data_attributes(project) }
|
||||
|
||||
where(:has_user, :project_already_forked, :has_forkable_groups, :expected) do
|
||||
where(:has_user, :project_already_forked, :has_groups_allowing_project_creation, :expected) do
|
||||
false | false | false | nil
|
||||
true | false | false | data_attributes_without_user_fork_url
|
||||
true | false | true | data_attributes_without_user_fork_url
|
||||
|
|
@ -1111,7 +1111,7 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
|
|||
allow(user).to receive(:can?).with(:fork_project, project).and_return(true)
|
||||
allow(user).to receive(:can?).with(:create_projects, anything).and_return(true)
|
||||
allow(user).to receive(:already_forked?).with(project).and_return(project_already_forked)
|
||||
allow(user).to receive(:has_forkable_groups?).and_return(has_forkable_groups)
|
||||
allow(user).to receive(:has_groups_allowing_project_creation?).and_return(has_groups_allowing_project_creation)
|
||||
|
||||
allow(project).to receive(:forks_count).and_return(4)
|
||||
allow(project).to receive(:full_path).and_return(project_path)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,43 @@ RSpec.describe User, feature_category: :user_profile do
|
|||
include ExclusiveLeaseHelpers
|
||||
include LdapHelpers
|
||||
|
||||
shared_examples 'checks for groups with project creation permission' do
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
context 'when user does not belong in a group' do
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
|
||||
context 'when user belongs in group allowing project creation' do
|
||||
let_it_be(:group) do
|
||||
create(:group, developers: [user], project_creation_level: Gitlab::Access::DEVELOPER_PROJECT_ACCESS)
|
||||
end
|
||||
|
||||
it { is_expected.to be(true) }
|
||||
end
|
||||
|
||||
context 'when user belongs in group not allowing project creation' do
|
||||
let_it_be(:group) do
|
||||
create(:group, developers: [user], project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS)
|
||||
end
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
|
||||
context 'when group is shared with another group allowing project creation' do
|
||||
let_it_be(:shared_group_link) do
|
||||
create(
|
||||
:group_group_link,
|
||||
:developer,
|
||||
shared_with_group: group,
|
||||
shared_group: create(:group, project_creation_level: Gitlab::Access::DEVELOPER_PROJECT_ACCESS)
|
||||
)
|
||||
end
|
||||
|
||||
it { is_expected.to be(true) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'having unique enum values'
|
||||
|
||||
describe 'modules' do
|
||||
|
|
@ -2953,7 +2990,6 @@ RSpec.describe User, feature_category: :user_profile do
|
|||
let_it_be_with_refind(:user) { create(:user) }
|
||||
let_it_be_with_refind(:group) { create(:group, owners: user) }
|
||||
|
||||
it { expect(user.several_namespaces?).to be_truthy }
|
||||
it { expect(user.authorized_groups).to contain_exactly(group) }
|
||||
it { expect(user.owned_groups).to contain_exactly(group) }
|
||||
it { expect(user.namespaces).to contain_exactly(user.namespace, group) }
|
||||
|
|
@ -3022,19 +3058,10 @@ RSpec.describe User, feature_category: :user_profile do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'group multiple owners' do
|
||||
let_it_be(:user) { create :user }
|
||||
let_it_be(:user2) { create :user }
|
||||
let_it_be(:group) { create :group, owners: [user, user2] }
|
||||
|
||||
it { expect(user2.several_namespaces?).to be_truthy }
|
||||
end
|
||||
|
||||
describe 'namespaced' do
|
||||
let_it_be(:user) { create :user }
|
||||
let_it_be(:project) { create(:project, namespace: user.namespace) }
|
||||
|
||||
it { expect(user.several_namespaces?).to be_falsey }
|
||||
it { expect(user.namespaces).to contain_exactly(user.namespace) }
|
||||
end
|
||||
|
||||
|
|
@ -4160,6 +4187,24 @@ RSpec.describe User, feature_category: :user_profile do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#has_groups_allowing_project_creation?' do
|
||||
subject { user.has_groups_allowing_project_creation? }
|
||||
|
||||
it_behaves_like 'checks for groups with project creation permission'
|
||||
end
|
||||
|
||||
describe '#can_select_namespace?' do
|
||||
subject { user.can_select_namespace? }
|
||||
|
||||
context 'when user is admin' do
|
||||
let_it_be(:user) { create(:user, :admin) }
|
||||
|
||||
it { is_expected.to be(true) }
|
||||
end
|
||||
|
||||
it_behaves_like 'checks for groups with project creation permission'
|
||||
end
|
||||
|
||||
describe '#can_create_project?' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue