Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-10-31 18:27:33 +00:00
parent b579182e26
commit bf13bba8a2
72 changed files with 487 additions and 424 deletions

View File

@ -36,7 +36,9 @@ They are frequently updated, and everyone should make sure they are aware of the
## EM/PM release post item checklist
- [ ] Set yourself as the Assignee, meaning you are the DRI.
- [ ] If the deprecation is a [breaking change](https://handbook.gitlab.com/handbook/product/gitlab-the-product/#breaking-changes), add label `breaking change`.
- [ ] For [breaking changes](https://handbook.gitlab.com/handbook/product/gitlab-the-product/#breaking-changes):
- [ ] Add the `breaking change` label to the MR.
- [ ] If the breaking change affects GitLab.com, add `window` with a value of `1`, `2`, or `3`. The value represents the planned release window for GitLab.com, typically in the three weeks before the major release date. You should intentionally plan this window ahead of time. If you're not sure, ask `@swiskow`.
- [ ] Confirm this MR is labeled ~"release post item::deprecation"
- [ ] Follow the process to [create a deprecation YAML file](https://handbook.gitlab.com/handbook/marketing/blog/release-posts/#creating-the-announcement).
- [ ] Add reviewers by the 10th.

View File

@ -229,7 +229,7 @@
{"name":"gitlab-glfm-markdown","version":"0.0.21","platform":"ruby","checksum":"cb960ac1bc509d72b460c9dc934fb0a02cf061a5de6b1b00c72b794817d63b40"},
{"name":"gitlab-glfm-markdown","version":"0.0.21","platform":"x86_64-darwin","checksum":"8425ee27e0b32b75619e08e1700c1302297b44928adc19a026bea243c96363f5"},
{"name":"gitlab-glfm-markdown","version":"0.0.21","platform":"x86_64-linux","checksum":"9ea7d7a7a20c15960839521459a82edab787a4d8475ee412beba8362aa5fcd71"},
{"name":"gitlab-kas-grpc","version":"17.5.0","platform":"ruby","checksum":"4b0af5619e3cc68d7293abb7dca96f5cab7d9700c42622e525e78d36d43a744c"},
{"name":"gitlab-kas-grpc","version":"17.5.1","platform":"ruby","checksum":"88639bfaa9301d78a7fbff696ec262ed696a15a6f41c1b51bffe6b39c7a61ca7"},
{"name":"gitlab-labkit","version":"0.36.1","platform":"ruby","checksum":"04fb6941b7e5fc1fdcee8f9971fa2086a4dc442e39e67a74b992403dd580c300"},
{"name":"gitlab-license","version":"2.5.0","platform":"ruby","checksum":"4c166c469c2ad17876ca43188a4ccebe3feb0726c4c1770047f8dcef96573f4d"},
{"name":"gitlab-mail_room","version":"0.0.25","platform":"ruby","checksum":"223ce7c3c0797b6015eaa37147884e6ddc7be9a7ee90a424358c96bc18613b1a"},

View File

@ -739,7 +739,7 @@ GEM
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.21)
rb_sys (= 0.9.94)
gitlab-kas-grpc (17.5.0)
gitlab-kas-grpc (17.5.1)
grpc (~> 1.0)
gitlab-labkit (0.36.1)
actionpack (>= 5.0.0, < 8.0.0)

View File

@ -230,7 +230,7 @@
{"name":"gitlab-glfm-markdown","version":"0.0.21","platform":"ruby","checksum":"cb960ac1bc509d72b460c9dc934fb0a02cf061a5de6b1b00c72b794817d63b40"},
{"name":"gitlab-glfm-markdown","version":"0.0.21","platform":"x86_64-darwin","checksum":"8425ee27e0b32b75619e08e1700c1302297b44928adc19a026bea243c96363f5"},
{"name":"gitlab-glfm-markdown","version":"0.0.21","platform":"x86_64-linux","checksum":"9ea7d7a7a20c15960839521459a82edab787a4d8475ee412beba8362aa5fcd71"},
{"name":"gitlab-kas-grpc","version":"17.5.0","platform":"ruby","checksum":"4b0af5619e3cc68d7293abb7dca96f5cab7d9700c42622e525e78d36d43a744c"},
{"name":"gitlab-kas-grpc","version":"17.5.1","platform":"ruby","checksum":"88639bfaa9301d78a7fbff696ec262ed696a15a6f41c1b51bffe6b39c7a61ca7"},
{"name":"gitlab-labkit","version":"0.36.1","platform":"ruby","checksum":"04fb6941b7e5fc1fdcee8f9971fa2086a4dc442e39e67a74b992403dd580c300"},
{"name":"gitlab-license","version":"2.5.0","platform":"ruby","checksum":"4c166c469c2ad17876ca43188a4ccebe3feb0726c4c1770047f8dcef96573f4d"},
{"name":"gitlab-mail_room","version":"0.0.25","platform":"ruby","checksum":"223ce7c3c0797b6015eaa37147884e6ddc7be9a7ee90a424358c96bc18613b1a"},

View File

@ -749,7 +749,7 @@ GEM
nokogiri (~> 1, >= 1.10.8)
gitlab-glfm-markdown (0.0.21)
rb_sys (= 0.9.94)
gitlab-kas-grpc (17.5.0)
gitlab-kas-grpc (17.5.1)
grpc (~> 1.0)
gitlab-labkit (0.36.1)
actionpack (>= 5.0.0, < 8.0.0)

View File

@ -400,6 +400,7 @@ export default {
},
submit() {
this.$emit(this.isEditing ? 'update-variable' : 'add-variable', this.variableToEmit);
this.$refs.drawer.$el.scrollTo({ top: 0, behavior: 'smooth' });
},
trackVariableValidationErrors() {
const property = this.getTrackingErrorProperty();
@ -440,6 +441,7 @@ export default {
<template>
<div>
<gl-drawer
ref="drawer"
open
data-testid="ci-variable-drawer"
:header-height="getDrawerHeaderHeight"
@ -663,10 +665,9 @@ export default {
>
{{ $options.i18n.variableReferenceDescription }}
</gl-alert>
<div class="gl-flex">
<div class="gl-mb-5 gl-flex gl-gap-3">
<gl-button
category="primary"
class="gl-mr-3"
variant="confirm"
:disabled="!canSubmit"
data-testid="ci-variable-confirm-button"
@ -678,7 +679,6 @@ export default {
v-gl-modal-directive="`delete-variable-${variable.key}`"
variant="danger"
category="secondary"
class="gl-mr-3"
data-testid="ci-variable-delete-button"
>{{ $options.i18n.deleteVariable }}</gl-button
>

View File

@ -99,6 +99,7 @@ export default {
data() {
return {
ciVariables: [],
environments: [],
hasNextPage: false,
isInitialLoading: true,
isLoadingMoreItems: false,
@ -158,7 +159,6 @@ export default {
}
},
},
// eslint-disable-next-line @gitlab/vue-no-undef-apollo-properties
environments: {
query() {
return this.queryData?.environments?.query || {};

View File

@ -6,10 +6,10 @@ export default {
modal: {
id: 'delete-pipeline-schedule-modal',
deleteConfirmation: s__(
'PipelineSchedules|Are you sure you want to delete this pipeline schedule?',
'PipelineSchedules|Are you sure you want to delete this scheduled pipeline?',
),
actionPrimary: {
text: s__('PipelineSchedules|Delete pipeline schedule'),
text: s__('PipelineSchedules|Delete scheduled pipeline'),
attributes: { variant: 'danger' },
},
actionCancel: {

View File

@ -4,9 +4,9 @@ import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
export const i18n = {
playTooltip: s__('PipelineSchedules|Run pipeline schedule'),
editTooltip: s__('PipelineSchedules|Edit pipeline schedule'),
deleteTooltip: s__('PipelineSchedules|Delete pipeline schedule'),
playTooltip: s__('PipelineSchedules|Run scheduled pipeline'),
editTooltip: s__('PipelineSchedules|Edit scheduled pipeline'),
deleteTooltip: s__('PipelineSchedules|Delete scheduled pipeline'),
takeOwnershipTooltip: s__('PipelineSchedules|Take ownership of pipeline schedule'),
};

View File

@ -93,7 +93,7 @@ export default {
<gl-button
:disabled="disabled"
category="primary"
variant="confirm"
variant="default"
:href="template.link"
data-testid="template-link"
@click="trackEvent(template.name)"

View File

@ -233,7 +233,6 @@ export default {
icon: 'approval',
token: UserToken,
dataType: 'user',
operators: OPERATORS_IS_NOT,
fullPath: this.fullPath,
isProject: true,
recentSuggestionsStorageKey: `${this.fullPath}-merge_requests-recent-tokens-approved_by`,
@ -259,7 +258,6 @@ export default {
icon: 'user',
token: UserToken,
dataType: 'user',
operators: OPERATORS_IS_NOT,
fullPath: this.fullPath,
isProject: true,
recentSuggestionsStorageKey: `${this.fullPath}-merge-requests-recent-tokens-assignee`,
@ -273,7 +271,6 @@ export default {
icon: 'user',
token: UserToken,
dataType: 'user',
operators: OPERATORS_IS_NOT,
fullPath: this.fullPath,
isProject: true,
recentSuggestionsStorageKey: `${this.fullPath}-merge-requests-recent-tokens-reviewer`,
@ -363,7 +360,6 @@ export default {
title: TOKEN_TITLE_LABEL,
icon: 'labels',
token: LabelToken,
operators: OPERATORS_IS_NOT,
fetchLabels: this.fetchLabels,
recentSuggestionsStorageKey: `${this.fullPath}-merge_requests-recent-tokens-label`,
},
@ -416,7 +412,6 @@ export default {
title: TOKEN_TITLE_MY_REACTION,
icon: 'thumb-up',
token: EmojiToken,
operators: OPERATORS_IS_NOT,
unique: true,
fetchEmojis: this.fetchEmojis,
recentSuggestionsStorageKey: `${this.fullPath}-merge_requests-recent-tokens-my_reaction`,

View File

@ -18,7 +18,7 @@ export default ({ el, router }) => {
const { projectPath, ref, isBlob, webIdeUrl, ...options } = convertObjectPropsToCamelCase(
JSON.parse(el.dataset.options),
);
const { webIdePromoPopoverImg, cssClasses } = el.dataset;
const { webIdePromoPopoverImg, cssClasses, defaultBranch } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
@ -37,7 +37,15 @@ export default ({ el, router }) => {
webIdeUrl: isBlob
? webIdeUrl
: webIDEUrl(
joinPaths('/', projectPath, 'edit', ref, '-', this.$route?.params.path || '', '/'),
joinPaths(
'/',
projectPath,
'edit',
ref || defaultBranch,
'-',
this.$route?.params.path || '',
'/',
),
),
projectPath,
cssClasses,

View File

@ -11,6 +11,7 @@ import initAmbiguousRefModal from '~/ref/init_ambiguous_ref_modal';
import CodeDropdown from '~/vue_shared/components/code_dropdown/code_dropdown.vue';
import initSourceCodeDropdowns from '~/vue_shared/components/download_dropdown/init_download_dropdowns';
import EmptyProject from '~/pages/projects/show/empty_project';
import initWebIdeLink from '~/pages/projects/shared/web_ide_link';
import { initHomePanel } from '../home_panel';
// Project show page loads different overview content based on user preferences
@ -94,3 +95,4 @@ initCodeDropdown();
initSourceCodeDropdowns();
initFindFileShortcut();
initEmptyProjectTabs();
initWebIdeLink({ el: document.getElementById('js-tree-web-ide-link') });

View File

@ -145,7 +145,7 @@ export default {
this.queryFilterValues = { ...data };
},
updateCounts() {
this.$apollo.queries.todosCount.refetch();
this.$apollo.queries.pendingTodosCount.refetch();
},
},
};

View File

@ -238,7 +238,7 @@ export default {
return this.gitpodText || __('Gitpod');
},
computedShowGitpodButton() {
return this.showGitpodButton && this.gitpodEnabled;
return this.showGitpodButton && this.gitpodEnabled && this.gitpodUrl;
},
pipelineEditorAction() {
if (!this.showPipelineEditorButton) {

View File

@ -106,10 +106,10 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
def skip
if two_factor_grace_period_expired?
redirect_to new_profile_two_factor_auth_path, alert: _('Cannot skip two factor authentication setup')
redirect_to profile_two_factor_auth_url, alert: _('Cannot skip two factor authentication setup')
else
session[:skip_two_factor] = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
redirect_to root_path
redirect_to root_url
end
end

View File

@ -54,7 +54,7 @@ module WebIdeButtonHelper
end
def gitpod_url
return "" unless Gitlab::CurrentSettings.gitpod_enabled
return "" unless Gitlab::CurrentSettings.gitpod_enabled && @ref
"#{Gitlab::CurrentSettings.gitpod_url}##{project_tree_url(@project, tree_join(@ref, @path || ''))}"
end

View File

@ -49,7 +49,7 @@ module Users
SQL
::Gitlab::Database::LoadBalancing::SessionMap
.current(connection.load_balancer).fallback_to_replicas_for_ambiguous_queries do
.current(load_balancer).fallback_to_replicas_for_ambiguous_queries do
connection.execute(sql).to_a
end
end

View File

@ -17,7 +17,8 @@
.project-clone-holder.gl-block.sm:gl-hidden
= render "shared/mobile_clone_panel"
.project-clone-holder.gl-hidden.sm:gl-flex.gl-justify-end.gl-w-full
.project-clone-holder.gl-hidden.sm:gl-flex.gl-justify-end.gl-w-full.gl-gap-3
= render 'shared/web_ide_button', blob: nil
= render "projects/buttons/code", ref: @ref
= render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5' }, body_options: { class: 'gl-bg-gray-10 gl-p-5 gl-rounded-base' }) do |c|

View File

@ -3,6 +3,6 @@
- page_title _("Edit"), @schedule.description, _("Pipeline Schedule")
%h1.page-title.gl-text-size-h-display
= _("Edit Pipeline Schedule")
= _("Edit Scheduled Pipeline")
#pipeline-schedules-form-edit{ data: js_pipeline_schedules_form_data(@project, @schedule) }

View File

@ -1,6 +1,8 @@
- return unless current_user && current_user.namespace
- type = blob ? 'blob' : 'tree'
- button_data = web_ide_button_data({ blob: blob })
- fork_options = fork_modal_options(@project, blob)
- css_classes = false unless local_assigns[:css_classes]
.gl-inline-block{ data: { options: button_data.merge(fork_options).to_json, web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg'), css_classes: css_classes }, id: "js-#{type}-web-ide-link" }
.gl-inline-block{ data: { options: button_data.merge(fork_options).to_json, web_ide_promo_popover_img: image_path('web-ide-promo-popover.svg'), css_classes: css_classes, default_branch: @project.default_branch_or_main }, id: "js-#{type}-web-ide-link" }

View File

@ -47,33 +47,73 @@
}
},
"additional_properties": {
"type": "object",
"properties": {
"label": {
"anyOf": [
{
"description": "Only base additional properties are provided",
"type": "object",
"properties": {
"description": {
"type": "string"
"label": {
"$ref": "#additional_prop"
},
"property": {
"$ref": "#additional_prop"
},
"value": {
"$ref": "#additional_prop"
}
},
"additionalProperties": {
"type": "null",
"x-error": "Either property/label or value must be used before defining other additional_properties"
}
},
{
"description": "All string-type base additional properties are provided, allowing custom properties",
"type": "object",
"properties": {
"label": {
"$ref": "#additional_prop"
},
"property": {
"$ref": "#additional_prop"
},
"value": {
"$ref": "#additional_prop"
}
},
"required": [
"description"
"property",
"label"
],
"additionalProperties": false
"additionalProperties": {
"$ref": "#additional_prop"
}
},
"property": {
{
"description": "All numeric-type base additional properties are provided, allowing custom properties",
"type": "object",
"properties": {
"description": {
"type": "string"
"label": {
"$ref": "#additional_prop"
},
"property": {
"$ref": "#additional_prop"
},
"value": {
"$ref": "#additional_prop"
}
},
"required": [
"description"
"value"
],
"additionalProperties": false
},
"value": {
"additionalProperties": {
"$ref": "#additional_prop"
}
}
],
"$defs": {
"additional_prop": {
"$anchor": "additional_prop",
"type": "object",
"properties": {
"description": {
@ -85,8 +125,7 @@
],
"additionalProperties": false
}
},
"additionalProperties": true
}
},
"iglu_schema_url": {
"type": [

View File

@ -1,9 +0,0 @@
---
name: use_load_balancing_session_map
feature_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/3834
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/168642
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/496505
milestone: '17.6'
group: group::scalability
type: gitlab_com_derisk
default_enabled: false

View File

@ -1,7 +1,11 @@
- title: "Self-managed certificate-based integration with Kubernetes"
announcement_milestone: "14.5"
removal_milestone: "18.0"
removal_milestone: "19.0"
breaking_change: true
impact: high
scope: [instance, group, project]
resolution_role: Maintainer
manual_task: true
body: |
The certificate-based integration with Kubernetes [will be deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/).

View File

@ -13,6 +13,7 @@
scope: project
resolution_role: Maintainer
manual_task: true
window: 1
body: | # (required) Don't change this line.
We introduces the OpenTofu CI/CD template in 16.8 as CI/CD components were not available for self-managed installations yet.
With the introduction of [GitLab CI/CD components for self-managed users](https://docs.gitlab.com/ee/ci/components/#use-a-gitlabcom-component-in-a-self-managed-instance)

View File

@ -9,6 +9,7 @@
scope: project
resolution_role: Developer
manual_task: true
window: 2
body: | # (required) Don't change this line.
The cloud native buildpack (CNB) builder image was updated to `heroku/builder:24` in the Auto DevOps Build project. While we don't expect the changes to be disruptive for the most part, this might be a breaking change for some users of Auto DevOps, and especially users of Auto Build. To better understand the impact of you workloads, review the following:

View File

@ -8,7 +8,6 @@
# and a link to the deprecation issue
reporter: dhershkovitch
stage: verify
window: "2"
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/424417
body: | # (required) Don't change this line.
The `previousStageJobsOrNeeds` field in GraphQL will be removed as it has been replaced by the `previousStageJobs` and `needs` fields.

View File

@ -8,7 +8,6 @@
# and a link to the deprecation issue
reporter: joshlambert
stage: systems
window: "1"
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/480914
impact: low # Can be one of: [critical, high, medium, low]
scope: instance # Can be one or a combination of: [instance, group, project]

View File

@ -7,7 +7,6 @@
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/472213
impact: low
scope: instance
window: "3"
resolution_role: Maintainer
manual_task: true
body: |

View File

@ -26,9 +26,8 @@
announcement_milestone: "XX.YY"
# Change breaking_change to false if needed.
breaking_change: true
# The stage and GitLab username of the person reporting the change,
# and a link to the deprecation issue
reporter: exampleuser
window: # Can be [1, 2, or 3] - The window when the breaking change will be deployed on GitLab.com
reporter: exampleuser # The GitLab username of the person reporting the change
stage: stage
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/000000
# Use the impact calculator https://gitlab-com.gitlab.io/gl-infra/breaking-change-impact-calculator/?
@ -36,7 +35,6 @@
scope: # Can be one or a combination of: [instance, group, project]
resolution_role: # Can be one of: [Admin, Owner, Maintainer, Developer]
manual_task: # Can be true or false. Use this to denote whether a resolution action must be performed manually (true), or if it can be automated by using the API or other automation (false).
window: # Can be "1", "2" or "3"
body: | # (required) Don't change this line.
<!-- START OF BODY COMMENT

View File

@ -5,4 +5,4 @@ feature_category: team_planning
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/167972
milestone: '17.5'
queued_migration_version: 20241002185804
finalized_by: # version of the migration that finalized this BBM
finalized_by: 20241030165330

View File

@ -7,5 +7,4 @@ feature_categories:
description: https://docs.gitlab.com/ee/user/project/deploy_tokens/
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/db18993f652425b72c4b854e18a002e0ec44b196
milestone: '10.7'
gitlab_schema: gitlab_main
sharding_key_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/477395
gitlab_schema: gitlab_main_clusterwide

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AddSoftwareLicenseIndexesToNameColumns < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.6'
CUSTOM_SOFTWARE_LICENSES_INDEX_NAME = 'idx_custom_software_licenses_lower_name'
SOFTWARE_LICENSES_INDEX_NAME = 'idx_software_licenses_lower_name'
def up
add_concurrent_index :custom_software_licenses, 'LOWER(name)', name: CUSTOM_SOFTWARE_LICENSES_INDEX_NAME
add_concurrent_index :software_licenses, 'LOWER(name)', name: SOFTWARE_LICENSES_INDEX_NAME
end
def down
remove_concurrent_index_by_name :custom_software_licenses, CUSTOM_SOFTWARE_LICENSES_INDEX_NAME
remove_concurrent_index_by_name :software_licenses, SOFTWARE_LICENSES_INDEX_NAME
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class FinalizeBackfillIssuesCorrectWorkItemTypeId < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
milestone '17.6'
MIGRATION = "BackfillIssuesCorrectWorkItemTypeId"
def up
ensure_batched_background_migration_is_finished(
job_class_name: MIGRATION,
table_name: :issues,
column_name: :id,
job_arguments: [],
finalize: true
)
end
def down
# no-op
end
end

View File

@ -0,0 +1 @@
eb07013a603f182a6c7ddb51a3bd6da91d655a1fff83791fbd978b4c09520a2c

View File

@ -0,0 +1 @@
cc3ef05bcf103ea2e3a69a450eb71be8680fd6d4aa9d6538276667003eadd24b

View File

@ -27948,6 +27948,8 @@ CREATE UNIQUE INDEX idx_custom_field_select_options_on_custom_field_id_lower_val
CREATE UNIQUE INDEX idx_custom_fields_on_namespace_id_and_lower_name ON custom_fields USING btree (namespace_id, lower(name));
CREATE INDEX idx_custom_software_licenses_lower_name ON custom_software_licenses USING btree (lower(name));
CREATE INDEX idx_deletions_on_project_id_and_id_where_pending ON ONLY p_batched_git_ref_updates_deletions USING btree (project_id, id) WHERE (status = 1);
CREATE INDEX idx_dep_proxy_pkgs_settings_enabled_maven_on_project_id ON dependency_proxy_packages_settings USING btree (project_id) WHERE ((enabled = true) AND (maven_external_registry_url IS NOT NULL));
@ -28178,6 +28180,8 @@ CREATE UNIQUE INDEX idx_software_license_policies_unique_on_custom_license_proje
CREATE UNIQUE INDEX idx_software_license_policies_unique_on_project_and_scan_policy ON software_license_policies USING btree (project_id, software_license_id, scan_result_policy_id);
CREATE INDEX idx_software_licenses_lower_name ON software_licenses USING btree (lower((name)::text));
CREATE INDEX idx_status_check_responses_on_id_and_status ON status_check_responses USING btree (id, status);
CREATE INDEX idx_streaming_group_namespace_filters_on_namespace_id ON audit_events_streaming_group_namespace_filters USING btree (namespace_id);

View File

@ -0,0 +1,111 @@
---
stage: AI-Powered
group: Custom Models
description: Get started with self-hosted AI models.
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Self-hosted model configuration and authentication
DETAILS:
**Tier:** Ultimate with GitLab Duo Enterprise - [Start a trial](https://about.gitlab.com/solutions/gitlab-duo-pro/sales/?type=free-trial)
**Offering:** Self-managed
**Status:** Beta
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/12972) in GitLab 17.1 [with a flag](../../administration/feature_flags.md) named `ai_custom_model`. Disabled by default.
> - [Enabled on self-managed](https://gitlab.com/groups/gitlab-org/-/epics/15176) in GitLab 17.6.
> - Changed to require GitLab Duo add-on in GitLab 17.6 and later.
There are two configuration options for self-managed customers:
- **GitLab.com AI Gateway**: Use the GitLab-managed AI Gateway with default external
large language model (LLM) providers (for example, Google Vertex or Anthropic).
- **Self-hosted AI Gateway**: Deploy and manage your own AI Gateway and language models in your infrastructure,
without depending on GitLab-provided external language providers.
## GitLab.com AI Gateway
In this configuration, your GitLab instance depends on and sends requests to the external GitLab AI Gateway, which communicates with external AI vendors such as Google Vertex or Anthropic. The response is then forwarded back to your GitLab instance.
```mermaid
%%{init: { "theme": "default", "fontFamily": "GitLab Sans", "sequence": { "actorFontSize": 12, "participantFontSize": 12, "messageFontSize": 12 } }}%%
sequenceDiagram
actor User as User
participant SelfHostedGitLab as Self-hosted GitLab (Your Instance)
participant GitLabAIGateway as GitLab AI Gateway (External)
participant GitLabAIVendor as GitLab AI Vendor (External)
User ->> SelfHostedGitLab: Send request
SelfHostedGitLab ->> SelfHostedGitLab: Check if self-hosted model is configured
SelfHostedGitLab ->> GitLabAIGateway: Forward request for AI processing
GitLabAIGateway ->> GitLabAIVendor: Create prompt and send request to AI model server
GitLabAIVendor -->> GitLabAIGateway: Respond to the prompt
GitLabAIGateway -->> SelfHostedGitLab: Forward AI response
SelfHostedGitLab -->> User: Forward AI response
```
## Self-hosted AI Gateway
In this configuration, the entire system is isolated within the enterprise, ensuring a fully self-hosted environment that safeguards data privacy.
```mermaid
%%{init: { "theme": "default", "fontFamily": "GitLab Sans", "sequence": { "actorFontSize": 12, "participantFontSize": 12, "messageFontSize": 12 } }}%%
sequenceDiagram
actor User as User
participant SelfHostedGitLab as Self-hosted GitLab
participant SelfHostedAIGateway as Self-hosted AI Gateway
participant SelfHostedModel as Self-hosted model
User ->> SelfHostedGitLab: Send request
SelfHostedGitLab ->> SelfHostedGitLab: Check if self-hosted model is configured
SelfHostedAIGateway ->> SelfHostedModel: Create prompt and perform request to AI model server
SelfHostedGitLab ->> SelfHostedAIGateway: Forward request for AI processing
SelfHostedModel -->> SelfHostedAIGateway: Respond to the prompt
SelfHostedAIGateway -->> SelfHostedGitLab: Forward AI response
SelfHostedGitLab -->> User: Forward AI response
```
For more information, see the [self-hosted model deployment blueprint](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/custom_models/).
## Authentication for self-hosted models
The authentication process for self-hosted models is secure, efficient, and made up of the following key components:
- **Self-issued tokens**: In this architecture, access credentials are not synchronized with `cloud.gitlab.com`. Instead, tokens are self-issued dynamically, similar to the functionality on GitLab.com. This method provides users with immediate access while maintaining a high level of security.
- **Offline environments**: In offline setups, there are no connections to `cloud.gitlab.com`. All requests are routed exclusively to the self-hosted AI Gateway.
- **Token minting and verification**: The GitLab self-managed instance mints the token, which is then verified by the AI Gateway against the GitLab instance.
- **Model configuration and security**: When an administrator configures a model, they can incorporate an API key to authenticate requests. Additionally, you can enhance security by specifying connection IP addresses within your network, ensuring that only trusted IPs can interact with the model.
As illustrated in the following diagram:
1. The authentication flow begins when the user configures the model through the GitLab instance and submits a request to access the GitLab Duo feature.
1. The GitLab instance mints an access token, which the user forwards to GitLab and then to the AI Gateway for verification.
1. Upon confirming the token's validity, the AI Gateway sends a request to the AI model, which uses the API key to authenticate the request and process it.
1. The results are then relayed back to the GitLab instance, completing the flow by sending the response to the user, which is designed to be secure and efficient.
```mermaid
%%{init: { "theme": "default", "fontFamily": "GitLab Sans", "sequence": { "actorFontSize": 12, "participantFontSize": 12, "messageFontSize": 12 } }}%%
sequenceDiagram
participant User as User
participant GitLab as GitLab Instance
participant AI Gateway as AI Gateway
participant AIModel as AI Model
User->>GitLab: Configure Model
User->>GitLab: Request Access
GitLab->>GitLab: Mint Token
GitLab->>User: Send Token
User->>GitLab: Forward Minted Token
GitLab->>AI Gateway: Verify Token
AI Gateway->>GitLab: Token Validated
GitLab->>AI Gateway: Send Request to Model
AI Gateway->>AIModel: Send Request to Model
AIModel->>AIModel: Authenticate using API Key
AIModel->>AI Gateway: Process Request
AI Gateway->>GitLab: Send Result to GitLab
GitLab->>User: Send Response
```

View File

@ -18,7 +18,7 @@ DETAILS:
To configure your GitLab instance to access the available self-hosted models in your infrastructure:
1. Use a [locally hosted or GitLab.com AI Gateway](index.md#self-managed-customer-configuration-types).
1. Use a [locally hosted or GitLab.com AI Gateway](index.md#choose-a-configuration-type).
1. Configure your GitLab instance.
1. Configure the self-hosted model.
1. Configure the GitLab Duo features to use your self-hosted model.

View File

@ -34,109 +34,30 @@ This setup ensures enterprise-level privacy and flexibility, allowing seamless i
### Prerequisites
The following are required:
Before setting up a self-hosted model infrastructure, you must have:
- A [supported model](supported_models_and_hardware_requirements.md) (either cloud-based or on-premises).
- A [supported serving platform](supported_llm_serving_platforms.md) (either cloud-based or on-premises).
- A locally hosted or GitLab.com AI Gateway.
- GitLab [Enterprise Edition license](../../administration/license.md).
## Self-managed customer configuration types
## Choose a configuration type
There are two configuration options for self-managed customers:
- **GitLab.com AI Gateway customers**: Use the GitLab-hosted AI Gateway with external LLM providers (for example, Google Vertex or Anthropic).
- **Self-hosted AI Gateway customers**: Deploy your own AI Gateway and LLMs within your infrastructure, without relying on external public services.
- [**GitLab.com AI Gateway**](configuration_types.md#gitlabcom-ai-gateway):
Use the GitLab-hosted AI Gateway with external
LLM providers (for example, Google Vertex or Anthropic).
- [**Self-hosted AI Gateway**](configuration_types.md#self-hosted-ai-gateway):
Deploy your own AI Gateway and LLMs within
your infrastructure, without relying on external public services.
### Fully self-hosted architecture
In this configuration, the entire system is isolated within the enterprise, ensuring a fully self-hosted environment that safeguards data privacy.
```mermaid
%%{init: { "theme": "default", "fontFamily": "GitLab Sans", "sequence": { "actorFontSize": 12, "participantFontSize": 12, "messageFontSize": 12 } }}%%
sequenceDiagram
actor User as User
participant SelfHostedGitLab as Self-hosted GitLab
participant SelfHostedAIGateway as Self-hosted AI Gateway
participant SelfHostedModel as Self-hosted model
User ->> SelfHostedGitLab: Send request
SelfHostedGitLab ->> SelfHostedGitLab: Check if self-hosted model is configured
SelfHostedGitLab ->> SelfHostedAIGateway: Forward request for AI processing
SelfHostedAIGateway ->> SelfHostedModel: Create prompt and perform request to AI model server
SelfHostedModel -->> SelfHostedAIGateway: Respond to the prompt
SelfHostedAIGateway -->> SelfHostedGitLab: Forward AI response
SelfHostedGitLab -->> User: Forward AI response
```
### GitLab AI vendor architecture
In this configuration, your GitLab instance depends on and sends requests to the external GitLab AI Gateway, which communicates with external AI vendors such as Google Vertex or Anthropic. The response is then forwarded back to your GitLab instance.
```mermaid
%%{init: { "theme": "default", "fontFamily": "GitLab Sans", "sequence": { "actorFontSize": 12, "participantFontSize": 12, "messageFontSize": 12 } }}%%
sequenceDiagram
actor User as User
participant SelfHostedGitLab as Self-hosted GitLab (Your Instance)
participant GitLabAIGateway as GitLab AI Gateway (External)
participant GitLabAIVendor as GitLab AI Vendor (External)
User ->> SelfHostedGitLab: Send request
SelfHostedGitLab ->> SelfHostedGitLab: Check if self-hosted model is configured
SelfHostedGitLab ->> GitLabAIGateway: Forward request for AI processing
GitLabAIGateway ->> GitLabAIVendor: Create prompt and send request to AI model server
GitLabAIVendor -->> GitLabAIGateway: Respond to the prompt
GitLabAIGateway -->> SelfHostedGitLab: Forward AI response
SelfHostedGitLab -->> User: Forward AI response
```
For more details, see the [Blueprint](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/custom_models/).
## Authentication for self-hosted models
The authentication process for self-hosted models is designed to be secure and efficient, comprising the following key components:
- **Self-issued tokens**: In this architecture, access credentials are not synchronized with `cloud.gitlab.com`. Instead, tokens are self-issued dynamically, similar to the functionality on GitLab.com. This method provides users with immediate access while maintaining a high level of security.
- **Offline environments**: In offline setups, there are no connections to `cloud.gitlab.com`. All requests are routed exclusively to the self-hosted AI Gateway.
- **Token minting and verification**: The GitLab self-managed instance mints the token, which is then verified by the AI Gateway against the GitLab instance.
- **Model configuration and security**: When an administrator configures a model, they can incorporate an API key to authenticate requests. Additionally, you can enhance security by specifying connection IP addresses within your network, ensuring that only trusted IPs can interact with the model.
As illustrated in the following diagram:
1. The authentication flow begins when the user configures the model through the GitLab instance and submits a request to access the GitLab Duo feature.
1. The GitLab instance mints an access token, which the user forwards to GitLab and then to the AI Gateway for verification.
1. Upon confirming the token's validity, the AI Gateway sends a request to the AI model, which uses the API key to authenticate the request and process it.
1. The results are then relayed back to the GitLab instance, completing the flow by sending the response to the user, which is designed to be secure and efficient.
```mermaid
%%{ init : { "theme" : "default", "themeVariables": { "actorBackground": "#ffffff", "actorBorder": "#34495e", "actorTextColor": "#34495e", "participantBackground": "#e0f7fa", "participantBorder": "#00796b", "participantTextColor": "#00796b", "sequenceNumberColor": "#00796b", "noteTextColor": "#34495e" } } }%%
sequenceDiagram
participant User as User
participant GitLab as GitLab Instance
participant AI Gateway as AI Gateway
participant AIModel as AI Model
User->>GitLab: Configure Model
User->>GitLab: Request Access
GitLab->>GitLab: Mint Token
GitLab->>User: Send Token
User->>GitLab: Forward Minted Token
GitLab->>AI Gateway: Verify Token
AI Gateway->>GitLab: Token Validated
GitLab->>AI Gateway: Send Request to Model
AI Gateway->>AIModel: Send Request to Model
AIModel->>AIModel: Authenticate using API Key
AIModel->>AI Gateway: Process Request
AI Gateway->>GitLab: Send Result to GitLab
GitLab->>User: Send Response
```
Before setting up a self-hosted model infrastructure, you must decide which
configuration type to implement.
## Set up a self-hosted infrastructure
To establish a fully isolated self-hosted infrastructure:
To set up a fully isolated self-hosted model infrastructure:
1. **Install a Large Language Model (LLM) Serving Infrastructure**
@ -155,9 +76,5 @@ To establish a fully isolated self-hosted infrastructure:
## Related topics
- AWS Bedrock
- [Import Custom Models Into Amazon Bedrock](https://www.youtube.com/watch?v=CA2AXfWWdpA)
## Troubleshooting
To begin troubleshooting, run the debugging scripts to verify your self-hosted model setup. For further guidance on other actions you can take, see the [troubleshooting documentation](troubleshooting.md).
- [Import custom models into Amazon Bedrock](https://www.youtube.com/watch?v=CA2AXfWWdpA)
- [Troubleshooting](troubleshooting.md)

View File

@ -100,6 +100,32 @@ Related Handbook pages:
- <https://handbook.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes>
- <https://handbook.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-doc>
## Update the breaking change windows documentation
The [breaking change windows](../../update/breaking_windows.md)
documentation is generated based on the `window` value in the YAML files located in
[`gitlab/data/deprecations`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/data/deprecations).
To update the breaking change windows page when a YAML file is added,
edited, or removed:
1. From the command line, go to your local clone of the [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab) project.
1. Create, edit, or remove the YAML file under [`data/deprecations`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/data/deprecations).
1. Compile the breaking change windows documentation:
```shell
bin/rake gitlab:docs:compile_windows
```
1. If needed, you can verify the documentation is up to date with:
```shell
bin/rake gitlab:docs:check_windows
```
1. Commit the updated documentation and push the changes.
1. Create a merge request.
## Update the related documentation
When features are deprecated and removed, [update the related documentation](../documentation/styleguide/deprecations_and_removals.md).

View File

@ -43,7 +43,8 @@ that are coded across multiple repositories.
|---|---|---|
| [All feature flags in GitLab](../../../user/feature_flags.md) | [Generated during docs build](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/doc/raketasks.md#generate-the-feature-flag-tables) | [Technical Writing](https://handbook.gitlab.com/handbook/product/ux/technical-writing/) |
| [GitLab Runner feature flags](https://docs.gitlab.com/runner/configuration/feature-flags.html) | [Page source](https://gitlab.com/gitlab-org/gitlab-runner/-/blob/ec6e1797d2173a95c8ac7f726bd62f6f110b7211/docs/configuration/feature-flags.md?plain=1#L39) | [Runner](https://handbook.gitlab.com/handbook/engineering/development/ops/verify/runner/) |
| [Deprecations and removals by version](../../../update/deprecations.md) | [Deprecating GitLab features](../../deprecation_guidelines/index.md) | |
| [Deprecations and removals by version](../../../update/deprecations.md) | [Update the deprecations and removals documentation](../../deprecation_guidelines/index.md#update-the-deprecations-and-removals-documentation) | |
| [Breaking change windows](../../../update/breaking_windows.md) | [Update the breaking change windows documentation](../../deprecation_guidelines/index.md#update-the-breaking-change-windows-documentation) | |
| [GraphQL API resources](../../../api/graphql/reference/index.md) | [GraphQL API style guide](../../api_graphql_styleguide.md#documentation-and-schema) | [Import and Integrate](https://handbook.gitlab.com/handbook/engineering/development/dev/foundations/import-and-integrate/) |
| [Audit event types](../../../user/compliance/audit_event_types.md) | [Audit event development guidelines](../../audit_event_guide/index.md) | [Compliance](https://handbook.gitlab.com/handbook/engineering/development/sec/govern/compliance/) |
| [Available custom role permissions](../../../user/custom_roles/abilities.md) | [Generated by Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/master/tooling/custom_roles/docs/templates/custom_abilities.md.erb) | [Authorization](https://handbook.gitlab.com/handbook/product/categories/#authorization-group)|

View File

@ -305,8 +305,11 @@ and is not affected by the current search.
## Add seats to subscription
Your subscription cost is based on the maximum number of seats you use during the billing period.
Even if you reach the number of seats in your subscription, you can continue to add users.
GitLab [bills you for the overage](../quarterly_reconciliation.md).
- If [restricted access](../../administration/settings/sign_up_restrictions.md#turn-on-restricted-access)
is turned on, when there are no seats left in your subscription you must purchase more seats for groups to add new billable users.
- If restricted access is turned off, when there are no seats left in your subscription groups can continue to add billable
users. GitLab [bills you for the overage](../quarterly_reconciliation.md).
To add seats to a subscription:

View File

@ -25,7 +25,6 @@ This window takes place on April 21 - 23, 2025 from 09:00 UTC to 22:00 UTC.
| Deprecation | Impact | Stage | Scope |
|-------------|--------|-------|-------|
| [Rate limits for common User, Project, and Group API endpoints](https://gitlab.com/gitlab-org/gitlab/-/issues/480914) | Low | Systems | Instance |
## Window 2
@ -33,7 +32,6 @@ This window takes place on April 28 - 30, 2025 from 09:00 UTC to 22:00 UTC.
| Deprecation | Impact | Stage | Scope |
|-------------|--------|-------|-------|
| [Remove `previousStageJobsOrNeeds` from GraphQL](https://gitlab.com/gitlab-org/gitlab/-/issues/424417) | | Verify | |
## Window 3
@ -41,4 +39,3 @@ This window takes place on May 5 - 7, 2025 from 09:00 UTC to 22:00 UTC.
| Deprecation | Impact | Stage | Scope |
|-------------|--------|-------|-------|
| [Limited `scan` actions in a scan execution policy](https://gitlab.com/gitlab-org/gitlab/-/issues/472213) | Low | Govern | Instance |

View File

@ -99,6 +99,34 @@ Before upgrading to GitLab 19.0, please ensure you have [migrated](https://docs.
<div class="deprecation breaking-change" data-milestone="19.0">
### Self-managed certificate-based integration with Kubernetes
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">14.5</span>
- Removal in GitLab <span class="milestone">19.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/groups/gitlab-org/configure/-/epics/8).
</div>
The certificate-based integration with Kubernetes [will be deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/).
As a self-managed customer, we are introducing the [feature flag](https://docs.gitlab.com/ee/administration/feature_flags.html#enable-or-disable-the-feature) `certificate_based_clusters` in GitLab 15.0 so you can keep your certificate-based integration enabled. However, the feature flag will be disabled by default, so this change is a **breaking change**.
In GitLab 18.0 we will remove both the feature and its related code. Until the final removal in 18.0, features built on this integration will continue to work, if you enable the feature flag. Until the feature is removed, GitLab will continue to fix security and critical issues as they arise.
For a more robust, secure, forthcoming, and reliable integration with Kubernetes, we recommend you use the
[agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html)
Although an explicit removal date is set, we don't plan to remove this feature until the new solution has feature parity.
For more information about the blockers to removal, see [this issue](https://gitlab.com/gitlab-org/configure/general/-/issues/199).
For updates and details about this deprecation, follow [this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8).
</div>
<div class="deprecation breaking-change" data-milestone="19.0">
### Single database connection is deprecated
<div class="deprecation-notes">
@ -768,34 +796,6 @@ Occurrences of the `active` identifier in the GitLab GraphQL API endpoints will
<div class="deprecation breaking-change" data-milestone="18.0">
### Self-managed certificate-based integration with Kubernetes
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">14.5</span>
- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/groups/gitlab-org/configure/-/epics/8).
</div>
The certificate-based integration with Kubernetes [will be deprecated and removed](https://about.gitlab.com/blog/2021/11/15/deprecating-the-cert-based-kubernetes-integration/).
As a self-managed customer, we are introducing the [feature flag](https://docs.gitlab.com/ee/administration/feature_flags.html#enable-or-disable-the-feature) `certificate_based_clusters` in GitLab 15.0 so you can keep your certificate-based integration enabled. However, the feature flag will be disabled by default, so this change is a **breaking change**.
In GitLab 18.0 we will remove both the feature and its related code. Until the final removal in 18.0, features built on this integration will continue to work, if you enable the feature flag. Until the feature is removed, GitLab will continue to fix security and critical issues as they arise.
For a more robust, secure, forthcoming, and reliable integration with Kubernetes, we recommend you use the
[agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html)
Although an explicit removal date is set, we don't plan to remove this feature until the new solution has feature parity.
For more information about the blockers to removal, see [this issue](https://gitlab.com/gitlab-org/configure/general/-/issues/199).
For updates and details about this deprecation, follow [this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8).
</div>
<div class="deprecation breaking-change" data-milestone="18.0">
### Slack notifications integration
<div class="deprecation-notes">

View File

@ -141,6 +141,18 @@ see [Packaged PostgreSQL deployed in an HA/Geo Cluster](https://docs.gitlab.com/
| 17.1 | All | None |
| 17.2 | All | None |
- Geo replication details for secondary sites appear to be empty even if Geo replication is working. See [issue 468509](https://gitlab.com/gitlab-org/gitlab/-/issues/468509). There is no known workaround. The bug is fixed in GitLab 17.4.
**Affected releases**:
| Affected minor releases | Affected patch releases | Fixed in |
| ----------------------- | ----------------------- | -------- |
| 16.11 | 16.11.5 - 16.11.10 | None |
| 17.0 | All | 17.0.7 |
| 17.1 | All | 17.1.7 |
| 17.2 | All | 17.2.5 |
| 17.3 | All | 17.3.1 |
## 16.10.0
You might encounter the following error while upgrading to GitLab 16.10 or later:

View File

@ -263,6 +263,7 @@ The OpenSSL 3 upgrade has been postponed to GitLab 17.7.0.
| Affected minor releases | Affected patch releases | Fixed in |
| ----------------------- | ----------------------- | -------- |
| 16.11 | 16.11.5 - 16.11.10 | None |
| 17.0 | All | 17.0.7 |
| 17.1 | All | 17.1.7 |
| 17.2 | All | 17.2.5 |
@ -322,6 +323,7 @@ The OpenSSL 3 upgrade has been postponed to GitLab 17.7.0.
| Affected minor releases | Affected patch releases | Fixed in |
| ----------------------- | ----------------------- | -------- |
| 16.11 | 16.11.5 - 16.11.10 | None |
| 17.0 | All | 17.0.7 |
| 17.1 | All | 17.1.7 |
| 17.2 | All | 17.2.5 |
@ -359,6 +361,7 @@ The OpenSSL 3 upgrade has been postponed to GitLab 17.7.0.
| Affected minor releases | Affected patch releases | Fixed in |
| ----------------------- | ----------------------- | -------- |
| 16.11 | 16.11.5 - 16.11.10 | None |
| 17.0 | All | 17.0.7 |
| 17.1 | All | 17.1.7 |
| 17.2 | All | 17.2.5 |
@ -385,6 +388,7 @@ The OpenSSL 3 upgrade has been postponed to GitLab 17.7.0.
| Affected minor releases | Affected patch releases | Fixed in |
| ----------------------- | ----------------------- | -------- |
| 16.11 | 16.11.5 - 16.11.10 | None |
| 17.0 | All | 17.0.7 |
| 17.1 | All | 17.1.7 |
| 17.2 | All | 17.2.5 |

View File

@ -20,17 +20,25 @@ To minimize the risk of exposing your secrets, always store secrets outside of t
repositories. After a sensitive value is pushed to a remote
repository, anyone with access to the repository can use the secret to
impersonate the authorized user.
Secret detection monitors your activity to help prevent your secrets
from being exposed. GitLab has three methods for detecting secrets, which
you can use simultaneously:
- The [pipeline](pipeline/index.md) method detects secrets during the project's CI/CD pipeline.
Pipeline secret detection works with all text files, regardless of language or framework.
This method cannot reject pushes.
- The [secret push protection](secret_push_protection/index.md) method detects secrets when users push changes to the
remote Git branch. This method can reject pushes if a secret is detected.
- The [client-side](client/index.md) method runs in your browser, and warns you if the content of text you're about
to post contains a potential secret.
Secret detection monitors your activity to both:
- Help prevent your secrets from being leaked.
- Help you respond if a secret is leaked.
You should take a multi-layered security approach and enable all available secret detection methods:
- [Secret push protection](secret_push_protection/index.md) scans commits for secrets when you
push changes to GitLab. The push is blocked if secrets are detected, unless you skip secret push protection.
This method reduces the risk of secrets being leaked.
- [Pipeline secret detection](pipeline/index.md) runs as part of a project's CI/CD pipeline. Commits
to the repository's default branch are scanned for secrets. If pipeline secret detection is
enabled in merge request pipelines, commits to the development branch are scanned for secrets,
enabling you to respond before they're committed to the default branch.
- [Client-side secret detection](client/index.md) scans descriptions and comments in both issues and
merge requests for secrets before they're saved to GitLab. When a secret is detected you can
choose to edit the input and remove the secret or, if it's a false positive, save the description
or comment.
If a secret is committed to a repository, GitLab records the exposure
in the Vulnerability Report. For some secret types, GitLab can even

View File

@ -9,20 +9,6 @@ module Gitlab
# has been completed. Sessions can be used to keep track of what hosts
# should be used for queries.
class Session
CACHE_KEY = :gitlab_load_balancer_session
def self.current
RequestStore[CACHE_KEY] ||= new
end
def self.clear_session
RequestStore.delete(CACHE_KEY)
end
def self.without_sticky_writes(&block)
current.ignore_writes(&block)
end
def initialize
@use_primary = false
@performed_write = false

View File

@ -10,45 +10,24 @@ module Gitlab
# lb - Gitlab::Database::LoadBalancing::LoadBalancer instance
def self.current(load_balancer)
return Session.current unless use_session_map?
cached_instance.lookup(load_balancer)
end
# models - Array<ActiveRecord::Base>
def self.with_sessions(models)
return Session.current unless use_session_map?
dbs = models.map { |m| m.load_balancer.name }.uniq
dbs.each { |db| cached_instance.validate_db_name(db) }
ScopedSessions.new(dbs, cached_instance.session_map)
end
def self.clear_session
return Session.clear_session unless use_session_map?
RequestStore.delete(CACHE_KEY)
end
def self.without_sticky_writes(&)
return Session.without_sticky_writes(&) unless use_session_map?
with_sessions(Gitlab::Database::LoadBalancing.base_models).ignore_writes(&)
end
def self.use_session_map?
::Feature.enabled?(:use_load_balancing_session_map, :current_request, type: :gitlab_com_derisk)
rescue ActiveRecord::StatementInvalid,
Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError
# If the feature_gates table is missing, we should default to a false.
# In a migration scope, we also rescue and default to false.
false
rescue StandardError => e
::Gitlab::ErrorTracking.track_exception(e)
false
end
private_class_method :use_session_map?
def self.cached_instance
RequestStore[CACHE_KEY] ||= new
end

View File

@ -10,7 +10,7 @@ module Gitlab
def self.for_tables(tables)
Gitlab::Database::LoadBalancing::SessionMap
.current(connection.load_balancer)
.current(load_balancer)
.use_primary do
# calling `.to_a` here to execute the query in the primary's scope
# and to avoid having the scope chained and re-executed

View File

@ -541,7 +541,8 @@ module Gitlab
h[k] = {
signature: +''.b,
signed_text: +''.b,
signer: :SIGNER_UNSPECIFIED
signer: :SIGNER_UNSPECIFIED,
author_email: +''.b
}
end
@ -552,6 +553,7 @@ module Gitlab
signatures[current_commit_id][:signature] << message.signature
signatures[current_commit_id][:signed_text] << message.signed_text
signatures[current_commit_id][:author_email] << message.author.email if message.author.present?
# The actual value is send once. All the other chunks send SIGNER_UNSPECIFIED
signatures[current_commit_id][:signer] = message.signer unless message.signer == :SIGNER_UNSPECIFIED

View File

@ -5,7 +5,6 @@ module Gitlab
class EventDefinitionValidator
EVENT_SCHEMA_PATH = Rails.root.join('config/events/schema.json')
SCHEMA = ::JSONSchemer.schema(EVENT_SCHEMA_PATH)
NOT_VALIDATED_PROPERTIES = [:value].freeze
def initialize(definition)
@attributes = definition.attributes
@ -13,37 +12,6 @@ module Gitlab
end
def validation_errors
(validate_schema << validate_additional_properties).compact
end
private
attr_reader :attributes, :path
def validate_additional_properties
additional_props = attributes[:additional_properties]&.map { |k, _| k }
return unless additional_props.present?
extra_props = additional_props - Gitlab::Tracking::EventValidator::BASE_ADDITIONAL_PROPERTIES.keys
unused_props = prioritized_properties - additional_props
return unless extra_props.present? && unused_props.present?
<<~ERROR_MSG
--------------- VALIDATION ERROR ---------------
Definition file: #{path}
Error type: consider using the built-in additional properties:
"#{prioritized_properties.join(', ')}"
before adding custom extra properties: #{extra_props.join(', ')}
ERROR_MSG
end
def prioritized_properties
Gitlab::Tracking::EventValidator::BASE_ADDITIONAL_PROPERTIES.keys - NOT_VALIDATED_PROPERTIES
end
def validate_schema
SCHEMA.validate(attributes.deep_stringify_keys).map do |error|
<<~ERROR_MSG
--------------- VALIDATION ERROR ---------------
@ -51,10 +19,14 @@ module Gitlab
Error type: #{error['type']}
Data: #{error['data']}
Path: #{error['data_pointer']}
Details: #{error['details']}
Details: #{error['details'] || error['error']}
ERROR_MSG
end
end
private
attr_reader :attributes, :path
end
end
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true
OUTPUT_FILE = 'doc/update/breaking_window.md'
OUTPUT_FILE = 'doc/update/breaking_windows.md'
DEPRECATIONS_PATH = 'data/deprecations'
TARGET_MILESTONE = '18.0'
@ -37,7 +37,7 @@ def write_metadata(file)
stage: none
group: none
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
noindex: false
noindex: true
---
# Breaking change deployments on GitLab.com

View File

@ -20656,10 +20656,10 @@ msgstr ""
msgid "Edit Password"
msgstr ""
msgid "Edit Pipeline Schedule"
msgid "Edit Release"
msgstr ""
msgid "Edit Release"
msgid "Edit Scheduled Pipeline"
msgstr ""
msgid "Edit Slack integration"
@ -40193,7 +40193,7 @@ msgstr ""
msgid "PipelineSchedules|An error occurred while updating the pipeline schedule."
msgstr ""
msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
msgid "PipelineSchedules|Are you sure you want to delete this scheduled pipeline?"
msgstr ""
msgid "PipelineSchedules|Can have custom CI/CD variables."
@ -40208,13 +40208,13 @@ msgstr ""
msgid "PipelineSchedules|Cron timezone"
msgstr ""
msgid "PipelineSchedules|Delete pipeline schedule"
msgid "PipelineSchedules|Delete scheduled pipeline"
msgstr ""
msgid "PipelineSchedules|Description"
msgstr ""
msgid "PipelineSchedules|Edit pipeline schedule"
msgid "PipelineSchedules|Edit scheduled pipeline"
msgstr ""
msgid "PipelineSchedules|Explore plan limits"
@ -40262,7 +40262,7 @@ msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgid "PipelineSchedules|Run scheduled pipeline"
msgstr ""
msgid "PipelineSchedules|Runs for a specific branch or tag."

View File

@ -1,4 +1,4 @@
ARG GDK_SHA=f14f8f3445959818c1272a9767fefa3b282f59c2
ARG GDK_SHA=4d74dc68619bb2f81fb22216fa9ca5d3b15b67bc
# Use tag prefix when running on 'stable' branch to make sure 'protected' image is used which is not deleted by registry cleanup
ARG GDK_BASE_TAG_PREFIX

View File

@ -204,8 +204,6 @@ spec/frontend/ci/catalog/components/ci_catalog_home_spec.js
spec/frontend/ci/catalog/components/list/ci_resources_list_item_spec.js
spec/frontend/ci/catalog/components/pages/ci_resource_details_page_spec.js
spec/frontend/ci/catalog/index_spec.js
spec/frontend/ci/ci_variable_list/components/ci_variable_drawer_spec.js
spec/frontend/ci/ci_variable_list/components/ci_variable_shared_spec.js
spec/frontend/ci/job_details/components/log/line_header_spec.js
spec/frontend/ci/job_details/components/log/line_spec.js
spec/frontend/ci/job_details/components/log/log_spec.js
@ -426,7 +424,6 @@ spec/frontend/usage_quotas/storage/components/namespace_storage_app_spec.js
spec/frontend/users_select/index_spec.js
spec/frontend/vue_alerts_spec.js
spec/frontend/vue_merge_request_widget/components/checks/conflicts_spec.js
spec/frontend/vue_merge_request_widget/components/merge_checks_spec.js
spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
spec/frontend/vue_merge_request_widget/components/states/mr_widget_merging_spec.js

View File

@ -489,4 +489,31 @@ RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :system_acc
it_behaves_like 'user must enter a valid current password'
end
describe 'PATCH skip' do
let(:user) { create(:user, otp_grace_period_started_at: Time.zone.now) }
def request
patch :skip
end
before do
stub_application_setting(require_two_factor_authentication: true)
stub_application_setting(two_factor_grace_period: 24)
end
it 'redirects the user to the root url' do
request
expect(response).to redirect_to root_url
end
it 'redirects back to 2fa page if grace period expired' do
travel_to(27.hours.from_now) do
request
expect(response).to redirect_to profile_two_factor_auth_url
end
end
end
end

View File

@ -97,6 +97,22 @@ RSpec.describe 'Two factor auths', feature_category: :system_access do
stub_application_setting(require_two_factor_authentication: true)
end
context 'when a grace period is set' do
before do
stub_application_setting(two_factor_grace_period: 24.hours)
end
it 'allows the user to skip enabling within the grace period', :js do
visit root_path
expect(page).to have_current_path(profile_two_factor_auth_path, ignore_query: true)
click_link 'Configure it later'
expect(page).to have_current_path(root_path)
end
end
context 'when invalid pin is provided' do
let_it_be(:user) { create(:omniauth_user) }

View File

@ -27,7 +27,7 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :continuous_integrat
it 'edits the pipeline' do
find_by_testid('edit-pipeline-schedule-btn').click
expect(page).to have_content(s_('PipelineSchedules|Edit Pipeline Schedule'))
expect(page).to have_content(s_('PipelineSchedules|Edit Scheduled Pipeline'))
expect(page).to have_button(s_('PipelineSchedules|Save changes'))
end
@ -147,10 +147,10 @@ RSpec.describe 'Pipeline Schedules', :js, feature_category: :continuous_integrat
it 'deletes the pipeline' do
within_testid('pipeline-schedule-table-row') do
click_button s_('PipelineSchedules|Delete pipeline schedule')
click_button s_('PipelineSchedules|Delete scheduled pipeline')
end
accept_gl_confirm(button_text: s_('PipelineSchedules|Delete pipeline schedule'))
accept_gl_confirm(button_text: s_('PipelineSchedules|Delete scheduled pipeline'))
expect(page).not_to have_css('[data-testid="pipeline-schedule-table-row"]')
end

View File

@ -9,6 +9,8 @@ identifiers:
additional_properties:
label:
description: TODO
property:
description: TODO
custom_key1:
description: The extra custom property name 1
custom_key2:

View File

@ -379,6 +379,7 @@
- "\e[B\e[B\e[B" # Arrow down to: Weekly count of unique users where label/value is...
- "\n" # Select: Weekly count of unique users where label/value is...
- "failure\n" # Input value for "label" filter
- " \n" # Ignore whitespace to skip "property" filter
- "metrics\n" # Input value for "custom_key1" filter
- "\n" # Skip "custom_key2" filter
- "30,13\n" # Input value for "custom_key3" filter

View File

@ -254,7 +254,7 @@ describe('CI Variable Drawer', () => {
},
});
expect(findVisibilityRadioGroup().attributes('disabled')).toBe('true');
expect(findVisibilityRadioGroup().attributes().disabled).toBe('true');
});
});
@ -609,6 +609,7 @@ describe('CI Variable Drawer', () => {
],
]);
expect(wrapper.emitted('close-form')).toBeUndefined();
expect(wrapper.findComponent(GlDrawer).element.scrollTo).toHaveBeenCalledTimes(1);
});
});

View File

@ -7,6 +7,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import TodosApp from '~/todos/components/todos_app.vue';
import TodoItem from '~/todos/components/todo_item.vue';
import TodosFilterBar from '~/todos/components/todos_filter_bar.vue';
import TodosMarkAllDoneButton from '~/todos/components/todos_mark_all_done_button.vue';
import getTodosQuery from '~/todos/components/queries/get_todos.query.graphql';
import { INSTRUMENT_TAB_LABELS, STATUS_BY_TAB } from '~/todos/constants';
import { mockTracking, unmockTracking } from 'jest/__helpers__/tracking_helper';
@ -37,6 +38,7 @@ describe('TodosApp', () => {
const findTodoItems = () => wrapper.findAllComponents(TodoItem);
const findGlTabs = () => wrapper.findComponent(GlTabs);
const findFilterBar = () => wrapper.findComponent(TodosFilterBar);
const findMarkAllDoneButton = () => wrapper.findComponent(TodosMarkAllDoneButton);
const findPendingTodosCount = () => wrapper.findByTestId('pending-todos-count');
it('should have a tracking event for each tab', () => {
@ -83,6 +85,17 @@ describe('TodosApp', () => {
expect(todosCountsQuerySuccessHandler).toHaveBeenLastCalledWith(filters);
});
it('re-fetches the pending todos count when mark all done button is clicked', async () => {
createComponent();
await waitForPromises();
expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(1);
findMarkAllDoneButton().vm.$emit('change');
expect(todosCountsQuerySuccessHandler).toHaveBeenCalledTimes(2);
});
it('shows the pending todos count once it has been fetched', async () => {
createComponent();

View File

@ -177,7 +177,7 @@ describe('Merge request merge checks component', () => {
});
it('sorts merge checks', async () => {
mountComponent({
shallowMountComponent({
mergeabilityChecks: [
{ identifier: 'discussions_not_resolved', status: 'SUCCESS' },
{ identifier: 'status_checks_must_pass', status: 'INACTIVE' },
@ -187,15 +187,11 @@ describe('Merge request merge checks component', () => {
await waitForPromises();
await wrapper.findByTestId('widget-toggle').trigger('click');
wrapper.vm.toggleCollapsed();
const mergeChecks = wrapper.findAllByTestId('merge-check');
expect(mergeChecks.length).toBe(2);
expect(mergeChecks.at(0).props('check')).toEqual(expect.objectContaining({ status: 'FAILED' }));
expect(mergeChecks.at(1).props('check')).toEqual(
expect.objectContaining({ status: 'SUCCESS' }),
);
expect(wrapper.vm.sortedChecks.length).toBe(2);
expect(wrapper.vm.sortedChecks[0].status).toBe('FAILED');
expect(wrapper.vm.sortedChecks[1].status).toBe('SUCCESS');
});
it('does not render check component if no message exists', async () => {
@ -210,6 +206,8 @@ describe('Merge request merge checks component', () => {
await wrapper.findByTestId('widget-toggle').trigger('click');
await waitForPromises();
const mergeChecks = wrapper.findAllByTestId('merge-check');
expect(mergeChecks.length).toBe(1);
@ -266,7 +264,7 @@ describe('Merge request merge checks component', () => {
});
it('renders checking text', () => {
expect(wrapper.text()).toBe('Checking if merge request can be merged...');
expect(wrapper.text()).toContain('Checking if merge request can be merged...');
});
it('renders checks expanded by default', () => {

View File

@ -560,11 +560,6 @@ RSpec.describe Feature, :clean_gitlab_redis_feature_flag, stub_feature_flags: fa
context 'and feature has been disabled' do
before do
# TODO: revert changes to .once when removing use_load_balancing_session_map feature flag
# We stub SessionMap.current since it uses a feature flag. Within this spec, all feature flags
# definitions are missing due to the stubbed Feature::Definition.definitions method.
allow(Gitlab::Database::LoadBalancing::SessionMap)
.to receive(:current).and_return(Gitlab::Database::LoadBalancing::Session.current)
described_class.disable(:my_feature_flag)
end

View File

@ -13,8 +13,7 @@ RSpec.describe Gitlab::Auth::TokenExpirationBanner, feature_category: :system_ac
# for specs, we need to reset it each time
before do
described_class.instance_variable_set(:@show_token_expiration_banner, nil)
# TODO: revert changes to .twice when removing use_load_balancing_session_map feature flag https://gitlab.com/gitlab-org/gitlab/-/issues/496505
allow(Gitlab).to receive(:version_info).at_least(:twice).and_return(gitlab_version)
allow(Gitlab).to receive(:version_info).twice.and_return(gitlab_version)
end
it { is_expected.to be(false) }

View File

@ -2,7 +2,9 @@
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::BackfillIssuesCorrectWorkItemTypeId, feature_category: :team_planning do
RSpec.describe Gitlab::BackgroundMigration::BackfillIssuesCorrectWorkItemTypeId,
feature_category: :team_planning,
schema: 20241030165330 do
let(:batch_column) { 'id' }
let(:sub_batch_size) { 2 }
let(:pause_ms) { 0 }

View File

@ -12,29 +12,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::SessionMap, feature_category: :d
described_class.clear_session
end
context 'when feature flag is disabled' do
before do
described_class.current(lb) # initialise a SessionMap
stub_feature_flags(use_load_balancing_session_map: false)
end
it 'returns sessions from Gitlab::Database::LoadBalancing::Session.current' do
expect(described_class.current(lb)).to eq(Gitlab::Database::LoadBalancing::Session.current)
end
end
context 'when feature flag lookup returns unexpected error' do
before do
allow(Feature).to receive(:enabled?).and_raise(StandardError)
end
it 'tracks exception and return false' do
# behaves as if feature flag is disabled
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(StandardError)
expect(described_class.current(lb)).to eq(Gitlab::Database::LoadBalancing::Session.current)
end
end
context 'when already initialised' do
before do
described_class.current(lb)
@ -141,21 +118,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::SessionMap, feature_category: :d
expect(RequestStore[described_class::CACHE_KEY]).to eq(nil)
end
context 'when feature flag is disabled' do
before do
described_class.current(lb) # initialise a SessionMap
stub_feature_flags(use_load_balancing_session_map: false)
end
it 'clears session from Gitlab::Database::LoadBalancing::Session.current' do
expect(Gitlab::Database::LoadBalancing::Session.current).not_to eq(nil)
described_class.clear_session
expect(RequestStore[Gitlab::Database::LoadBalancing::Session::CACHE_KEY]).to eq(nil)
end
end
end
describe '.without_sticky_writes' do
@ -181,20 +143,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::SessionMap, feature_category: :d
# exact logic for ignore_writes is tested in `.with_sessions` test suite
end
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(use_load_balancing_session_map: false)
end
it 'calls Gitlab::Database::LoadBalancing::Session instead' do
expect(Gitlab::Database::LoadBalancing::Session).to receive(:without_sticky_writes).and_yield
described_class.without_sticky_writes do
# exact logic for ignore_writes is tested in `.with_sessions` test suite
end
end
end
end
describe '.with_sessions' do
@ -231,17 +179,6 @@ RSpec.describe Gitlab::Database::LoadBalancing::SessionMap, feature_category: :d
end.to raise_error(instance_of(described_class::InvalidLoadBalancerNameError))
end
context 'when use_load_balancing_session_map is disabled' do
before do
stub_feature_flags(use_load_balancing_session_map: false)
end
it 'returns Session instead of ScopedSession' do
expect(with_sessions)
.to be_an_instance_of(Gitlab::Database::LoadBalancing::Session)
end
end
context 'when calling use_primary!' do
it 'applies use_primary! to all sessions' do
with_sessions.use_primary!

View File

@ -3,47 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::LoadBalancing::Session do
after do
described_class.clear_session
end
describe '.current' do
it 'returns the current session' do
expect(described_class.current).to be_an_instance_of(described_class)
end
end
describe '.clear_session' do
it 'clears the current session' do
described_class.current
described_class.clear_session
expect(RequestStore[described_class::CACHE_KEY]).to be_nil
end
end
describe '.without_sticky_writes' do
it 'ignores sticky write events sent by a connection proxy' do
described_class.without_sticky_writes do
described_class.current.write!
end
session = described_class.current
expect(session).not_to be_using_primary
end
it 'still is aware of write that happened' do
described_class.without_sticky_writes do
described_class.current.write!
end
session = described_class.current
expect(session.performed_write?).to be true
end
end
describe '#use_primary?' do
it 'returns true when the primary should be used' do
instance = described_class.new

View File

@ -1251,12 +1251,14 @@ RSpec.describe Gitlab::GitalyClient::CommitService, feature_category: :gitaly do
[large_signed_text, *signed_by_user].each do |commit_id|
expect(signatures[commit_id][:signature]).to be_present
expect(signatures[commit_id][:signer]).to eq(:SIGNER_USER)
expect(signatures[commit_id][:author_email]).to be_present
end
signed_by_user.each do |commit_id|
commit = project.commit(commit_id)
expect(signatures[commit_id][:signed_text]).to include(commit.message)
expect(signatures[commit_id][:signed_text]).to include(commit.description)
expect(signatures[commit_id][:author_email]).to eq(commit.author_email)
end
expect(signatures[large_signed_text][:signed_text].size).to eq(4971878)

View File

@ -22,7 +22,6 @@ RSpec.describe Gitlab::Tracking::EventDefinitionValidator, feature_category: :se
let(:path) { File.join('events', 'issues_create.yml') }
let(:definition) { Gitlab::Tracking::EventDefinition.new(path, attributes) }
# let(:yaml_content) { attributes.deep_stringify_keys.to_yaml }
describe '#validate' do
using RSpec::Parameterized::TableSyntax
@ -69,15 +68,21 @@ RSpec.describe Gitlab::Tracking::EventDefinitionValidator, feature_category: :se
where(:label, :property, :value, :custom, :error?) do
true | true | true | true | false
true | true | true | false | false
true | true | false | false | false
true | true | false | true | false
true | false | false | false | false
false | true | false | false | false
false | true | true | false | false
true | false | true | true | true
true | true | false | false | false
true | false | true | true | false
true | false | true | false | false
true | false | false | true | true
false | true | true | true | true
false | false | true | true | true
true | false | false | false | false
false | true | true | true | false
false | true | true | false | false
false | true | false | true | true
false | true | false | false | false
false | false | true | true | false
false | false | true | false | false
false | false | false | true | true
false | false | false | false | false
nil | nil | nil | nil | false
end
with_them do
@ -86,6 +91,8 @@ RSpec.describe Gitlab::Tracking::EventDefinitionValidator, feature_category: :se
attributes[:additional_properties][:property] = { description: "button state" } if property
attributes[:additional_properties][:value] = { description: "package version" } if value
attributes[:additional_properties][:custom] = { description: "custom" } if custom
attributes.delete(:additional_properties) if [label, property, value, custom].all?(&:nil?)
end
subject { described_class.new(definition).validation_errors.any? }