Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-04-10 15:18:47 +00:00
parent 6bbf79d852
commit d024f170c7
117 changed files with 1945 additions and 343 deletions

View File

@ -256,7 +256,6 @@ export default {
'app/assets/javascripts/tags/components/delete_tag_modal.vue',
'app/assets/javascripts/token_access/components/outbound_token_access.vue',
'app/assets/javascripts/token_access/components/token_permissions.vue',
'app/assets/javascripts/tooltips/components/tooltips.vue',
'app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue',
'app/assets/javascripts/user_lists/components/user_lists.vue',
'app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue',

View File

@ -1 +1 @@
d19af9f22edb454a615b9bb90fdcaa24f72eb488
a2177df705fe856c93c8576bb96cd15e225ea32f

View File

@ -1 +1 @@
96892bcaa0e6b6ff3727d5b312cab22e8dcb9d59
a817e7aaa39a4b29f1c99e38bf6b9f8a074d7098

View File

@ -270,7 +270,7 @@ gem 'asciidoctor-kroki', '~> 0.10.0', require: false, feature_category: :markdow
gem 'rouge', '~> 4.5.0', feature_category: :shared
gem 'truncato', '~> 0.7.13', feature_category: :team_planning
gem 'nokogiri', '~> 1.18', feature_category: :shared
gem 'gitlab-glfm-markdown', '~> 0.0.27', feature_category: :markdown
gem 'gitlab-glfm-markdown', '~> 0.0.29', feature_category: :markdown
gem 'tanuki_emoji', '~> 0.13', feature_category: :markdown
gem 'unicode-emoji', '~> 4.0', feature_category: :markdown
@ -729,7 +729,7 @@ gem 'cvss-suite', '~> 3.3.0', require: 'cvss_suite', feature_category: :software
gem 'arr-pm', '~> 0.0.12', feature_category: :package_registry
# Remote Development
gem 'devfile', '~> 0.3.0', feature_category: :workspaces
gem 'devfile', '~> 0.4.0', feature_category: :workspaces
# Apple plist parsing
gem 'CFPropertyList', '~> 3.0.0', feature_category: :mobile_devops

View File

@ -113,10 +113,10 @@
{"name":"deprecation_toolkit","version":"1.5.1","platform":"ruby","checksum":"a8a1ab1a19ae40ea12560b65010e099f3459ebde390b76621ef0c21c516a04ba"},
{"name":"derailed_benchmarks","version":"2.2.1","platform":"ruby","checksum":"654280664fded41c9cd8fc27fc0fcfaf096023afab90eb4ac1185ba70c5d4439"},
{"name":"descendants_tracker","version":"0.0.4","platform":"ruby","checksum":"e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897"},
{"name":"devfile","version":"0.3.0","platform":"aarch64-linux","checksum":"a0fe52455c0c4b092727fb002a9c1ceed823c8c862522eab65090ae9325ecdb1"},
{"name":"devfile","version":"0.3.0","platform":"arm64-darwin","checksum":"5c950972f6c064915f487678344e286bf1ca9225a104302a9092945e6942edf7"},
{"name":"devfile","version":"0.3.0","platform":"ruby","checksum":"7de291449c57429867f3df33b9cf2f929bd39ed3cfba553b0959afdfdea8fa5a"},
{"name":"devfile","version":"0.3.0","platform":"x86_64-linux","checksum":"3f90080602c660b36abf506559378ae904bca82023cce484c8a6f3f98b7155db"},
{"name":"devfile","version":"0.4.0","platform":"aarch64-linux","checksum":"ca9a030210755023608e8f853794c0006ebd1acff2b0f54a47202a9bf98a8bce"},
{"name":"devfile","version":"0.4.0","platform":"arm64-darwin","checksum":"99588818b3833373236af0cf0559932a4dac4ee6fa017fa7f8885e6acb83a7e3"},
{"name":"devfile","version":"0.4.0","platform":"ruby","checksum":"885b7728dae945582321364346f5bb59c4f92457f6cea2231c30ad1e5a168af9"},
{"name":"devfile","version":"0.4.0","platform":"x86_64-linux","checksum":"942fb20bce2a13a58ec58632ce1c7a1323cc7e95819e39b548529044b4ad89bc"},
{"name":"device_detector","version":"1.0.0","platform":"ruby","checksum":"b800fb3150b00c23e87b6768011808ac1771fffaae74c3238ebaf2b782947a7d"},
{"name":"devise","version":"4.9.4","platform":"ruby","checksum":"920042fe5e704c548aa4eb65ebdd65980b83ffae67feb32c697206bfd975a7f8"},
{"name":"devise-two-factor","version":"4.1.1","platform":"ruby","checksum":"c95f5b07533e62217aaed3c386874d94e2d472fb5f2b6598afe8600fc17a8b95"},
@ -224,13 +224,13 @@
{"name":"gitlab-dangerfiles","version":"4.8.1","platform":"ruby","checksum":"bbad321c9638152a643d27a20b35ba1e2d8eddcc6bdfc4493d7b96e816ecf300"},
{"name":"gitlab-experiment","version":"0.9.1","platform":"ruby","checksum":"f230ee742154805a755d5f2539dc44d93cdff08c5bbbb7656018d61f93d01f48"},
{"name":"gitlab-fog-azure-rm","version":"2.2.0","platform":"ruby","checksum":"31aa7c2170f57874053144e7f716ec9e15f32e71ffbd2c56753dce46e2e78ba9"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"aarch64-linux-gnu","checksum":"67a2e7d2cd1208d22abb9c162e88aa725f0fa31ea7fa8a6f56481370a5d1ef2d"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"aarch64-linux-musl","checksum":"c4b8ce9061238f0cebdaeeceb64bf2e6f1d72f4bfe72b11ac191f45dce12e302"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"arm64-darwin","checksum":"fe71765e04305f5a34647b3338e5101f92547f627a76ddedab35631f98907420"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"ruby","checksum":"960e481c037bbe319ec73792a3fc0fa024a9c11ab16786f24591417a255514a1"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"x86_64-darwin","checksum":"1434de2be23464ac379e30a125213ce00e6c907f47362b50a2d50488bc1e73d2"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"x86_64-linux-gnu","checksum":"59c5a0c577cb9301253bce6c9c0e2b9585110a34c46197cedc16e1142fb2feaf"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"x86_64-linux-musl","checksum":"298757eb48905451285d8c2ef4ecbb1691ed2b30f522998bc65474be340def8a"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"aarch64-linux-gnu","checksum":"b4c12b3f87c27f4397344b58b37bb7db6d635747bb88bc9ffe57664b743b6d7b"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"aarch64-linux-musl","checksum":"815e476e31f7f0d89fc410ec95dc2bf502936073a5fa5ec6849fd38dfb27f1c1"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"arm64-darwin","checksum":"7a0b2e4f35e61a1227199117dd3632c45ee8e5b3ef06b4f92011a30de762f5f0"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"ruby","checksum":"a19a8a996d403d98b7d9acfb57d3be5259681011c647c5a8a0a1292f5f6eb226"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-darwin","checksum":"1e322c51ec338a6958010a062005285f335318c2a4b2dee71c2848468498c08d"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-gnu","checksum":"e8086a21a4e3187d76fa89eecac88aa57a89627de2a3b789d70d4844efe881db"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-musl","checksum":"f934efe5efc53d36ea00a030cc0d530bad81901ef782b7774dd0bfaef73f1c37"},
{"name":"gitlab-kas-grpc","version":"17.9.1","platform":"ruby","checksum":"fd480c1669c741ceab8d5f86b7e5e32b71f4f25af8b523725382dae425aaa958"},
{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},

View File

@ -529,7 +529,7 @@ GEM
thor (>= 0.19, < 2)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devfile (0.3.0)
devfile (0.4.0)
device_detector (1.0.0)
devise (4.9.4)
bcrypt (~> 3.0)
@ -761,7 +761,7 @@ GEM
mime-types
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.28)
gitlab-glfm-markdown (0.0.29)
rb_sys (~> 0.9.109)
gitlab-kas-grpc (17.9.1)
grpc (~> 1.0)
@ -2057,7 +2057,7 @@ DEPENDENCIES
declarative_policy (~> 1.1.0)
deprecation_toolkit (~> 1.5.1)
derailed_benchmarks
devfile (~> 0.3.0)
devfile (~> 0.4.0)
device_detector
devise (~> 4.9.3)
devise-pbkdf2-encryptable (~> 0.0.0)!
@ -2108,7 +2108,7 @@ DEPENDENCIES
gitlab-duo-workflow-service-client (~> 0.1)!
gitlab-experiment (~> 0.9.1)
gitlab-fog-azure-rm (~> 2.2.0)
gitlab-glfm-markdown (~> 0.0.27)
gitlab-glfm-markdown (~> 0.0.29)
gitlab-housekeeper!
gitlab-http!
gitlab-kas-grpc (~> 17.9.0.pre.rc2)

View File

@ -113,10 +113,10 @@
{"name":"deprecation_toolkit","version":"1.5.1","platform":"ruby","checksum":"a8a1ab1a19ae40ea12560b65010e099f3459ebde390b76621ef0c21c516a04ba"},
{"name":"derailed_benchmarks","version":"2.2.1","platform":"ruby","checksum":"654280664fded41c9cd8fc27fc0fcfaf096023afab90eb4ac1185ba70c5d4439"},
{"name":"descendants_tracker","version":"0.0.4","platform":"ruby","checksum":"e9c41dd4cfbb85829a9301ea7e7c48c2a03b26f09319db230e6479ccdc780897"},
{"name":"devfile","version":"0.3.0","platform":"aarch64-linux","checksum":"a0fe52455c0c4b092727fb002a9c1ceed823c8c862522eab65090ae9325ecdb1"},
{"name":"devfile","version":"0.3.0","platform":"arm64-darwin","checksum":"5c950972f6c064915f487678344e286bf1ca9225a104302a9092945e6942edf7"},
{"name":"devfile","version":"0.3.0","platform":"ruby","checksum":"7de291449c57429867f3df33b9cf2f929bd39ed3cfba553b0959afdfdea8fa5a"},
{"name":"devfile","version":"0.3.0","platform":"x86_64-linux","checksum":"3f90080602c660b36abf506559378ae904bca82023cce484c8a6f3f98b7155db"},
{"name":"devfile","version":"0.4.0","platform":"aarch64-linux","checksum":"ca9a030210755023608e8f853794c0006ebd1acff2b0f54a47202a9bf98a8bce"},
{"name":"devfile","version":"0.4.0","platform":"arm64-darwin","checksum":"99588818b3833373236af0cf0559932a4dac4ee6fa017fa7f8885e6acb83a7e3"},
{"name":"devfile","version":"0.4.0","platform":"ruby","checksum":"885b7728dae945582321364346f5bb59c4f92457f6cea2231c30ad1e5a168af9"},
{"name":"devfile","version":"0.4.0","platform":"x86_64-linux","checksum":"942fb20bce2a13a58ec58632ce1c7a1323cc7e95819e39b548529044b4ad89bc"},
{"name":"device_detector","version":"1.0.0","platform":"ruby","checksum":"b800fb3150b00c23e87b6768011808ac1771fffaae74c3238ebaf2b782947a7d"},
{"name":"devise","version":"4.9.4","platform":"ruby","checksum":"920042fe5e704c548aa4eb65ebdd65980b83ffae67feb32c697206bfd975a7f8"},
{"name":"devise-two-factor","version":"4.1.1","platform":"ruby","checksum":"c95f5b07533e62217aaed3c386874d94e2d472fb5f2b6598afe8600fc17a8b95"},
@ -224,13 +224,13 @@
{"name":"gitlab-dangerfiles","version":"4.8.1","platform":"ruby","checksum":"bbad321c9638152a643d27a20b35ba1e2d8eddcc6bdfc4493d7b96e816ecf300"},
{"name":"gitlab-experiment","version":"0.9.1","platform":"ruby","checksum":"f230ee742154805a755d5f2539dc44d93cdff08c5bbbb7656018d61f93d01f48"},
{"name":"gitlab-fog-azure-rm","version":"2.2.0","platform":"ruby","checksum":"31aa7c2170f57874053144e7f716ec9e15f32e71ffbd2c56753dce46e2e78ba9"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"aarch64-linux-gnu","checksum":"67a2e7d2cd1208d22abb9c162e88aa725f0fa31ea7fa8a6f56481370a5d1ef2d"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"aarch64-linux-musl","checksum":"c4b8ce9061238f0cebdaeeceb64bf2e6f1d72f4bfe72b11ac191f45dce12e302"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"arm64-darwin","checksum":"fe71765e04305f5a34647b3338e5101f92547f627a76ddedab35631f98907420"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"ruby","checksum":"960e481c037bbe319ec73792a3fc0fa024a9c11ab16786f24591417a255514a1"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"x86_64-darwin","checksum":"1434de2be23464ac379e30a125213ce00e6c907f47362b50a2d50488bc1e73d2"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"x86_64-linux-gnu","checksum":"59c5a0c577cb9301253bce6c9c0e2b9585110a34c46197cedc16e1142fb2feaf"},
{"name":"gitlab-glfm-markdown","version":"0.0.28","platform":"x86_64-linux-musl","checksum":"298757eb48905451285d8c2ef4ecbb1691ed2b30f522998bc65474be340def8a"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"aarch64-linux-gnu","checksum":"b4c12b3f87c27f4397344b58b37bb7db6d635747bb88bc9ffe57664b743b6d7b"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"aarch64-linux-musl","checksum":"815e476e31f7f0d89fc410ec95dc2bf502936073a5fa5ec6849fd38dfb27f1c1"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"arm64-darwin","checksum":"7a0b2e4f35e61a1227199117dd3632c45ee8e5b3ef06b4f92011a30de762f5f0"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"ruby","checksum":"a19a8a996d403d98b7d9acfb57d3be5259681011c647c5a8a0a1292f5f6eb226"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-darwin","checksum":"1e322c51ec338a6958010a062005285f335318c2a4b2dee71c2848468498c08d"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-gnu","checksum":"e8086a21a4e3187d76fa89eecac88aa57a89627de2a3b789d70d4844efe881db"},
{"name":"gitlab-glfm-markdown","version":"0.0.29","platform":"x86_64-linux-musl","checksum":"f934efe5efc53d36ea00a030cc0d530bad81901ef782b7774dd0bfaef73f1c37"},
{"name":"gitlab-kas-grpc","version":"17.9.1","platform":"ruby","checksum":"fd480c1669c741ceab8d5f86b7e5e32b71f4f25af8b523725382dae425aaa958"},
{"name":"gitlab-labkit","version":"0.37.0","platform":"ruby","checksum":"d2dd0a60db2149a9a8eebf2975dc23f54ac3ceb01bdba732eb1b26b86dfffa70"},
{"name":"gitlab-license","version":"2.6.0","platform":"ruby","checksum":"2c1f8ae73835640ec77bf758c1d0c9730635043c01cf77902f7976e826d7d016"},

View File

@ -541,7 +541,7 @@ GEM
thor (>= 0.19, < 2)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devfile (0.3.0)
devfile (0.4.0)
device_detector (1.0.0)
devise (4.9.4)
bcrypt (~> 3.0)
@ -773,7 +773,7 @@ GEM
mime-types
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.28)
gitlab-glfm-markdown (0.0.29)
rb_sys (~> 0.9.109)
gitlab-kas-grpc (17.9.1)
grpc (~> 1.0)
@ -2091,7 +2091,7 @@ DEPENDENCIES
declarative_policy (~> 1.1.0)
deprecation_toolkit (~> 1.5.1)
derailed_benchmarks
devfile (~> 0.3.0)
devfile (~> 0.4.0)
device_detector
devise (~> 4.9.3)
devise-pbkdf2-encryptable (~> 0.0.0)!
@ -2142,7 +2142,7 @@ DEPENDENCIES
gitlab-duo-workflow-service-client (~> 0.1)!
gitlab-experiment (~> 0.9.1)
gitlab-fog-azure-rm (~> 2.2.0)
gitlab-glfm-markdown (~> 0.0.27)
gitlab-glfm-markdown (~> 0.0.29)
gitlab-housekeeper!
gitlab-http!
gitlab-kas-grpc (~> 17.9.0.pre.rc2)

View File

@ -0,0 +1,69 @@
<script>
import { GlBadge, GlTab } from '@gitlab/ui';
import { I18N_FETCH_ERROR } from '~/ci/runner/constants';
import { createAlert } from '~/alert';
import { fetchPolicies } from '~/lib/graphql';
import allRunnersQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners.query.graphql';
import RunnerName from '~/ci/runner/components/runner_name.vue';
export default {
components: {
GlBadge,
GlTab,
RunnerName,
},
data() {
return {
runners: {
items: [],
pageInfo: {},
},
};
},
apollo: {
runners: {
query: allRunnersQuery,
fetchPolicy: fetchPolicies.NETWORK_ONLY,
variables() {
return {
type: 'INSTANCE_TYPE',
};
},
update(data) {
const { runners } = data;
return {
items: runners?.nodes || [],
pageInfo: runners?.pageInfo || {},
};
},
error() {
createAlert({ message: I18N_FETCH_ERROR });
},
},
},
computed: {
runnersItems() {
return this.runners.items;
},
runnersItemCount() {
return this.runnersItems.length;
},
},
};
</script>
<template>
<gl-tab>
<template #title>
<div class="gl-flex gl-gap-2">
{{ __('Instance') }}
<gl-badge>{{ runnersItemCount }}</gl-badge>
</div>
</template>
<ul>
<li v-for="runner in runnersItems" :key="runner.key">
<runner-name :key="runner.key" :runner="runner" />
</li>
</ul>
</gl-tab>
</template>

View File

@ -0,0 +1,92 @@
<script>
import { GlBadge, GlTab } from '@gitlab/ui';
import { __ } from '~/locale';
import { I18N_FETCH_ERROR } from '~/ci/runner/constants';
import { createAlert } from '~/alert';
import { fetchPolicies } from '~/lib/graphql';
import groupRunnersQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners.query.graphql';
import RunnerName from '~/ci/runner/components/runner_name.vue';
export const QUERY_TYPES = {
project: 'PROJECT_TYPE',
group: 'GROUP_TYPE',
};
export default {
components: {
GlBadge,
GlTab,
RunnerName,
},
props: {
title: {
type: String,
required: false,
default: __('Project'),
},
type: {
type: String,
required: false,
default: 'project',
},
groupFullPath: {
type: String,
required: true,
},
},
data() {
return {
runners: {
items: [],
urlsById: {},
pageInfo: {},
},
};
},
apollo: {
runners: {
query: groupRunnersQuery,
fetchPolicy: fetchPolicies.NETWORK_ONLY,
variables() {
return {
type: QUERY_TYPES[this.type],
groupFullPath: this.groupFullPath,
};
},
update(data) {
const { edges = [], pageInfo = {} } = data?.group?.runners || {};
const items = edges.map(({ node }) => node);
return { items, pageInfo };
},
error() {
createAlert({ message: I18N_FETCH_ERROR });
},
},
},
computed: {
runnersItems() {
return this.runners.items;
},
runnersItemsCount() {
return this.runnersItems.length;
},
},
};
</script>
<template>
<gl-tab>
<template #title>
<div class="gl-flex gl-gap-2">
{{ title }}
<gl-badge>{{ runnersItemsCount }}</gl-badge>
</div>
</template>
<ul>
<li v-for="runner in runnersItems" :key="runner.key">
<runner-name :key="runner.key" :runner="runner" />
</li>
</ul>
</gl-tab>
</template>

View File

@ -1,6 +1,11 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import ProjectRunnersSettingsApp from './project_runners_settings_app.vue';
Vue.use(VueApollo);
export const initProjectRunnersSettings = (selector = '#js-project-runners-settings') => {
const el = document.querySelector(selector);
@ -8,10 +13,31 @@ export const initProjectRunnersSettings = (selector = '#js-project-runners-setti
return null;
}
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
const {
canCreateRunner,
allowRegistrationToken,
registrationToken,
newProjectRunnerPath,
groupFullPath,
} = el.dataset;
return new Vue({
el,
apolloProvider,
render(h) {
return h(ProjectRunnersSettingsApp, {});
return h(ProjectRunnersSettingsApp, {
props: {
canCreateRunner: parseBoolean(canCreateRunner),
allowRegistrationToken: parseBoolean(allowRegistrationToken),
registrationToken,
newProjectRunnerPath,
groupFullPath,
},
});
},
});
};

View File

@ -1,11 +1,64 @@
<script>
import { GlButton, GlTabs } from '@gitlab/ui';
import CrudComponent from '~/vue_shared/components/crud_component.vue';
import RegistrationDropdown from '~/ci/runner/components/registration/registration_dropdown.vue';
import RunnersTab from '~/ci/runner/project_runners_settings/components/runners_tab.vue';
import InstanceRunnersTab from '~/ci/runner/project_runners_settings/components/instance_runners_tab.vue';
export default {
name: 'ProjectRunnersSettingsApp',
components: {
GlButton,
GlTabs,
CrudComponent,
RegistrationDropdown,
RunnersTab,
InstanceRunnersTab,
},
props: {
canCreateRunner: {
type: Boolean,
required: true,
},
allowRegistrationToken: {
type: Boolean,
required: true,
},
registrationToken: {
type: String,
required: false,
default: null,
},
newProjectRunnerPath: {
type: String,
required: false,
default: null,
},
groupFullPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div>
<!-- eslint-disable-next-line @gitlab/vue-require-i18n-strings -->
<pre>:vue_project_runners_settings</pre>
</div>
<crud-component :title="s__('Runners|Runners')" body-class="!gl-m-0">
<template #actions>
<gl-button v-if="canCreateRunner" size="small" :href="newProjectRunnerPath">{{
s__('Runners|New project runner')
}}</gl-button>
<registration-dropdown
size="small"
type="PROJECT_TYPE"
:allow-registration-token="allowRegistrationToken"
:registration-token="registrationToken"
/>
</template>
<gl-tabs>
<runners-tab :title="__('Project')" type="project" :group-full-path="groupFullPath" />
<runners-tab :title="__('Group')" type="group" :group-full-path="groupFullPath" />
<instance-runners-tab />
</gl-tabs>
</crud-component>
</template>

View File

@ -1,14 +1,23 @@
import { addShortcutsExtension } from '~/behaviors/shortcuts';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initBoards from '~/boards';
import { ISSUE_WIT_FEEDBACK_BADGE } from '~/work_items/constants';
addShortcutsExtension(ShortcutsNavigation);
initBoards();
if (gon.features.workItemsViewPreference) {
let feedback = {};
if (gon.features.workItemViewForIssues) {
feedback = {
...ISSUE_WIT_FEEDBACK_BADGE,
};
}
if (gon.features.workItemsViewPreference || gon.features.workItemViewForIssues) {
import(/* webpackChunkName: 'work_items_feedback' */ '~/work_items_feedback')
.then(({ initWorkItemsFeedback }) => {
initWorkItemsFeedback();
initWorkItemsFeedback(feedback);
})
.catch({});
}

View File

@ -1,11 +1,20 @@
import { mountIssuesListApp } from '~/issues/list';
import { ISSUE_WIT_FEEDBACK_BADGE } from '~/work_items/constants';
mountIssuesListApp();
if (gon.features.workItemsViewPreference) {
let feedback = {};
if (gon.features.workItemViewForIssues) {
feedback = {
...ISSUE_WIT_FEEDBACK_BADGE,
};
}
if (gon.features.workItemsViewPreference || gon.features.workItemViewForIssues) {
import(/* webpackChunkName: 'work_items_feedback' */ '~/work_items_feedback')
.then(({ initWorkItemsFeedback }) => {
initWorkItemsFeedback();
initWorkItemsFeedback(feedback);
})
.catch({});
}

View File

@ -291,6 +291,7 @@ export default {
:option="selectedProjectOption"
:namespace="namespace"
data-testid="new-project-step2"
@onSelectNamespace="onSelectNamespace"
@back="onBack"
@next="onNext"
/>

View File

@ -1,11 +1,13 @@
<script>
import { GlButton } from '@gitlab/ui';
import MultiStepFormTemplate from '~/vue_shared/components/multi_step_form_template.vue';
import SharedProjectCreationFields from './shared_project_creation_fields.vue';
export default {
components: {
GlButton,
MultiStepFormTemplate,
SharedProjectCreationFields,
},
props: {
option: {
@ -13,12 +15,30 @@ export default {
required: false,
default: () => ({}),
},
namespace: {
type: Object,
required: true,
},
},
methods: {
onSelectNamespace(newNamespace) {
this.$emit('onSelectNamespace', newNamespace);
},
},
};
</script>
<template>
<multi-step-form-template :title="option.title" :current-step="2" :steps-total="2">
<template #form>
<shared-project-creation-fields
:namespace="namespace"
@onSelectNamespace="onSelectNamespace"
/>
<!-- Project Configuration and Experimental features will be added here in: https://gitlab.com/gitlab-org/gitlab/-/issues/514700 -->
<!-- Two checkboxes from JiHu should be added here in: https://gitlab.com/gitlab-org/gitlab/-/issues/514700 -->
</template>
<template #next>
<gl-button
category="primary"

View File

@ -0,0 +1,116 @@
<script>
import { GlFormGroup, GlFormInput } from '@gitlab/ui';
import { kebabCase } from 'lodash';
import validation, { initForm } from '~/vue_shared/directives/validation';
import NewProjectDestinationSelect from './project_destination_select.vue';
export default {
components: {
GlFormGroup,
GlFormInput,
NewProjectDestinationSelect,
},
directives: {
validation: validation(),
},
props: {
namespace: {
type: Object,
required: true,
},
},
data() {
const form = initForm({
fields: {
'project[name]': { value: null },
'project[path]': { value: null },
},
});
return {
form,
selectedNamespace: this.namespace,
};
},
methods: {
updateSlug() {
this.form.fields['project[path]'].value = kebabCase(this.form.fields['project[name]'].value);
},
onSelectNamespace(newNamespace) {
this.$emit('onSelectNamespace', newNamespace);
},
},
};
</script>
<template>
<div>
<gl-form-group
:label="s__('ProjectsNew|Project name')"
label-for="project[name]"
:description="
s__(
'ProjectsNew|Must start with a lowercase or uppercase letter, digit, emoji, or underscore. Can also contain dots, pluses, dashes, or spaces.',
)
"
:invalid-feedback="form.fields['project[name]'].feedback"
data-testid="project-name-group"
>
<gl-form-input
id="project[name]"
v-model="form.fields['project[name]'].value"
v-validation:[form.showValidation]
:validation-message="s__('ProjectsNew|Please enter project name.')"
:state="form.fields['project[name]'].state"
name="project[name]"
required
:placeholder="s__('ProjectsNew|My awesome project')"
data-testid="project-name-input"
@input="updateSlug"
/>
</gl-form-group>
<div class="gl-flex gl-flex-col gl-gap-4 sm:gl-flex-row">
<gl-form-group
:label="s__('ProjectsNew|Choose a group or namespace')"
class="sm:gl-w-1/2"
label-for="namespace"
:invalid-feedback="
s__('ProjectsNew|Pick a group or namespace where you want to create this project.')
"
:state="selectedNamespace.id !== null"
data-testid="project-namespace-group"
>
<new-project-destination-select
toggle-aria-labelled-by="namespace"
:namespace-id="selectedNamespace.id"
:namespace-full-path="selectedNamespace.fullPath"
@onSelectNamespace="onSelectNamespace"
/>
</gl-form-group>
<div class="gl-mt-2 gl-hidden gl-pt-6 sm:gl-block">/</div>
<gl-form-group
:label="s__('ProjectsNew|Project slug')"
label-for="project[path]"
class="sm:gl-w-1/2"
:invalid-feedback="form.fields['project[path]'].feedback"
data-testid="project-slug-group"
>
<gl-form-input
id="project[path]"
v-model="form.fields['project[path]'].value"
v-validation:[form.showValidation]
:validation-message="s__('ProjectsNew|Please enter project slug.')"
:state="form.fields['project[path]'].state"
name="project[path]"
required
:placeholder="s__('ProjectsNew|my-awesome-project')"
data-testid="project-slug-input"
/>
</gl-form-group>
</div>
<!-- Deployment Target and Visibility Level should be added in: https://gitlab.com/gitlab-org/gitlab/-/issues/514700 -->
</div>
</template>

View File

@ -55,6 +55,7 @@ export default {
this.observer.disconnect();
},
methods: {
// eslint-disable-next-line vue/no-unused-properties -- addTooltips is part of the component's public API for adding tooltips dynamically.
addTooltips(elements, config) {
const newTooltips = elements
.filter((element) => !this.tooltipExists(element))
@ -81,6 +82,7 @@ export default {
}
}
},
// eslint-disable-next-line vue/no-unused-properties -- fixTitle is part of the component's public API for updating tooltip titles.
fixTitle(target) {
const tooltip = this.findTooltipByTarget(target);
@ -88,6 +90,7 @@ export default {
tooltip.title = target.getAttribute('title');
}
},
// eslint-disable-next-line vue/no-unused-properties -- triggerEvent is part of the component's public API for triggering tooltip events.
triggerEvent(target, event) {
const tooltip = this.findTooltipByTarget(target);
const tooltipRef = this.$refs[tooltip?.id];

View File

@ -185,6 +185,11 @@ export default {
required: false,
default: false,
},
namespaceFullName: {
type: String,
required: false,
default: '',
},
},
data() {
return {
@ -863,6 +868,7 @@ export default {
v-model="selectedProjectFullPath"
:full-path="fullPath"
:is-group="isGroup"
:current-project-name="namespaceFullName"
/>
</gl-form-group>

View File

@ -89,6 +89,11 @@ export default {
validator: (i) => i.id && i.type && i.reference && i.webUrl,
default: null,
},
namespaceFullName: {
type: String,
required: false,
default: '',
},
},
data() {
return {
@ -320,6 +325,7 @@ export default {
:work-item-type-name="selectedWorkItemTypeName"
:related-item="relatedItem"
:should-discard-draft="shouldDiscardDraft"
:namespace-full-name="namespaceFullName"
:is-modal="true"
@changeType="selectedWorkItemTypeName = $event"
@confirmCancel="handleConfirmCancellation"

View File

@ -267,7 +267,7 @@ export default {
this.$emit('replied');
clearDraft(this.autosaveKey);
this.cancelEditing();
this.doFullPageReloadIfIncident(commentText);
this.doFullPageReloadIfUnsupportedTypeChange(commentText);
} catch (error) {
this.$emit('error', error.message);
Sentry.captureException(error);
@ -275,16 +275,16 @@ export default {
this.isSubmitting = false;
}
},
// Until incidents are fully migrated to work items
// Until incidents and Service Desk issues are fully migrated to work items
// we need to browse to the detail page again
// so the legacy detail view is rendered.
// https://gitlab.com/gitlab-org/gitlab/-/issues/502823
doFullPageReloadIfIncident(commentText) {
// Matches quick actions /promote_to incident /promote_to_incident and /type incident case insensitive
const incidentTypeChangeRegex =
/\/(promote_to(?:_incident|\s{1,3}incident)|type\s{1,3}incident)(?!\S)/im;
doFullPageReloadIfUnsupportedTypeChange(commentText) {
// Matches quick actions /promote_to incident /promote_to_incident /type incident and /convert_to_ticket case insensitive
const unsupportedTypeChangeRegex =
/\/(promote_to(?:_incident|\s{1,3}incident)|type\s{1,3}incident|convert_to_ticket)(?!\S)/im;
if (incidentTypeChangeRegex.test(commentText)) {
if (unsupportedTypeChangeRegex.test(commentText)) {
visitUrl(this.workItem.webUrl);
}
},

View File

@ -793,6 +793,7 @@ export default {
:related-item="relatedItemData"
:preselected-work-item-type="workItemTypeNameEnum"
:show-project-selector="!isEpic"
:namespace-full-name="namespaceFullName"
:is-group="isGroup"
hide-button
@workItemCreated="$emit('workItemCreated')"

View File

@ -4,6 +4,8 @@ module Types
class GroupType < NamespaceType
graphql_name 'Group'
include ::NamespacesHelper
implements ::Types::Namespaces::GroupInterface
authorize :read_group
@ -356,6 +358,22 @@ module Types
description: 'Cluster agents associated with projects in the group and its subgroups.',
resolver: ::Resolvers::Clusters::AgentsResolver
field :marked_for_deletion_on, ::Types::TimeType,
null: true,
description: 'Date when group was scheduled to be deleted.',
experiment: { milestone: '16.11' }
field :is_adjourned_deletion_enabled, GraphQL::Types::Boolean,
null: false,
description: 'Indicates if delayed group deletion is enabled.',
method: :adjourned_deletion?,
experiment: { milestone: '16.11' }
field :permanent_deletion_date, GraphQL::Types::String,
null: true,
description: 'Date when group will be deleted if delayed group deletion is enabled.',
experiment: { milestone: '16.11' }
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|
LabelsFinder
@ -451,6 +469,18 @@ module Types
)
end
def marked_for_deletion_on
return unless group.adjourned_deletion?
group.marked_for_deletion_on
end
def permanent_deletion_date
return unless group.adjourned_deletion_configured?
permanent_deletion_date_formatted(Date.current)
end
private
def group

View File

@ -4,6 +4,8 @@ module Types
class ProjectType < BaseObject
graphql_name 'Project'
include ::NamespacesHelper
connection_type_class Types::CountableConnectionType
authorize :read_project
@ -134,6 +136,22 @@ module Types
null: true,
description: 'Indicates the archived status of the project.'
field :marked_for_deletion_on, ::Types::TimeType,
null: true,
description: 'Date when project was scheduled to be deleted.',
experiment: { milestone: '16.10' }
field :is_adjourned_deletion_enabled, GraphQL::Types::Boolean,
null: false,
description: 'Indicates if delayed project deletion is enabled.',
method: :adjourned_deletion?,
experiment: { milestone: '16.11' }
field :permanent_deletion_date, GraphQL::Types::String,
null: true,
description: 'Date when project will be deleted if delayed project deletion is enabled.',
experiment: { milestone: '16.11' }
field :visibility, GraphQL::Types::String,
null: true,
description: 'Visibility of the project.'
@ -1017,6 +1035,20 @@ module Types
)
end
def marked_for_deletion_on
## marked_for_deletion_at is deprecated in our v5 REST API in favor of marked_for_deletion_on
## https://docs.gitlab.com/ee/api/projects.html#removals-in-api-v5
return unless project.adjourned_deletion?
project.marked_for_deletion_at
end
def permanent_deletion_date
return unless project.adjourned_deletion_configured?
permanent_deletion_date_formatted(Date.current)
end
private
def project

View File

@ -126,6 +126,16 @@ module Ci
}
end
def project_runners_settings_data(project)
{
can_create_runner: can?(current_user, :create_runner, project).to_s,
allow_registration_token: project.namespace.allow_runner_registration_token?.to_s,
registration_token: can?(current_user, :read_runners_registration_token, project) ? project.runners_token : nil,
group_full_path: project.group&.full_path,
new_project_runner_path: new_project_runner_path(project)
}
end
def toggle_shared_runners_settings_data(project)
data = {
is_enabled: project.shared_runners_enabled?.to_s,

View File

@ -6,12 +6,22 @@ class List < ApplicationRecord
belongs_to :board
belongs_to :label
belongs_to :group
belongs_to :project
has_many :list_user_preferences
enum list_type: { backlog: 0, label: 1, closed: 2, assignee: 3, milestone: 4, iteration: 5 }
validates :board, :list_type, presence: true, unless: :importing?
validates :label_id, uniqueness: { scope: :board_id }, if: :label?
validates :group, presence: true, unless: :project
validates :project, presence: true, unless: :group
validates :group, absence: {
message: ->(_object, _data) { _("can't be specified if a project was already provided") }
}, if: :project
before_validation :ensure_group_or_project
scope :preload_associated_models, -> { preload(:board, label: :priorities) }
@ -47,6 +57,13 @@ class List < ApplicationRecord
end
end
end
private
def ensure_group_or_project
self.group_id = board&.group_id
self.project_id = board&.project_id
end
end
List.prepend_mod_with('List')
List.prepend_mod

View File

@ -1,5 +1,5 @@
- if Feature.enabled?(:vue_project_runners_settings, @project)
#js-project-runners-settings
#js-project-runners-settings{ data: project_runners_settings_data(@project) }
- else
.gl-flex.gl-flex-col.gl-gap-5.gl-mt-5
= render 'projects/runners/project_runners'

View File

@ -6,4 +6,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/534439
milestone: '17.11'
group: group::authentication
type: beta
default_enabled: false
default_enabled: true

View File

@ -4,4 +4,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/515960
milestone: '17.10'
type: development
group: group::analytics instrumentation
default_enabled: false
default_enabled: true

View File

@ -0,0 +1,8 @@
---
migration_job_name: BackfillListsShardingKey
description: Backfills group_id or project_id for records in the lists table using the boards table.
feature_category: team_planning
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186991
milestone: '17.11'
queued_migration_version: 20250404130722
finalized_by: # version of the migration that finalized this BBM

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
class RemoveSeatAssignmentsNamespaceIdNotNull < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.11'
def up
change_column_null :subscription_seat_assignments, :namespace_id, true
end
def down
change_column_null :subscription_seat_assignments, :namespace_id, false
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class CleanupRecordsWithNullNamespaceIdFromSeatAssignments < Gitlab::Database::Migration[2.2]
restrict_gitlab_migration gitlab_schema: :gitlab_main
disable_ddl_transaction!
milestone '17.11'
BATCH_SIZE = 1000
class SeatAssignment < MigrationRecord
include EachBatch
self.table_name = 'subscription_seat_assignments'
end
def up
# no-op - this migration is required to allow a rollback of `RemoveSeatAssignmentsNamespaceIdNotNull`
end
def down
SeatAssignment.each_batch(of: BATCH_SIZE) do |relation|
relation
.where(namespace_id: nil)
.delete_all
end
end
end

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
class AddShardingKeyToListsTable < Gitlab::Database::Migration[2.2]
milestone '17.11'
def change
add_column :lists, :group_id, :bigint
add_column :lists, :project_id, :bigint
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class AddDuoNanoEnabledToAiSettings < Gitlab::Database::Migration[2.2]
milestone '17.11'
def change
add_column :ai_settings, :duo_nano_features_enabled, :boolean, null: true
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
class DisableAiEventsBackfillToChForCom < Gitlab::Database::Migration[2.2]
restrict_gitlab_migration gitlab_schema: :gitlab_main
milestone '17.11'
def up
::Feature.disable(:ai_events_backfill_to_ch) if Gitlab.org_or_com?
end
def down
# no-op
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class ReplaceSubscriptionSeatAssignmentsNamespaceIdIdx < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.11'
OLD_IDX_NAME = 'uniq_idx_subscription_seat_assignments_on_namespace_and_user'
NEW_IDX_NAME = 'uniq_idx_subscription_seat_assignments_on_namespace_id_and_user'
def up
remove_concurrent_index :subscription_seat_assignments, [:namespace_id, :user_id], name: OLD_IDX_NAME
add_concurrent_index :subscription_seat_assignments, [:namespace_id, :user_id],
name: NEW_IDX_NAME, unique: true, where: "namespace_id IS NOT NULL"
end
def down
remove_concurrent_index :subscription_seat_assignments, [:namespace_id, :user_id], name: NEW_IDX_NAME
add_concurrent_index :subscription_seat_assignments, [:namespace_id, :user_id], name: OLD_IDX_NAME, unique: true
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
class AddListsShardingKeyNotNullConstraint < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.11'
def up
add_multi_column_not_null_constraint(:lists, :group_id, :project_id, validate: false)
end
def down
remove_multi_column_not_null_constraint(:lists, :group_id, :project_id)
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddListsProjectIdIndex < Gitlab::Database::Migration[2.2]
INDEX_NAME = 'index_lists_on_project_id'
disable_ddl_transaction!
milestone '17.11'
def up
add_concurrent_index :lists, :project_id, name: INDEX_NAME
end
def down
remove_concurrent_index :lists, :project_id, name: INDEX_NAME
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddListsGroupIdIndex < Gitlab::Database::Migration[2.2]
INDEX_NAME = 'index_lists_on_group_id'
disable_ddl_transaction!
milestone '17.11'
def up
add_concurrent_index :lists, :group_id, name: INDEX_NAME
end
def down
remove_concurrent_index :lists, :group_id, name: INDEX_NAME
end
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
class AddListsEnsureShardingKeyTrigger < Gitlab::Database::Migration[2.2]
include Gitlab::Database::SchemaHelpers
milestone '17.11'
LISTS_TABLE = 'lists'
TRIGGER_FUNCTION_NAME = 'ensure_lists_sharding_key'
TRIGGER_NAME = 'trigger_ensure_lists_sharding_key'
def up
create_trigger_function(TRIGGER_FUNCTION_NAME, replace: true) do
<<~SQL
IF NEW."project_id" IS NULL AND NEW."group_id" IS NULL THEN
SELECT "boards"."project_id", "boards"."group_id"
INTO NEW."project_id", NEW."group_id"
FROM "boards"
WHERE "boards"."id" = NEW."board_id";
END IF;
RETURN NEW;
SQL
end
create_trigger(
LISTS_TABLE, TRIGGER_NAME, TRIGGER_FUNCTION_NAME, fires: 'BEFORE INSERT OR UPDATE'
)
end
def down
drop_trigger(LISTS_TABLE, TRIGGER_NAME)
drop_function(TRIGGER_FUNCTION_NAME)
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddListsProjectIdInvalidFk < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.11'
def up
add_concurrent_foreign_key :lists,
:projects,
column: :project_id,
target_column: :id,
reverse_lock_order: true,
validate: false
end
def down
with_lock_retries do
remove_foreign_key_if_exists :lists, column: :project_id
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
class AddListsGroupIdInvalidFk < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.11'
def up
add_concurrent_foreign_key :lists,
:namespaces,
column: :group_id,
target_column: :id,
reverse_lock_order: true,
validate: false
end
def down
with_lock_retries do
remove_foreign_key_if_exists :lists, column: :group_id
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class QueueBackfillListsShardingKey < Gitlab::Database::Migration[2.2]
milestone '17.11'
restrict_gitlab_migration gitlab_schema: :gitlab_main
MIGRATION = "BackfillListsShardingKey"
BATCH_SIZE = 10000
SUB_BATCH_SIZE = 100
def up
queue_batched_background_migration(
MIGRATION,
:lists,
:id,
batch_size: BATCH_SIZE,
sub_batch_size: SUB_BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, :lists, :id, [])
end
end

View File

@ -0,0 +1 @@
a7ed53fbcc4f62e91897564af3d70dd51ebc9c16bd56ce8faf8dfc0ca5a562e9

View File

@ -0,0 +1 @@
f63803345b7ab36f8257fc2fda3953821cec06c5aead52676a0ba47e429e0c87

View File

@ -0,0 +1 @@
2e3b372b99288c7bcac5c1aac8bd0a50b848e4b198d69b6739b8666619a6b61b

View File

@ -0,0 +1 @@
650dcba158095849fb8e5e4532a41b3731eaf9f04daccf6e7f28cb0a0bef3a23

View File

@ -0,0 +1 @@
11b1c67e7353d6b65a23d6949622b2e10ccd5e7c95f072e25bc8f943bbc24ff5

View File

@ -0,0 +1 @@
9cc37f08cdf8c98884d78155a0c3289c1efabbcbf6439377ffce65231ac79520

View File

@ -0,0 +1 @@
e3835afdbfa2d06ef31f4eb0d47d8a7463ac7b38415e378f759b66296145cff5

View File

@ -0,0 +1 @@
4173ca3d43f3a8e990cf729fc6eda5b86979ebfa79e7bc185487e8d06c427c73

View File

@ -0,0 +1 @@
7afb4e884d0cb08ee0dec7d8043e28277ccae844a0c51cacf59c648eaca4ee78

View File

@ -0,0 +1 @@
db46e72b7285377b0e7a6de03f82366789d4d90106efdf9824a0e98aadde4985

View File

@ -0,0 +1 @@
9b89315a16190eb416e6eb76621a1cebf6df98e1fe135a3b0411063c1a1e14b6

View File

@ -0,0 +1 @@
7be31444f198efaee82f4c5835657b54fda852472c3753af9c6e04e1c59bb82b

View File

@ -0,0 +1 @@
46f7d7fcc1345c80d5b2ecca2a7023c1693f1ec247c7dd18a9b3e556ca56bee6

View File

@ -178,6 +178,21 @@ RETURN NULL;
END
$$;
CREATE FUNCTION ensure_lists_sharding_key() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW."project_id" IS NULL AND NEW."group_id" IS NULL THEN
SELECT "boards"."project_id", "boards"."group_id"
INTO NEW."project_id", NEW."group_id"
FROM "boards"
WHERE "boards"."id" = NEW."board_id";
END IF;
RETURN NEW;
END
$$;
CREATE TABLE namespaces (
id bigint NOT NULL,
name character varying NOT NULL,
@ -7984,6 +7999,7 @@ CREATE TABLE ai_settings (
amazon_q_role_arn text,
duo_workflow_service_account_user_id bigint,
duo_workflow_oauth_application_id bigint,
duo_nano_features_enabled boolean,
CONSTRAINT check_3cf9826589 CHECK ((char_length(ai_gateway_url) <= 2048)),
CONSTRAINT check_a02bd8868c CHECK ((char_length(amazon_q_role_arn) <= 2048)),
CONSTRAINT check_singleton CHECK ((singleton IS TRUE))
@ -16807,7 +16823,9 @@ CREATE TABLE lists (
max_issue_count integer DEFAULT 0 NOT NULL,
max_issue_weight integer DEFAULT 0 NOT NULL,
limit_metric character varying(20),
iteration_id bigint
iteration_id bigint,
group_id bigint,
project_id bigint
);
CREATE SEQUENCE lists_id_seq
@ -23338,7 +23356,7 @@ ALTER SEQUENCE subscription_add_ons_id_seq OWNED BY subscription_add_ons.id;
CREATE TABLE subscription_seat_assignments (
id bigint NOT NULL,
namespace_id bigint NOT NULL,
namespace_id bigint,
user_id bigint NOT NULL,
last_activity_on timestamp with time zone,
created_at timestamp with time zone NOT NULL,
@ -29033,6 +29051,9 @@ ALTER TABLE ONLY instance_type_ci_runners
ALTER TABLE ONLY project_type_ci_runners
ADD CONSTRAINT check_619c71f3a2 UNIQUE (id);
ALTER TABLE lists
ADD CONSTRAINT check_6dadb82d36 CHECK ((num_nonnulls(group_id, project_id) = 1)) NOT VALID;
ALTER TABLE description_versions
ADD CONSTRAINT check_76c1eb7122 CHECK ((num_nonnulls(epic_id, issue_id, merge_request_id) = 1)) NOT VALID;
@ -35634,6 +35655,8 @@ CREATE UNIQUE INDEX index_list_user_preferences_on_user_id_and_list_id ON list_u
CREATE UNIQUE INDEX index_lists_on_board_id_and_label_id ON lists USING btree (board_id, label_id);
CREATE INDEX index_lists_on_group_id ON lists USING btree (group_id);
CREATE INDEX index_lists_on_iteration_id ON lists USING btree (iteration_id);
CREATE INDEX index_lists_on_label_id ON lists USING btree (label_id);
@ -35642,6 +35665,8 @@ CREATE INDEX index_lists_on_list_type ON lists USING btree (list_type);
CREATE INDEX index_lists_on_milestone_id ON lists USING btree (milestone_id);
CREATE INDEX index_lists_on_project_id ON lists USING btree (project_id);
CREATE INDEX index_lists_on_user_id ON lists USING btree (user_id);
CREATE INDEX index_loose_foreign_keys_deleted_records_for_partitioned_query ON ONLY loose_foreign_keys_deleted_records USING btree (partition, fully_qualified_table_name, consume_after, id) WHERE (status = 1);
@ -38488,7 +38513,7 @@ CREATE UNIQUE INDEX uniq_idx_streaming_destination_id_and_namespace_id ON audit_
CREATE UNIQUE INDEX uniq_idx_streaming_group_destination_id_and_namespace_id ON audit_events_streaming_group_namespace_filters USING btree (external_streaming_destination_id, namespace_id);
CREATE UNIQUE INDEX uniq_idx_subscription_seat_assignments_on_namespace_and_user ON subscription_seat_assignments USING btree (namespace_id, user_id);
CREATE UNIQUE INDEX uniq_idx_subscription_seat_assignments_on_namespace_id_and_user ON subscription_seat_assignments USING btree (namespace_id, user_id) WHERE (namespace_id IS NOT NULL);
CREATE UNIQUE INDEX uniq_idx_user_add_on_assignments_on_add_on_purchase_and_user ON subscription_user_add_on_assignments USING btree (add_on_purchase_id, user_id);
@ -41580,6 +41605,8 @@ CREATE TRIGGER trigger_efb9d354f05a BEFORE INSERT OR UPDATE ON incident_manageme
CREATE TRIGGER trigger_eff80ead42ac BEFORE INSERT OR UPDATE ON ci_unit_test_failures FOR EACH ROW EXECUTE FUNCTION trigger_eff80ead42ac();
CREATE TRIGGER trigger_ensure_lists_sharding_key BEFORE INSERT OR UPDATE ON lists FOR EACH ROW EXECUTE FUNCTION ensure_lists_sharding_key();
CREATE TRIGGER trigger_f6c61cdddf31 BEFORE INSERT OR UPDATE ON ml_model_metadata FOR EACH ROW EXECUTE FUNCTION trigger_f6c61cdddf31();
CREATE TRIGGER trigger_f6f59d8216b3 BEFORE INSERT OR UPDATE ON protected_environment_deploy_access_levels FOR EACH ROW EXECUTE FUNCTION trigger_f6f59d8216b3();
@ -42518,6 +42545,9 @@ ALTER TABLE p_ci_builds
ALTER TABLE ONLY routes
ADD CONSTRAINT fk_679ff8213d FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE NOT VALID;
ALTER TABLE ONLY lists
ADD CONSTRAINT fk_67f2498cc9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE NOT VALID;
ALTER TABLE ONLY merge_requests_approval_rules_approver_groups
ADD CONSTRAINT fk_67fa93ad4b FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@ -43742,6 +43772,9 @@ ALTER TABLE ONLY cluster_agents
ALTER TABLE ONLY protected_tag_create_access_levels
ADD CONSTRAINT fk_f7dfda8c51 FOREIGN KEY (protected_tag_id) REFERENCES protected_tags(id) ON DELETE CASCADE;
ALTER TABLE ONLY lists
ADD CONSTRAINT fk_f8b2e8680c FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE NOT VALID;
ALTER TABLE ONLY project_requirement_compliance_statuses
ADD CONSTRAINT fk_f9109a4712 FOREIGN KEY (compliance_framework_id) REFERENCES compliance_management_frameworks(id) ON DELETE CASCADE;

View File

@ -8,7 +8,7 @@ title: Auditor users
{{< details >}}
- Tier: Premium, Ultimate
- Offering: GitLab Self-Managed
- Offering: GitLab Self-Managed, GitLab Dedicated
{{< /details >}}

View File

@ -152,7 +152,7 @@ IPv6 address. If you don't have IPv6, you can omit the `AAAA` record.
To configure GitLab Pages DNS for single-domain sites without wildcard DNS:
1. Enable the GitLab Pages flag for this feature by adding
`gitlab_pages["namespace_in_path"] = true` to `/etc/gitlab/gitlab.rb`.
`gitlab_pages['namespace_in_path'] = true` to `/etc/gitlab/gitlab.rb`.
1. In your DNS provider, add entries for `example.io`.
Replace `example.io` with your domain name, and `192.0.0.0` with
the IPv4 version of your IP address. The entries look like this:
@ -268,7 +268,7 @@ To configure GitLab Pages to use single-domain sites:
pages_external_url 'http://example.io' # Important: not a subdomain of external_url, so cannot be http://pages.example.com
# Set this flag to enable this feature
gitlab_pages["namespace_in_path"] = true
gitlab_pages['namespace_in_path'] = true
```
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
@ -363,7 +363,7 @@ daemon doesn't listen to the public internet:
pages_nginx['redirect_http_to_https'] = true
# Set this flag to enable this feature
gitlab_pages["namespace_in_path"] = true
gitlab_pages['namespace_in_path'] = true
```
1. If your TLS certificate and key don't match the name of your domain, like

View File

@ -41738,6 +41738,7 @@ AI features that can be configured through the Duo self-hosted feature settings.
| <a id="aifeaturesduo_chat_explain_vulnerability"></a>`DUO_CHAT_EXPLAIN_VULNERABILITY` | Duo chat explain vulnerability feature setting. |
| <a id="aifeaturesduo_chat_fix_code"></a>`DUO_CHAT_FIX_CODE` | Duo chat fix code feature setting. |
| <a id="aifeaturesduo_chat_refactor_code"></a>`DUO_CHAT_REFACTOR_CODE` | Duo chat refactor code feature setting. |
| <a id="aifeaturesduo_chat_summarize_comments"></a>`DUO_CHAT_SUMMARIZE_COMMENTS` | Duo chat summarize comment feature setting. |
| <a id="aifeaturesduo_chat_troubleshoot_job"></a>`DUO_CHAT_TROUBLESHOOT_JOB` | Duo chat troubleshoot job feature setting. |
| <a id="aifeaturesduo_chat_write_tests"></a>`DUO_CHAT_WRITE_TESTS` | Duo chat write test feature setting. |
| <a id="aifeaturesgenerate_commit_message"></a>`GENERATE_COMMIT_MESSAGE` | Generate commit message feature setting. |

View File

@ -25,20 +25,13 @@ see [Conan packages in the package registry](../../user/packages/conan_repositor
Generally, these endpoints are used by the [Conan 1 package manager client](https://docs.conan.io/en/latest/)
and are not meant for manual consumption.
For instructions on how to upload and install Conan packages from the GitLab
package registry, see the [Conan package registry documentation](../../user/packages/conan_repository/_index.md).
{{< alert type="note" >}}
These endpoints do not adhere to the standard API authentication methods.
- These endpoints do not adhere to the standard API authentication methods.
See each route for details on how credentials are expected to be passed. Undocumented authentication methods might be removed in the future.
{{< /alert >}}
{{< alert type="note" >}}
The Conan registry is not FIPS compliant and is disabled when [FIPS mode](../../development/fips_gitlab.md) is enabled.
These endpoints will all return 404 Not Found.
- The Conan registry is not FIPS compliant and is disabled when [FIPS mode](../../development/fips_gitlab.md) is enabled.
These endpoints all return `404 Not Found`.
{{< /alert >}}

View File

@ -18,37 +18,30 @@ title: Conan v2 API
{{< /history >}}
{{< alert type="note" >}}
For Conan v1 operations, see [Conan v1 API](conan_v1.md).
{{< /alert >}}
Use this API to interact with the Conan v2 package manager. For more information, see [Conan packages in the package registry](../../user/packages/conan_repository/_index.md).
{{< alert type="flag" >}}
The availability of this feature is controlled by a feature flag. For more information, see the history.
{{< /alert >}}
Generally, these endpoints are used by the [Conan 2 package manager client](https://docs.conan.io/2/index.html)
and are not meant for manual consumption.
For instructions on how to upload and install Conan packages from the GitLab
package registry, see the [Conan package registry documentation](../../user/packages/conan_repository/_index.md) and [Conan 2 package manager client](https://docs.conan.io/2/index.html).
{{< alert type="note" >}}
These endpoints do not adhere to the standard API authentication methods.
See each route for details on how credentials are expected to be passed. Undocumented authentication methods might be removed in the future.
For Conan v1 operations, see [Conan v1 API](conan_v1.md).
{{< /alert >}}
Use this API to interact with the Conan v2 package manager. For more information, see [Conan packages in the package registry](../../user/packages/conan_repository/_index.md) or [Conan 2 package manager client](https://docs.conan.io/2/index.html).
Generally, these endpoints are used by the [Conan 2 package manager client](https://docs.conan.io/2/index.html)
and are not meant for manual consumption.
{{< alert type="note" >}}
The Conan registry is not FIPS compliant and is disabled when [FIPS mode](../../development/fips_gitlab.md) is enabled.
These endpoints will all return 404 Not Found.
- These endpoints do not adhere to the standard API authentication methods.
See each route for details on how credentials are expected to be passed. Undocumented authentication methods might be removed in the future.
- The Conan registry is not FIPS compliant and is disabled when [FIPS mode](../../development/fips_gitlab.md) is enabled.
These endpoints all return `404 Not Found`.
{{< /alert >}}
## Route prefix

View File

@ -9,11 +9,7 @@ Now for the fun part. Let's edit some code.
In this example, I found some UI text I'd like to change.
In the upper-right corner in GitLab, I selected my avatar and then **Preferences**.
I want to change `Customize the color of GitLab` to `Customize the color theme of the GitLab UI`:
![The UI text in GitLab before making the change.](../img/ui_color_theme_before_v16_9.png)
[View an interactive demo of this section](https://gitlab.navattic.com/uu5a0dc5).
I want to change `Syntax highlighting theme` to `Code syntax highlighting theme`:
Use your local IDE to make changes to the code in the GDK directory.
@ -23,13 +19,12 @@ Use your local IDE to make changes to the code in the GDK directory.
git checkout -b ui-updates
```
1. Search the `gitlab-development-kit/gitlab` directory for the string `Customize the color of GitLab`.
1. Search the `gitlab-development-kit/gitlab` directory for the string `Syntax highlighting theme`.
The results show one `.haml` file and several `.po` files.
1. Open the `app/views/profiles/preferences/show.html.haml` file.
1. Update the string from `Customize the color of GitLab` to
`Customize the color theme of the GitLab UI`.
1. Update the string from `Syntax highlighting theme` to
`Code syntax highlighting theme`.
1. Save the file.
1. You can check that you were successful:
@ -43,8 +38,6 @@ Use your local IDE to make changes to the code in the GDK directory.
1. Refresh the web browser where you're viewing the GDK.
The changes should be displayed. Take a screenshot.
![The UI text in GitLab after making the change.](../img/ui_color_theme_after_v16_9.png)
1. Commit the changes:
```shell

View File

@ -9,9 +9,7 @@ Now for the fun part. Let's edit some code.
In this example, I found some UI text I'd like to change.
In the upper-right corner in GitLab, I selected my avatar and then **Preferences**.
I want to change `Customize the color of GitLab` to `Customize the color theme of the GitLab UI`:
![The UI text in GitLab before making the change.](../img/ui_color_theme_before_v16_9.png)
I want to change `Syntax highlighting theme` to `Code syntax highlighting theme`:
1. Create a new branch for your changes:
@ -22,12 +20,12 @@ I want to change `Customize the color of GitLab` to `Customize the color theme o
The examples in this doc use a new branch called `ui-updates`.
1. Search the repository for the string `Customize the color of GitLab`:
1. Search the repository for the string `Syntax highlighting theme`:
- In VS Code, select the search icon <i class="fa fa-search fa-flip-horizontal" aria-hidden="true"></i> from the side toolbar.
1. Select the `app/views/profiles/preferences/show.html.haml` file.
1. Update the string to `Customize the color theme of the GitLab UI`.
1. Update the string to `Code syntax highlighting theme`.
1. Save your changes.
1. Use the IDE **Terminal** tab to commit the changes:
@ -36,7 +34,7 @@ I want to change `Customize the color of GitLab` to `Customize the color theme o
Standardizing the text on this page so
that each area uses consistent language."
```
```
Follow the GitLab
[commit message guidelines](../merge_request_workflow.md#commit-messages-guidelines).

View File

@ -12,21 +12,21 @@ to GitLab code using the Web IDE.
1. Go to the [GitLab community fork](https://gitlab.com/gitlab-community/gitlab).
1. Search the GitLab code for the string `Customize the color of GitLab`.
1. Search the GitLab code for the string `Syntax highlighting theme`.
From the [GitLab Community Fork](https://gitlab.com/gitlab-community/gitlab):
1. On the left sidebar, select **Search or go to**.
1. Enter the search string `"Customize the color of GitLab"`.
1. Enter the search string `"Syntax highlighting theme"`.
1. Select the filename
[from the results](https://gitlab.com/search?search=%22Customize+the+color+of+GitLab%22&nav_source=navbar&project_id=41372369&group_id=60717473&search_code=true).
[from the results](https://gitlab.com/search?search=%22Syntax+highlighting+theme%22&nav_source=navbar&project_id=41372369&group_id=60717473&search_code=true).
In this case, `app/views/profiles/preferences/show.html.haml`.
1. Open the file in Web IDE. Select **Edit > Open in Web IDE**.
- Keyboard shortcut: <kbd>.</kbd>
1. Update the string from `Customize the color of GitLab` to `Customize the color theme of the GitLab UI`.
1. Update the string from `Syntax highlighting theme` to `Code syntax highlighting theme`.
1. Save your changes.

View File

@ -59,7 +59,7 @@ See also [guidelines for heading levels in Markdown](../styleguide/_index.md#hea
## Related topics
If inline links are not sufficient, you can create a topic called **Related topics**
If inline links are not sufficient, you can create a section called **Related topics**
and include an unordered list of related topics. This topic should be above the Troubleshooting section.
Links in this section should be brief and scannable. They are usually not

View File

@ -148,7 +148,6 @@ install, and upgrade your Docker-based GitLab installation:
1. Create a `docker-compose.yml` file. For example:
```yaml
version: '3.6'
services:
gitlab:
image: gitlab/gitlab-ee:<version>-ee.0
@ -182,7 +181,6 @@ install, and upgrade your Docker-based GitLab installation:
`ports` section:
```yaml
version: '3.6'
services:
gitlab:
image: gitlab/gitlab-ee:<version>-ee.0
@ -302,7 +300,6 @@ Here's an example that deploys GitLab with four runners as a [stack](https://doc
1. Create a `docker-compose.yml` file:
```yaml
version: "3.6"
services:
gitlab:
image: gitlab/gitlab-ee:<version>-ee.0

View File

@ -74,7 +74,7 @@ For more information on:
label: "Provider name", # optional label for login button, defaults to "Saml"
args: {
assertion_consumer_service_url: "https://gitlab.example.com/users/auth/saml/callback",
idp_cert_fingerprint: "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8",
idp_cert_fingerprint: "2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6",
idp_sso_target_url: "https://login.example.com/idp",
issuer: "https://gitlab.example.com",
name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
@ -83,18 +83,15 @@ For more information on:
]
```
Where:
| Argument | Description |
| -------------------------------- | ----------- |
| `assertion_consumer_service_url` | The GitLab HTTPS endpoint (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). |
| `idp_cert_fingerprint` | Your IdP value. To generate the SHA256 fingerprint from the certificate, see [calculate the fingerprint](../user/group/saml_sso/troubleshooting.md#calculate-the-fingerprint). |
| `idp_sso_target_url` | Your IdP value. |
| `issuer` | Change to a unique name, which identifies the application to the IdP. |
| `name_identifier_format` | Your IdP value. |
- `assertion_consumer_service_url`: The GitLab HTTPS endpoint
(append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation).
- `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint.
For more information on these values, see the
[OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml).
For more information on other configuration settings, see
[configuring SAML on your IdP](#configure-saml-on-your-idp).
- `idp_sso_target_url`: Your IdP value.
- `issuer`: Change to a unique name, which identifies the application to the IdP.
- `name_identifier_format`: Your IdP value.
For more information on these values, see the [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). For more information on other configuration settings, see [configuring SAML on your IdP](#configure-saml-on-your-idp).
1. Save the file and reconfigure GitLab:
@ -158,24 +155,21 @@ For more information on:
label: 'Provider name' # optional label for login button, defaults to "Saml"
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
```
Where:
| Argument | Description |
| -------------------------------- | ----------- |
| `assertion_consumer_service_url` | The GitLab HTTPS endpoint (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). |
| `idp_cert_fingerprint` | Your IdP value. To generate the SHA256 fingerprint from the certificate, see [calculate the fingerprint](../user/group/saml_sso/troubleshooting.md#calculate-the-fingerprint). |
| `idp_sso_target_url` | Your IdP value. |
| `issuer` | Change to a unique name, which identifies the application to the IdP. |
| `name_identifier_format` | Your IdP value. |
- `assertion_consumer_service_url`: The GitLab HTTPS endpoint
(append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation).
- `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint.
For more information on these values, see the
[OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml).
For more information on other configuration settings, see
[configuring SAML on your IdP](#configure-saml-on-your-idp).
- `idp_sso_target_url`: Your IdP value.
- `issuer`: Change to a unique name, which identifies the application to the IdP.
- `name_identifier_format`: Your IdP value.
For more information on these values, see the [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). For more information on other configuration settings, see [configuring SAML on your IdP](#configure-saml-on-your-idp).
1. Create the Kubernetes Secret:
@ -258,7 +252,7 @@ For more information on:
label: "Provider name", # optional label for login button, defaults to "Saml"
args: {
assertion_consumer_service_url: "https://gitlab.example.com/users/auth/saml/callback",
idp_cert_fingerprint: "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8",
idp_cert_fingerprint: "2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6",
idp_sso_target_url: "https://login.example.com/idp",
issuer: "https://gitlab.example.com",
name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
@ -267,18 +261,15 @@ For more information on:
]
```
Where:
| Argument | Description |
| -------------------------------- | ----------- |
| `assertion_consumer_service_url` | The GitLab HTTPS endpoint (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). |
| `idp_cert_fingerprint` | Your IdP value. To generate the SHA256 fingerprint from the certificate, see [calculate the fingerprint](../user/group/saml_sso/troubleshooting.md#calculate-the-fingerprint). |
| `idp_sso_target_url` | Your IdP value. |
| `issuer` | Change to a unique name, which identifies the application to the IdP. |
| `name_identifier_format` | Your IdP value. |
- `assertion_consumer_service_url`: The GitLab HTTPS endpoint
(append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation).
- `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint.
For more information on these values, see the
[OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml).
For more information on other configuration settings, see
[configuring SAML on your IdP](#configure-saml-on-your-idp).
- `idp_sso_target_url`: Your IdP value.
- `issuer`: Change to a unique name, which identifies the application to the IdP.
- `name_identifier_format`: Your IdP value.
For more information on these values, see the [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). For more information on other configuration settings, see [configuring SAML on your IdP](#configure-saml-on-your-idp).
1. Save the file and restart GitLab:
@ -336,7 +327,7 @@ For more information on:
label: 'Provider name', # optional label for login button, defaults to "Saml"
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -344,18 +335,15 @@ For more information on:
}
```
Where:
| Argument | Description |
| -------------------------------- | ----------- |
| `assertion_consumer_service_url` | The GitLab HTTPS endpoint (append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation). |
| `idp_cert_fingerprint` | Your IdP value. To generate the SHA256 fingerprint from the certificate, see [calculate the fingerprint](../user/group/saml_sso/troubleshooting.md#calculate-the-fingerprint). |
| `idp_sso_target_url` | Your IdP value. |
| `issuer` | Change to a unique name, which identifies the application to the IdP. |
| `name_identifier_format` | Your IdP value. |
- `assertion_consumer_service_url`: The GitLab HTTPS endpoint
(append `/users/auth/saml/callback` to the HTTPS URL of your GitLab installation).
- `idp_cert_fingerprint`: Your IdP value. It must be a SHA1 fingerprint.
For more information on these values, see the
[OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml).
For more information on other configuration settings, see
[configuring SAML on your IdP](#configure-saml-on-your-idp).
- `idp_sso_target_url`: Your IdP value.
- `issuer`: Change to a unique name, which identifies the application to the IdP.
- `name_identifier_format`: Your IdP value.
For more information on these values, see the [OmniAuth SAML documentation](https://github.com/omniauth/omniauth-saml). For more information on other configuration settings, see [configuring SAML on your IdP](#configure-saml-on-your-idp).
1. Save the file and restart GitLab:
@ -720,10 +708,11 @@ To set up a Google Workspace:
When configuring the Google Workspace SAML application, record the following information:
| | Value | Description |
|-------------|--------------|-----------------------------------------------------------------------------------|
| SSO URL | Depends | Google Identity Provider details. Set to the GitLab `idp_sso_target_url` setting. |
| Certificate | Downloadable | Run `openssl x509 -in <your_certificate.crt> -noout -fingerprint -sha1` to generate the SHA1 fingerprint that can be used in the `idp_cert_fingerprint` setting. |
| | Value | Description |
| ------------------ | ------------ | ----------- |
| SSO URL | Depends | Google Identity Provider details. Set to the GitLab `idp_sso_target_url` setting. |
| Certificate | Downloadable | Google SAML certificate. |
| SHA256 fingerprint | Depends | Available when you download the certificate. To generate the SHA256 fingerprint from the certificate, see [calculate the fingerprint](../user/group/saml_sso/troubleshooting.md#calculate-the-fingerprint). |
Google Workspace Administrator also provides the IdP metadata, Entity ID, and SHA-256
fingerprint. However, GitLab does not need this information to connect to the
@ -940,7 +929,7 @@ If the attribute specified in `groups_attribute` is incorrect or missing then al
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -969,7 +958,7 @@ If the attribute specified in `groups_attribute` is incorrect or missing then al
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1022,7 +1011,7 @@ If the attribute specified in `groups_attribute` is incorrect or missing then al
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1053,7 +1042,7 @@ If the attribute specified in `groups_attribute` is incorrect or missing then al
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1111,7 +1100,7 @@ Example configuration:
external_groups: ['Freelancers'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1140,7 +1129,7 @@ Example configuration:
external_groups: ['Freelancers']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1193,7 +1182,7 @@ Example configuration:
external_groups: ['Freelancers'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1224,7 +1213,7 @@ Example configuration:
external_groups: ['Freelancers'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1275,7 +1264,7 @@ Example configuration:
admin_groups: ['Admins'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1304,7 +1293,7 @@ Example configuration:
admin_groups: ['Admins']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1357,7 +1346,7 @@ Example configuration:
admin_groups: ['Admins'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1388,7 +1377,7 @@ Example configuration:
admin_groups: ['Admins'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1446,7 +1435,7 @@ Example configuration:
auditor_groups: ['Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1475,7 +1464,7 @@ Example configuration:
auditor_groups: ['Auditors']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1528,7 +1517,7 @@ Example configuration:
auditor_groups: ['Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1559,7 +1548,7 @@ Example configuration:
auditor_groups: ['Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1623,7 +1612,7 @@ list.
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -1656,7 +1645,7 @@ list.
label: 'Our SAML Provider'
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1711,7 +1700,7 @@ list.
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1746,7 +1735,7 @@ list.
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1798,7 +1787,7 @@ An example configuration:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1825,7 +1814,7 @@ An example configuration:
label: 'Our SAML Provider'
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1876,7 +1865,7 @@ An example configuration:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -1905,7 +1894,7 @@ An example configuration:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -2237,7 +2226,7 @@ instead of `email`, let GitLab know by setting it on your configuration:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2265,7 +2254,7 @@ instead of `email`, let GitLab know by setting it on your configuration:
label: 'Our SAML Provider'
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -2318,7 +2307,7 @@ instead of `email`, let GitLab know by setting it on your configuration:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2348,7 +2337,7 @@ instead of `email`, let GitLab know by setting it on your configuration:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2390,7 +2379,7 @@ Configure [`username` or `nickname`](omniauth.md#per-provider-configuration) in
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2418,7 +2407,7 @@ Configure [`username` or `nickname`](omniauth.md#per-provider-configuration) in
label: 'Our SAML Provider'
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -2473,7 +2462,7 @@ Configure [`username` or `nickname`](omniauth.md#per-provider-configuration) in
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2505,7 +2494,7 @@ Configure [`username` or `nickname`](omniauth.md#per-provider-configuration) in
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2560,7 +2549,7 @@ These attributes have no default mappings and do not sync unless explicitly conf
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2592,7 +2581,7 @@ These attributes have no default mappings and do not sync unless explicitly conf
label: 'Our SAML Provider'
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -2647,7 +2636,7 @@ These attributes have no default mappings and do not sync unless explicitly conf
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2681,7 +2670,7 @@ These attributes have no default mappings and do not sync unless explicitly conf
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2728,7 +2717,7 @@ The value given is added to the current time at which the response is validated.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2758,7 +2747,7 @@ The value given is added to the current time at which the response is validated.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -2812,7 +2801,7 @@ The value given is added to the current time at which the response is validated.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2844,7 +2833,7 @@ The value given is added to the current time at which the response is validated.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2895,7 +2884,7 @@ In the following example, the value of `uid` attribute in the SAML response is s
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -2925,7 +2914,7 @@ In the following example, the value of `uid` attribute in the SAML response is s
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -2979,7 +2968,7 @@ In the following example, the value of `uid` attribute in the SAML response is s
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3011,7 +3000,7 @@ In the following example, the value of `uid` attribute in the SAML response is s
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3075,7 +3064,7 @@ This makes the key file one long string with no line feeds.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3106,7 +3095,7 @@ This makes the key file one long string with no line feeds.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors']
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -3161,7 +3150,7 @@ This makes the key file one long string with no line feeds.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3194,7 +3183,7 @@ This makes the key file one long string with no line feeds.
required_groups: ['Developers', 'Freelancers', 'Admins', 'Auditors'],
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3242,7 +3231,7 @@ To implement signing:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3279,7 +3268,7 @@ To implement signing:
label: 'Our SAML Provider'
args:
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback'
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8'
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6'
idp_sso_target_url: 'https://login.example.com/idp'
issuer: 'https://gitlab.example.com'
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
@ -3339,7 +3328,7 @@ To implement signing:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
@ -3378,7 +3367,7 @@ To implement signing:
label: 'Our SAML Provider',
args: {
assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
idp_cert_fingerprint: '2f:cb:19:57:68:c3:9e:9a:94:ce:c2:c2:e3:2c:59:c0:aa:d7:a3:36:5c:10:89:2e:81:16:b5:d8:3d:40:96:b6',
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',

View File

@ -54,7 +54,7 @@ If you're interested in a region not listed here, contact your account represent
When setting up GitLab Dedicated, you select a secondary region to host a failover instance for
disaster recovery. Some AWS regions are available only as secondary regions because they do not fully support certain AWS
features that GitLab Dedicated relies on. If GitLab initiates a failover to your secondary region during
a disaster recovery event or test, these limitations may impact available features.
a disaster recovery event or test, these limitations impact available features.
The following regions are verified for use as a secondary region but with known limitations:
@ -80,13 +80,15 @@ The following regions are verified for use as a secondary region but with known
These limitations may affect your service in the following ways:
- **No io2 volume support**: Regions without io2 volume support use gp3 volumes instead, which offer lower
data durability (99.8-99.9% compared to 99.999% for io2), potentially longer [RTO and RPO](https://handbook.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/) recovery times, and
may affect failover capabilities if rebuilding is necessary.
- **No io2 volume support**: In regions where AWS does not support io2 volumes, GitLab Dedicated uses GP3
volumes instead. GP3 volumes have lower durability (99.8-99.9% compared to 99.999% for io2), which
increases the risk of disk failures in your replica region. This can affect availability during failover
or while operating in the failed-over state. As a result, these regions are not covered by our standard
[RTO and RPO](https://handbook.gitlab.com/handbook/engineering/infrastructure/team/gitlab-dedicated/slas/) time objectives.
- **No SES support**: Regions without AWS Simple Email Service (SES) support cannot send email
notifications using the default configuration. To maintain email functionality in these regions,
you must set up your own [external SMTP mail service](../../administration/dedicated/configure_instance/users_notifications.md#smtp-email-service).
- **No SES support**: In regions where AWS does not support Simple Email Service (SES), GitLab
cannot send email notifications using the default configuration. To maintain email functionality
in these regions, set up your own [external SMTP mail service](../../administration/dedicated/configure_instance/users_notifications.md#smtp-email-service).
During onboarding, regions with these limitations are clearly marked. You must acknowledge the
associated risks before selecting one as your secondary region.

View File

@ -96,7 +96,7 @@ There are multiple ways to configure security scans in new projects:
- In a scan execution policy to enforce that pipelines run specific security scanners.
- In a pipeline execution policy to control which jobs must run in pipelines.
For simple use cases, you can use the project's CI/CD configuration. For a comprehensive security strategy, consider combining merge request approval policies with the other policy types.
For simple use cases, you can use the project's CI/CD configuration. For a comprehensive security strategy, consider combining merge request approval policies with the other policy types.
To minimize unnecessary approval requirements and ensure accurate security evaluations:
@ -248,20 +248,42 @@ This rule enforces the defined actions based on security scan findings.
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../../administration/feature_flags.md) named `license_scanning_policies`.
- [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/397644) in GitLab 15.11. Feature flag `license_scanning_policies` removed.
- The `branch_exceptions` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418741) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `security_policies_branch_exceptions`. Enabled by default. [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/133753) in GitLab 16.5. Feature flag removed.
- The `licenses` field was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/10203) in GitLab 17.11 [with a flag](../../../administration/feature_flags.md) named `exclude_license_packages`. Disabled by default.
{{< /history >}}
This rule enforces the defined actions based on license findings.
| Field | Type | Required | Possible values | Description |
|----------------------|---------------------|--------------------------------------------|------------------------------|-------------|
| `type` | `string` | true | `license_finding` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of protected branches the given policy applies to. Cannot be used with the `branches` field. Default branches must also be `protected`. |
| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `match_on_inclusion_license` | `boolean` | true | `true`, `false` | Whether the rule matches inclusion or exclusion of licenses listed in `license_types`. |
| `license_types` | `array` of `string` | true | license types | [SPDX license names](https://spdx.org/licenses) to match on, for example `Affero General Public License v1.0` or `MIT License`. |
| `license_states` | `array` of `string` | true | `newly_detected`, `detected` | Whether to match newly detected and/or previously detected licenses. The `newly_detected` state triggers approval when either a new package is introduced or when a new license for an existing package is detected. |
| Field | Type | Required | Possible values | Description |
|----------------|----------|-----------------------------------------------|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `type` | `string` | true | `license_finding` | The rule's type. |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of protected branches the given policy applies to. Cannot be used with the `branches` field. Default branches must also be `protected`. |
| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `match_on_inclusion_license` | `boolean` | true if `licenses` field does not exists | `true`, `false` | Whether the rule matches inclusion or exclusion of licenses listed in `license_types`. |
| `license_types` | `array` of `string` | true if `licenses` field does not exists | license types | [SPDX license names](https://spdx.org/licenses) to match on, for example `Affero General Public License v1.0` or `MIT License`. |
| `license_states` | `array` of `string` | true | `newly_detected`, `detected` | Whether to match newly detected and/or previously detected licenses. The `newly_detected` state triggers approval when either a new package is introduced or when a new license for an existing package is detected. |
| `licenses` | `object` | true if `license_types` field does not exists | `licenses` object | [SPDX license names](https://spdx.org/licenses) to match on including package exceptions. |
### `licenses` object
| Field | Type | Required | Possible values | Description |
|-----------|----------|-----------------------------------------|------------------------------------------------------|------------------------------------------------------------|
| `denied` | `object` | true if `allowed` field does not exist | `array` of `licenses_with_package_exclusion` objects | The list of denied licenses including package exceptions. |
| `allowed` | `object` | true if `denied` field does not exist | `array` of `licenses_with_package_exclusion` objects | The list of allowed licenses including package exceptions. |
### `licenses_with_package_exclusion` object
| Field | Type | Required | Possible values | Description |
|--------|----------|----------|-------------------|----------------------------------------------------|
| `name` | `string` | true | SPDX license name | [SPDX license name](https://spdx.org/licenses). |
| `packages` | `object` | false | `packages` object | List of packages exceptions for the given license. |
### `packages` object
| Field | Type | Required | Possible values | Description |
|--------|----------|----------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `excluding` | `object` | true | {purls: `array` of `strings` using the `uri` format} | List of package exceptions for the given license. Define the list of packages exceptions using the [`purl`](https://github.com/package-url/purl-spec?tab=readme-ov-file#purl) components `scheme:type/name@version`. The `scheme:type/name` components are required. The `@` and `version` are optional. If a version is specified, only that version is considered an exception. If no version is specified and the `@` character is added at the end of the `purl`, only packages with the exact name is considered a match. If the `@` character is not added to the package name, all packages with the same prefix for the given license are matches. For example, a purl `pkg:gem/bundler` matches the `bundler` and `bundler-stats` packages because both packages use the same license. Defining a `purl` `pkg:gem/bundler@` matches only the `bundler` package. |
## `any_merge_request` rule type

View File

@ -87,14 +87,7 @@ To set up Google Workspace as your identity provider:
| **GitLab single sign-on URL** | **Start URL** |
| **Identity provider single sign-on URL** | **SSO URL** |
1. Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint
required by GitLab to [configure SAML](#configure-gitlab):
1. Download the certificate.
1. Run this command:
```shell
openssl x509 -noout -fingerprint -sha1 -inform pem -in "GoogleIDPCertificate-domain.com.pem"
```
1. Google Workspace displays a SHA256 fingerprint when you retrieve the certificate. If you need to generate the SHA256 fingerprint later, see [calculate the fingerprint](troubleshooting.md#calculate-the-fingerprint).
1. Set these values:
- For **Primary email**: `email`.
@ -225,7 +218,7 @@ The following GitLab settings correspond to the Keycloak fields.
1. Retrieve the certificate fingerprint.
1. Note the value of the `<ds:X509Certificate>` tag.
1. Convert the value to [PEM format](https://www.ssl.com/guide/pem-der-crt-and-cer-x-509-encodings-and-conversions/#ftoc-heading-3).
1. [Calculate the fingerprint](../../group/saml_sso/troubleshooting.md#calculate-the-fingerprint).
1. [Calculate the fingerprint](troubleshooting.md#calculate-the-fingerprint).
### Configure assertions
@ -323,12 +316,6 @@ After you set up your identity provider to work with GitLab, you must configure
For more information, see the [SSO enforcement documentation](#sso-enforcement).
1. Select **Save changes**.
{{< alert type="note" >}}
The certificate [fingerprint algorithm](../../../integration/saml.md#configure-saml-on-your-idp) must be in SHA1. When configuring the identity provider (such as [Google Workspace](#google-workspace)), use a secure signature algorithm.
{{< /alert >}}
If you are having issues configuring GitLab, see the [troubleshooting documentation](#troubleshooting).
## User access and management

View File

@ -85,13 +85,6 @@ If available, you can add user-friendly group names instead. When setting up Azu
### IdP links and certificate
{{< alert type="note" >}}
Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint required by GitLab for configuring SAML, download the certificate and calculate the SHA1 certificate
fingerprint.
{{< /alert >}}
![Google Workspace Links and Certificate](img/GoogleWorkspace-linkscert_v14_10.png)
## Okta

View File

@ -219,13 +219,13 @@ For convenience, we've included some [example resources](example_saml_config.md)
### Calculate the fingerprint
If you use a `idp_cert_fingerprint`, it must be a SHA1 fingerprint. To calculate a SHA1 fingerprint, download the certificate file and run:
When configuring the `idp_cert_fingerprint` you should use a SHA256 fingerprint whenever possible. SHA1 is also supported, but is not recommended. You can calculate the fingerprint by running the following command on the certificate file:
```shell
openssl x509 -in <filename.crt> -noout -fingerprint -sha1
openssl x509 -in <certificate.crt> -noout -fingerprint -sha256
```
Replace `filename.crt` with the name of the certificate file.
Replace `<certificate.crt>` with the name of the certificate file.
## SSO Certificate updates
@ -248,8 +248,7 @@ must be validated using either a fingerprint, a certificate, or a validator.
For this requirement, be sure to take the following into account:
- If you use a fingerprint, it must be the correct SHA1 fingerprint. To confirm that you are using
the correct SHA1 fingerprint:
- If you use a fingerprint, confirm your SHA256 fingerprint:
1. Re-download the certificate file.
1. [Calculate the fingerprint](#calculate-the-fingerprint).
1. Compare the fingerprint to the value provided in `idp_cert_fingerprint`. The values should be the same.

View File

@ -48,13 +48,14 @@ A running workspace remains accessible to the user even if user permissions are
{{< history >}}
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/125331) in GitLab 16.2.
- Managing workspaces from the **Code** menu [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178492) in GitLab 17.11.
{{< /history >}}
To manage workspaces from a project:
1. On the left sidebar, select **Search or go to** and find your project.
1. In the upper right, select **Edit**.
1. In the upper right, select **Code**.
1. From the dropdown list, under **Your workspaces**, you can:
- Restart, stop, or terminate an existing workspace.
- Create a new workspace.

View File

@ -89,6 +89,9 @@ Instance methods required:
- `operation`: determines the operation which can be one of `upsert` or `delete`
- `identifier`: unique identifier
Optional methods:
- `unique_identifiers`: array of identifiers to build a unique identifier for every document. For example, `[identifier, branch_name]`. Defaults to `[identifier]`
Example for a reference reading from a database relation, with preloading and bulk embedding generation:
```ruby

View File

@ -88,10 +88,10 @@ module ActiveContext
def build_index_operations(ref)
return unless ref.operation.to_sym == :upsert
ref.jsons.map.with_index do |hash, index|
ref.jsons.map do |hash|
add_index_operation([
{ update: { _index: ref.partition, _id: unique_identifier(ref, index), routing: ref.routing }.compact },
{ doc: hash, doc_as_upsert: true }
{ update: { _index: ref.partition, _id: hash[:unique_identifier], routing: ref.routing }.compact },
{ doc: hash.except(:unique_identifier), doc_as_upsert: true }
])
end
end

View File

@ -54,10 +54,6 @@ module ActiveContext
# also reset anything that builds up from the refs array
end
def unique_identifier(ref, index)
"#{ref.identifier}:#{index}"
end
def extract_identifier(string)
string.split(':').first
end

View File

@ -29,8 +29,7 @@ module ActiveContext
end
def process_bulk_errors(result)
# we already return only failed references so nothing to do here
result
result.uniq { |ref| ref.unique_identifier(nil) }
end
def reset
@ -43,8 +42,8 @@ module ActiveContext
def build_operation(ref)
case ref.operation.to_sym
when :upsert
ref.jsons.each.with_index do |hash, index|
@operations << { "#{ref.partition_name}": { upsert: build_indexed_json(hash, ref, index) }, ref: ref }
ref.jsons.each do |hash|
@operations << { "#{ref.partition_name}": { upsert: build_indexed_json(hash, ref) }, ref: ref }
end
@operations << build_delete_operation(ref: ref, include_ref_version: true)
when :delete
@ -54,12 +53,13 @@ module ActiveContext
end
end
def build_indexed_json(hash, ref, index)
def build_indexed_json(hash, ref)
hash
.merge(
partition_id: ref.partition_number,
id: unique_identifier(ref, index)
id: hash[:unique_identifier]
)
.except(:unique_identifier)
.transform_values { |value| convert_pg_array(value) }
end

View File

@ -78,8 +78,9 @@ module ActiveContext
docs = docs.map { |doc| base.merge(doc) }
end
docs.map do |json|
docs.map.with_index do |json, index|
json.merge(
unique_identifier: unique_identifier(index),
ref_id: identifier,
ref_version: ref_version
)
@ -100,6 +101,14 @@ module ActiveContext
raise NotImplementedError
end
def unique_identifier(index)
[unique_identifiers, index].flatten.join(':')
end
def unique_identifiers
[identifier]
end
def partition_name
collection.name
end

View File

@ -59,6 +59,8 @@ module Keeps
query = "SELECT EXISTS (SELECT 1 FROM #{table_name_quoted} LIMIT 1)"
pg_client.exec_params(query)
rescue PG::UndefinedTable
false
end
private

View File

@ -24,7 +24,6 @@ module Banzai
multiline_block_quotes: true,
relaxed_autolinks: true,
sourcepos: true,
experimental_inline_sourcepos: true,
smart: false,
strikethrough: true,
table: true,
@ -45,7 +44,6 @@ module Banzai
OPTIONS.merge(
sourcepos: !sourcepos_disabled?,
experimental_inline_sourcepos: sourcepos_disabled? ? false : OPTIONS[:experimental_inline_sourcepos],
header_ids: headers_disabled? ? nil : OPTIONS[:header_ids],
autolink: !autolink_disabled?,
relaxed_autolinks: !autolink_disabled?,

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
class BackfillListsShardingKey < BatchedMigrationJob
operation_name :set_lists_sharding_key
feature_category :team_planning
def perform
each_sub_batch do |sub_batch|
connection.execute(
<<~SQL
WITH sub_batch AS MATERIALIZED (#{sub_batch.select(:id, :board_id).limit(sub_batch_size).to_sql})
UPDATE
"lists"
SET
"group_id" = "boards"."group_id", "project_id" = "boards"."project_id"
FROM
"sub_batch"
INNER JOIN "boards" ON "boards"."id" = "sub_batch"."board_id"
WHERE
"lists"."id" = "sub_batch"."id"
SQL
)
end
end
end
end
end

View File

@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'base64'
module Gitlab
module Doctor
class EncryptionKeys
attr_reader :logger
PRINT_PROGRESS_EVERY = 1000
KEY_TYPES = Gitlab::Encryption::KeyProvider::KEY_PROVIDERS.keys.grep(/active_record/)
Key = Struct.new(:type, :id, :truncated_secret)
def initialize(logger)
@logger = logger
end
def run!
logger.info "Gathering existing encryption keys:"
known_keys.each do |key|
logger.info "- #{key.type}: ID => `#{key.id}`; truncated secret => `#{key.truncated_secret}`"
end
logger.info "\n"
logger.info "Gathering encryption keys for models with Active Record Encryption attributes"
Rails.application.eager_load!
encryption_keys_usage_per_model =
models_with_encrypted_attributes.index_with do |model|
gather_encryption_keys(model)
end
encryption_keys_usage_per_model.each do |model, encryption_keys_usage|
logger.info "Encryption keys usage for #{model.name}:#{' NONE' if encryption_keys_usage.empty?}"
encryption_keys_usage.each do |key, count|
logger.info "- `#{key}`#{' (UNKNOWN KEY!)' unless known_keys.map(&:id).include?(key)} => #{count}"
end
end
end
private
def known_keys
@known_keys ||= KEY_TYPES.each_with_object([]) do |key_type, memo|
Gitlab::Encryption::KeyProvider[key_type].decryption_keys.each do |key|
memo << Key.new(key_type, key.id)
end
end.tap do |keys| # rubocop:disable Style/MultilineBlockChain -- avoid a local instance
populate_actual_secrets!(keys)
end
end
def populate_actual_secrets!(keys)
KEY_TYPES.each do |key_type|
actual_secrets = Gitlab::Encryption::KeyProvider::KEY_PROVIDERS[key_type].secrets.call
keys.select { |k| k.type == key_type }.each_with_index do |key, index|
key.truncated_secret = "#{actual_secrets[index][...3]}...#{actual_secrets[index][-3..]}"
end
end
end
def gather_encryption_keys(model)
encrypted_attributes = model.encrypted_attributes
total_count = model.count
return {} if total_count == 0
encryption_keys_usage = Hash.new { |hash, key| hash[key] = 0 }
model.find_each.with_index do |instance, index|
encrypted_attributes.each do |attribute_name|
encryption_keys_usage[encryption_key(instance, attribute_name)] += 1
end
logger.info "Checked #{index + 1}/#{total_count} #{model.name.pluralize}" if index % PRINT_PROGRESS_EVERY == 0
end
logger.info "Checked #{total_count} #{model.name.pluralize}\n"
encryption_keys_usage
end
def encryption_key(instance, attribute_name)
Base64.decode64(Gitlab::Json.parse(instance.ciphertext_for(attribute_name))['h']['i'])
end
def models_with_encrypted_attributes
ApplicationRecord.descendants.select { |d| d.encrypted_attributes.present? }
end
end
end
end

View File

@ -15,6 +15,11 @@ module Gitlab
Gitlab::CryptoHelper.sha256("#{instance_id}#{user_id}")
end
def self.instance_uuid
instance_id = Gitlab::CryptoHelper.sha256('instance')
Gitlab::UUID.v5(instance_id)
end
def self.instance_id
::Gitlab::CurrentSettings.uuid.presence || GITLAB_INSTANCE_UUID_NOT_SET
end

View File

@ -157,14 +157,16 @@ module Gitlab
payload.merge!(::Gitlab::Instrumentation::Middleware::PathTraversalCheck.payload)
end
# Returns the queuing duration for a Sidekiq job in seconds, as a float, if the
# Returns the total queuing duration for a Sidekiq job in seconds, as a float, if the
# `enqueued_at` field or `created_at` field is available.
# Includes buffering duration if a job was buffered by ConcurrencyLimit middleware.
#
# * If the job doesn't contain sufficient information, returns nil
# * If the job has a start time in the future, returns 0
# * If the job contains an invalid start time value, returns nil
# @param [Hash] job a Sidekiq job, represented as a hash
def self.queue_duration_for_job(job)
# @param [Boolean] with_buffering_duration whether to include buffering duration by ConcurrencyLimit
def self.queue_duration_for_job(job, with_buffering_duration: true)
# Old gitlab-shell messages don't provide enqueued_at/created_at attributes
enqueued_at = job['enqueued_at'] || job['created_at']
return unless enqueued_at
@ -172,11 +174,18 @@ module Gitlab
enqueued_at_time = convert_to_time(enqueued_at)
return unless enqueued_at_time
round_elapsed_time(enqueued_at_time)
buffering_duration = buffering_duration_for_job(job) # concurrency_limit_buffered_at -> enqueued_at
queueing_duration = round_elapsed_time(enqueued_at_time) # enqueued_at -> now
if with_buffering_duration && !queueing_duration.nil? && !buffering_duration.nil?
queueing_duration += buffering_duration
end
queueing_duration
end
# Returns the buffering duration for a Sidekiq job in seconds, as a float, if the
# `concurrency_limit_buffered_at` field is available.
# Returns the time a Sidekiq job waiting from being buffered until enqueued again in seconds, as a float, if the
# `concurrency_limit_buffered_at` and `enqueued_at`/`created_at` field is available.
#
# * If the job doesn't contain sufficient information, returns nil
# * If the job has a start time in the future, returns 0
@ -186,10 +195,17 @@ module Gitlab
buffered_at = job['concurrency_limit_buffered_at']
return unless buffered_at
# Old gitlab-shell messages don't provide enqueued_at/created_at attributes
enqueued_at = job['enqueued_at'] || job['created_at']
return unless enqueued_at
buffered_at_time = convert_to_time(buffered_at)
return unless buffered_at_time
round_elapsed_time(buffered_at_time)
enqueued_at_time = convert_to_time(enqueued_at)
return unless enqueued_at
round_elapsed_time(buffered_at_time, enqueued_at_time)
end
# Returns the time it took for a scheduled job to be enqueued in seconds, as a float,

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
module Gitlab
module Redis
class CursorStore
def initialize(cache_key, ttl: 1.hour)
@cache_key = cache_key
@ttl = ttl.to_i
end
def commit(payload)
Gitlab::Redis::SharedState.with do |redis|
redis.hset(cache_key, payload, ex: ttl)
end
end
def cursor
Gitlab::Redis::SharedState.with do |redis|
redis.hgetall(cache_key)
end.except('ex')
end
private
attr_reader :cache_key, :ttl
end
end
end

View File

@ -7,7 +7,8 @@ require 'sidekiq/job_retry'
module Gitlab
module SidekiqLogging
class JSONFormatter
TIMESTAMP_FIELDS = %w[created_at scheduled_at enqueued_at started_at retried_at failed_at completed_at].freeze
TIMESTAMP_FIELDS = %w[created_at scheduled_at enqueued_at started_at retried_at failed_at completed_at
concurrency_limit_buffered_at].freeze
def call(severity, timestamp, progname, data)
output = {

View File

@ -59,10 +59,12 @@ module Gitlab
payload['concurrency_limit_buffering_duration_s'] = buffering_duration_s if buffering_duration_s
queue_duration_s = ::Gitlab::InstrumentationHelper.queue_duration_for_job(payload)
scheduling_duration_s = ::Gitlab::InstrumentationHelper.queue_duration_for_job(job,
with_buffering_duration: false)
if queue_duration_s
payload['queue_duration_s'] = queue_duration_s
payload['scheduling_latency_s'] = queue_duration_s + buffering_duration_s.to_f
payload['scheduling_latency_s'] = scheduling_duration_s
end
enqueue_latency_s = ::Gitlab::InstrumentationHelper.enqueue_latency_for_scheduled_job(payload)

View File

@ -3,7 +3,7 @@
module Gitlab
module Tracking
class StandardContext
GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-1-1'
GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-1-5'
GITLAB_RAILS_SOURCE = 'gitlab-rails'
def initialize(
@ -61,6 +61,7 @@ module Gitlab
feature_enabled_by_namespace_ids: feature_enabled_by_namespace_ids,
realm: realm,
instance_id: instance_id,
unique_instance_id: Gitlab::GlobalAnonymousId.instance_uuid,
host_name: Gitlab::Environment.hostname,
instance_version: Gitlab.version_info.to_s,
context_generated_at: Time.current

View File

@ -26,5 +26,11 @@ namespace :gitlab do
Gitlab::Doctor::ResetTokens.new(logger, model_names: model_names, token_names: token_names, dry_run: dry_run).run!
end
desc "GitLab | Check Active Record Encryption keys"
task encryption_keys: :gitlab_environment do
logger = Logger.new($stdout)
Gitlab::Doctor::EncryptionKeys.new(logger).run!
end
end
end

View File

@ -3975,6 +3975,9 @@ msgstr ""
msgid "AdminAIPoweredFeatures|An error occurred while loading the AI feature settings. Please try again."
msgstr ""
msgid "AdminAIPoweredFeatures|Apply to all sub-features"
msgstr ""
msgid "AdminAIPoweredFeatures|Assists developers by providing real-time code completions and recommendations. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@ -4269,9 +4272,18 @@ msgstr ""
msgid "AdminSelfHostedModels|An error occurred while loading the self-hosted model. Please try again."
msgstr ""
msgid "AdminSelfHostedModels|An error occurred while updating the %{mainFeature} sub-feature settings. Please try again."
msgstr ""
msgid "AdminSelfHostedModels|An error occurred while updating the self-hosted model, please try again."
msgstr ""
msgid "AdminSelfHostedModels|Apply to all %{mainFeature} sub-features"
msgstr ""
msgid "AdminSelfHostedModels|Assign a setting to the %{subFeatureTitle} sub-feature before applying to all"
msgstr ""
msgid "AdminSelfHostedModels|Create self-hosted model"
msgstr ""
@ -48244,6 +48256,9 @@ msgstr ""
msgid "ProjectsNew|Choose a group"
msgstr ""
msgid "ProjectsNew|Choose a group or namespace"
msgstr ""
msgid "ProjectsNew|Connect your external repository to GitLab CI/CD."
msgstr ""
@ -48382,6 +48397,12 @@ msgstr ""
msgid "ProjectsNew|Please enter a valid username."
msgstr ""
msgid "ProjectsNew|Please enter project name."
msgstr ""
msgid "ProjectsNew|Please enter project slug."
msgstr ""
msgid "ProjectsNew|Please upload a valid GitLab project export file."
msgstr ""
@ -55508,9 +55529,6 @@ msgstr ""
msgid "SecurityReports|Export"
msgstr ""
msgid "SecurityReports|Export as CSV"
msgstr ""
msgid "SecurityReports|Failed to get security report information. Please reload the page or try again later."
msgstr ""
@ -69135,9 +69153,6 @@ msgstr ""
msgid "Workspaces|When no devfile is provided, the GitLab default devfile will be used."
msgstr ""
msgid "Workspaces|Workspace automatically terminates after"
msgstr ""
msgid "Workspaces|Workspaces"
msgstr ""

View File

@ -11,6 +11,10 @@ RSpec.describe 'Triggers', :js, feature_category: :continuous_integration do
let_it_be(:guest_user) { create(:user) }
let_it_be(:project) { create(:project) }
before do
stub_feature_flags(vue_project_runners_settings: false)
end
before_all do
project.add_maintainer(user)
project.add_maintainer(user2)

View File

@ -1,6 +1,7 @@
import MultiStepFormTemplate from '~/vue_shared/components/multi_step_form_template.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BlankProjectForm from '~/projects/new_v2/components/blank_project_form.vue';
import SharedProjectCreationFields from '~/projects/new_v2/components/shared_project_creation_fields.vue';
describe('Blank Project Form', () => {
let wrapper;
@ -25,6 +26,7 @@ describe('Blank Project Form', () => {
});
const findMultiStepFormTemplate = () => wrapper.findComponent(MultiStepFormTemplate);
const findSharedProjectCreationFields = () => wrapper.findComponent(SharedProjectCreationFields);
const findCreateButton = () => wrapper.findByTestId('create-project-button');
const findBackButton = () => wrapper.findByTestId('create-project-back-button');
@ -36,6 +38,12 @@ describe('Blank Project Form', () => {
});
});
describe('form', () => {
it('renders the SharedProjectCreationFields component', () => {
expect(findSharedProjectCreationFields().exists()).toBe(true);
});
});
it('renders the option to Create Project as disabled', () => {
expect(findCreateButton().text()).toBe('Create project');
expect(findCreateButton().props('disabled')).toBe(true);

View File

@ -0,0 +1,83 @@
import { nextTick } from 'vue';
import { GlFormInput } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SharedProjectCreationFields from '~/projects/new_v2/components/shared_project_creation_fields.vue';
import NewProjectDestinationSelect from '~/projects/new_v2/components/project_destination_select.vue';
describe('Project creation form fields component', () => {
let wrapper;
const defaultProps = {
namespace: {
id: '1',
fullPath: 'root',
isPersonal: true,
},
};
const createComponent = (props = {}) => {
wrapper = shallowMountExtended(SharedProjectCreationFields, {
propsData: {
...defaultProps,
...props,
},
stubs: {
GlFormInput,
},
});
};
beforeEach(() => {
createComponent();
});
const findProjectNameInput = () => wrapper.findByTestId('project-name-input');
const findProjectSlugInput = () => wrapper.findByTestId('project-slug-input');
const findNamespaceSelect = () => wrapper.findComponent(NewProjectDestinationSelect);
it('updates project slug according to a project name', async () => {
// NOTE: vue3 test needs the .setValue(value) and the vm.$emit('input'),
// while the vue2 needs either .setValue(value) or vm.$emit('input', value)
const value = 'My Awesome Project 123';
findProjectNameInput().setValue(value);
findProjectNameInput().vm.$emit('input', value);
await nextTick();
expect(findProjectSlugInput().element.value).toBe('my-awesome-project-123');
});
it('emits namespace change', () => {
findNamespaceSelect().vm.$emit('onSelectNamespace', {
id: '2',
fullPath: 'group/subgroup',
isPersonal: false,
});
expect(wrapper.emitted('onSelectNamespace')).toHaveLength(1);
expect(wrapper.emitted('onSelectNamespace')[0][0]).toEqual({
id: '2',
fullPath: 'group/subgroup',
isPersonal: false,
});
});
describe('validation', () => {
it('shows an error message when project name is cleared', async () => {
findProjectNameInput().setValue('');
findProjectNameInput().trigger('blur');
await nextTick();
const formGroup = wrapper.findByTestId('project-name-group');
expect(formGroup.vm.$attrs['invalid-feedback']).toBe('Please enter project name.');
});
it('shows an error message when slug is cleared', async () => {
findProjectSlugInput().setValue('');
findProjectSlugInput().trigger('blur');
await nextTick();
const formGroup = wrapper.findByTestId('project-slug-group');
expect(formGroup.vm.$attrs['invalid-feedback']).toBe('Please enter project slug.');
});
});
});

View File

@ -43,6 +43,7 @@ describe('CreateWorkItemModal', () => {
preselectedWorkItemType = 'EPIC',
relatedItem = null,
alwaysShowWorkItemTypeSelect = false,
namespaceFullName = 'GitLab.org / GitLab',
} = {}) => {
wrapper = shallowMount(CreateWorkItemModal, {
propsData: {
@ -51,6 +52,7 @@ describe('CreateWorkItemModal', () => {
hideButton,
relatedItem,
alwaysShowWorkItemTypeSelect,
namespaceFullName,
},
provide: {
fullPath: 'full-path',
@ -88,6 +90,7 @@ describe('CreateWorkItemModal', () => {
await nextTick();
expect(findCreateModal().props('visible')).toBe(true);
expect(findForm().props('namespaceFullName')).toBe('GitLab.org / GitLab');
expect(mockEvent.preventDefault).toHaveBeenCalled();
});

View File

@ -241,9 +241,13 @@ describe('Create work item component', () => {
);
it('defaults the selected project to the injected `fullPath` value', async () => {
createComponent({ props: { showProjectSelector: true } });
const namespaceFullName = 'GitLab.org / GitLab';
createComponent({
props: { showProjectSelector: true, namespaceFullName },
});
await waitForPromises();
expect(findProjectsSelector().props('currentProjectName')).toBe(namespaceFullName);
expect(findProjectsSelector().props('selectedProjectFullPath')).toBe('full-path');
});
});

View File

@ -299,16 +299,17 @@ describe('Work item add note', () => {
describe('when the work item type is changed to incident', () => {
it.each`
command | shouldPerformReload
${'/promote_to_incident'} | ${true}
${'/type Incident'} | ${true}
${'/type incident'} | ${true}
${'/promote_to Incident'} | ${true}
${'/promote_to incident'} | ${true}
${'/promote_to Epic'} | ${false}
${'/type Issue'} | ${false}
${'/type Task'} | ${false}
${'No quick action'} | ${false}
command | shouldPerformReload
${'/promote_to_incident'} | ${true}
${'/type Incident'} | ${true}
${'/type incident'} | ${true}
${'/promote_to Incident'} | ${true}
${'/promote_to incident'} | ${true}
${'/convert_to_ticket user@example.com'} | ${true}
${'/promote_to Epic'} | ${false}
${'/type Issue'} | ${false}
${'/type Task'} | ${false}
${'No quick action'} | ${false}
`(
'calls visitUrl $shouldPerformReload when note was added with command: $command',
async ({ command, shouldPerformReload }) => {

View File

@ -143,6 +143,7 @@ describe('WorkItemActions component', () => {
workItemsBeta = true,
parentId = null,
projectId = 'gid://gitlab/Project/1',
namespaceFullName = 'GitLab.org / GitLab Test',
} = {}) => {
wrapper = shallowMountExtended(WorkItemActions, {
isLoggedIn: isLoggedIn(),
@ -179,6 +180,7 @@ describe('WorkItemActions component', () => {
canCreateRelatedItem,
parentId,
projectId,
namespaceFullName,
showSidebar: true,
truncationEnabled: true,
},
@ -666,6 +668,7 @@ describe('WorkItemActions component', () => {
it('passes related item data to create work item modal', () => {
createComponent();
expect(findCreateWorkItemModal().props('namespaceFullName')).toBe('GitLab.org / GitLab Test');
expect(findCreateWorkItemModal().props('relatedItem')).toEqual({
id: 'gid://gitlab/WorkItem/1',
reference: 'gitlab-org/gitlab-test#1',

View File

@ -251,6 +251,7 @@ and more text
and even more`,
hideButton: true,
isGroup: false,
namespaceFullName: '',
parentId: 'gid://gitlab/WorkItem/818',
relatedItem: null,
showProjectSelector: false,

View File

@ -33,7 +33,8 @@ RSpec.describe GitlabSchema.types['Group'], feature_category: :groups_and_projec
contact_state_counts contacts work_item_types
recent_issue_boards ci_variables releases environment_scopes work_items autocomplete_users
lock_math_rendering_limits_enabled math_rendering_limits_enabled created_at updated_at
organization_edit_path is_linked_to_subscription cluster_agents
organization_edit_path is_linked_to_subscription cluster_agents marked_for_deletion_on
is_adjourned_deletion_enabled permanent_deletion_date
]
expect(described_class).to include_graphql_fields(*expected_fields)
@ -290,4 +291,88 @@ RSpec.describe GitlabSchema.types['Group'], feature_category: :groups_and_projec
end
end
end
describe 'group adjourned deletion fields', feature_category: :groups_and_projects do
let_it_be(:user) { create(:user) }
let_it_be(:pending_delete_group) do
create(:group_with_deletion_schedule, marked_for_deletion_on: Time.current, developers: user)
end
let_it_be(:query) do
%(
query {
group(fullPath: "#{pending_delete_group.full_path}") {
markedForDeletionOn
isAdjournedDeletionEnabled
permanentDeletionDate
}
}
)
end
subject(:group_data) do
result = GitlabSchema.execute(query, context: { current_user: user }).as_json
{
marked_for_deletion_on: result.dig('data', 'group', 'markedForDeletionOn'),
is_adjourned_deletion_enabled: result.dig('data', 'group', 'isAdjournedDeletionEnabled'),
permanent_deletion_date: result.dig('data', 'group', 'permanentDeletionDate')
}
end
context 'with adjourned deletion disabled' do
before do
allow_next_found_instance_of(Group) do |group|
allow(group).to receive_messages(adjourned_deletion?: false, adjourned_deletion_configured?: false)
end
end
it 'marked_for_deletion_on returns nil' do
expect(group_data[:marked_for_deletion_on]).to be_nil
end
it 'is_adjourned_deletion_enabled returns false' do
expect(group_data[:is_adjourned_deletion_enabled]).to be false
end
it 'permanent_deletion_date returns nil' do
expect(group_data[:permanent_deletion_date]).to be_nil
end
end
context 'with adjourned deletion enabled' do
before do
allow_next_found_instance_of(Group) do |group|
allow(group).to receive_messages(adjourned_deletion?: true, adjourned_deletion_configured?: true)
end
end
it 'marked_for_deletion_on returns correct date' do
marked_for_deletion_on_time = Time.zone.parse(group_data[:marked_for_deletion_on])
expect(marked_for_deletion_on_time).to eq(pending_delete_group.marked_for_deletion_on.iso8601)
end
it 'is_adjourned_deletion_enabled returns true' do
expect(group_data[:is_adjourned_deletion_enabled]).to be true
end
it 'permanent_deletion_date returns correct date', :freeze_time do
expect(group_data[:permanent_deletion_date])
.to eq(::Gitlab::CurrentSettings.deletion_adjourned_period.days.since(Date.current).strftime('%F'))
end
end
context 'with adjourned deletion enabled globally' do
before do
allow_next_found_instance_of(Group) do |group|
allow(group).to receive_messages(adjourned_deletion?: false, adjourned_deletion_configured?: true)
end
end
it 'permanent_deletion_date returns correct date', :freeze_time do
expect(group_data[:permanent_deletion_date])
.to eq(::Gitlab::CurrentSettings.deletion_adjourned_period.days.since(Date.current).strftime('%F'))
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More