Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									15e998c5bf
								
							
						
					
					
						commit
						39b47b75cf
					
				| 
						 | 
				
			
			@ -3980,7 +3980,6 @@ RSpec/FeatureCategory:
 | 
			
		|||
    - 'spec/lib/gitlab/usage_data_counters/merge_request_widget_extension_counter_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/usage_data_counters/note_counter_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/usage_data_counters/package_event_counter_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/usage_data_counters/productivity_analytics_counter_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
 | 
			
		||||
    - 'spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -510,7 +510,6 @@ Style/ClassAndModuleChildren:
 | 
			
		|||
    - 'lib/gitlab/usage_data_counters/ci_template_unique_counter.rb'
 | 
			
		||||
    - 'lib/gitlab/usage_data_counters/designs_counter.rb'
 | 
			
		||||
    - 'lib/gitlab/usage_data_counters/note_counter.rb'
 | 
			
		||||
    - 'lib/gitlab/usage_data_counters/productivity_analytics_counter.rb'
 | 
			
		||||
    - 'lib/gitlab/usage_data_counters/snippet_counter.rb'
 | 
			
		||||
    - 'lib/gitlab/usage_data_counters/source_code_counter.rb'
 | 
			
		||||
    - 'lib/gitlab/usage_data_counters/wiki_page_counter.rb'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										34
									
								
								CHANGELOG.md
								
								
								
								
							| 
						 | 
				
			
			@ -2,6 +2,16 @@
 | 
			
		|||
documentation](doc/development/changelog.md) for instructions on adding your own
 | 
			
		||||
entry.
 | 
			
		||||
 | 
			
		||||
## 16.11.1 (2024-04-24)
 | 
			
		||||
 | 
			
		||||
### Security (5 changes)
 | 
			
		||||
 | 
			
		||||
- [Validation for encoded formatting characters](gitlab-org/security/gitlab@fc42e4b96ae1ac3cd766569d62d025cbf23ef16c) ([merge request](gitlab-org/security/gitlab!3979))
 | 
			
		||||
- [Forbid untrusted sign-ins to GitLab with Bitbucket and fix related uid](gitlab-org/security/gitlab@ef083c319e67072029787cd5c6a588562984a58c) ([merge request](gitlab-org/security/gitlab!3983))
 | 
			
		||||
- [Ensure PAT scope is validated everywhere for GraphQL/ActionCable](gitlab-org/security/gitlab@1847435210161d95b9c5fcd079380e7f2892195f) ([merge request](gitlab-org/security/gitlab!3975))
 | 
			
		||||
- [Protect against ReDoS in FileFinder with wildcard filters](gitlab-org/security/gitlab@dc16f3baa640ca8d5b223782ef3d58369423a1dd) ([merge request](gitlab-org/security/gitlab!3969))
 | 
			
		||||
- [fix: Validate security report version against schema during parsing](gitlab-org/security/gitlab@55e58d49051aa42938ec1d159b5e7eb3c47d2eb1) ([merge request](gitlab-org/security/gitlab!3967))
 | 
			
		||||
 | 
			
		||||
## 16.11.0 (2024-04-17)
 | 
			
		||||
 | 
			
		||||
### Added (121 changes)
 | 
			
		||||
| 
						 | 
				
			
			@ -605,6 +615,20 @@ entry.
 | 
			
		|||
- [Finalize the backfill migration for onboarding status step url](gitlab-org/gitlab@f986c1b1cf00968ff106136893bfe68d47895c69) ([merge request](gitlab-org/gitlab!147278))
 | 
			
		||||
- [Remove ClusterRepositoryCache migration helper class](gitlab-org/gitlab@f71a7a94ce8d70d9d378ebc225b802b58f0ae006) ([merge request](gitlab-org/gitlab!147244))
 | 
			
		||||
 | 
			
		||||
## 16.10.4 (2024-04-24)
 | 
			
		||||
 | 
			
		||||
### Fixed (1 change)
 | 
			
		||||
 | 
			
		||||
- [Update vulnerability_reads scanner in the ingestion pipeline](gitlab-org/security/gitlab@14b8876233e5dd29149426fd88bab0fc4f014d46) **GitLab Enterprise Edition**
 | 
			
		||||
 | 
			
		||||
### Security (5 changes)
 | 
			
		||||
 | 
			
		||||
- [Validation for encoded formatting characters](gitlab-org/security/gitlab@4cd13c705ce1a94152fb2fd6fcaa77e90e6441e5) ([merge request](gitlab-org/security/gitlab!3950))
 | 
			
		||||
- [Forbid untrusted sign-ins to GitLab with Bitbucket and fix related uid](gitlab-org/security/gitlab@5d3c3a599cc5560dea2236474309537536428cdc) ([merge request](gitlab-org/security/gitlab!3984))
 | 
			
		||||
- [Ensure PAT scope is validated everywhere for GraphQL/ActionCable](gitlab-org/security/gitlab@079dfee8cff9da9075eec7c03ce002e87eeebfff) ([merge request](gitlab-org/security/gitlab!3976))
 | 
			
		||||
- [Protect against ReDoS in FileFinder with wildcard filters](gitlab-org/security/gitlab@0e7e54050f1c4829b1d55aac85bd4e9cd96f1580) ([merge request](gitlab-org/security/gitlab!3960))
 | 
			
		||||
- [fix: Validate security report version against schema during parsing](gitlab-org/security/gitlab@217040b1062caad501d60af387c47cff758788a1) ([merge request](gitlab-org/security/gitlab!3956))
 | 
			
		||||
 | 
			
		||||
## 16.10.3 (2024-04-12)
 | 
			
		||||
 | 
			
		||||
No changes.
 | 
			
		||||
| 
						 | 
				
			
			@ -1319,6 +1343,16 @@ No changes.
 | 
			
		|||
- [Add sharding keys for system_access](gitlab-org/gitlab@62c2fd4788e62e46f1469e2f18d178840e8e3df2) ([merge request](gitlab-org/gitlab!142501))
 | 
			
		||||
- [Add sharding keys for purchase](gitlab-org/gitlab@9c3843da74714c72483c17489d5d3d68ceffd2c8) ([merge request](gitlab-org/gitlab!142505))
 | 
			
		||||
 | 
			
		||||
## 16.9.6 (2024-04-24)
 | 
			
		||||
 | 
			
		||||
### Security (5 changes)
 | 
			
		||||
 | 
			
		||||
- [Validation for encoded formatting characters](gitlab-org/security/gitlab@de8dc151e5ef3f07cf50839e50645df6ec12f5a5) ([merge request](gitlab-org/security/gitlab!3951))
 | 
			
		||||
- [Forbid untrusted sign-ins to GitLab with Bitbucket and fix related uid](gitlab-org/security/gitlab@94496a91c17a0f73202cd5c55abc93395825c68c) ([merge request](gitlab-org/security/gitlab!3985))
 | 
			
		||||
- [Ensure PAT scope is validated everywhere for GraphQL/ActionCable](gitlab-org/security/gitlab@0dccf32b71614584e05a8590b21a902220e8c701) ([merge request](gitlab-org/security/gitlab!3977))
 | 
			
		||||
- [Protect against ReDoS in FileFinder with wildcard filters](gitlab-org/security/gitlab@60a7418ec10f7c6f4ef9bcc75b2fec71255ddcc3) ([merge request](gitlab-org/security/gitlab!3961))
 | 
			
		||||
- [fix: Validate security report version against schema during parsing](gitlab-org/security/gitlab@ce709ff78fd8f18024383085d6ac0bf43fa2efbb) ([merge request](gitlab-org/security/gitlab!3957))
 | 
			
		||||
 | 
			
		||||
## 16.9.5 (2024-04-12)
 | 
			
		||||
 | 
			
		||||
No changes.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								Gemfile
								
								
								
								
							
							
						
						
									
										4
									
								
								Gemfile
								
								
								
								
							| 
						 | 
				
			
			@ -358,7 +358,6 @@ gem 'gitlab-license', '~> 2.4', feature_category: :shared
 | 
			
		|||
gem 'rack-attack', '~> 6.7.0' # rubocop:todo Gemfile/MissingFeatureCategory
 | 
			
		||||
 | 
			
		||||
# Sentry integration
 | 
			
		||||
gem 'sentry-raven', '~> 3.1', feature_category: :error_tracking
 | 
			
		||||
gem 'sentry-ruby', '~> 5.10.0', feature_category: :error_tracking
 | 
			
		||||
gem 'sentry-rails', '~> 5.10.0', feature_category: :error_tracking
 | 
			
		||||
gem 'sentry-sidekiq', '~> 5.10.0', feature_category: :error_tracking
 | 
			
		||||
| 
						 | 
				
			
			@ -411,7 +410,6 @@ group :opentelemetry do
 | 
			
		|||
  gem 'opentelemetry-instrumentation-action_view', feature_category: :tooling
 | 
			
		||||
  gem 'opentelemetry-instrumentation-aws_sdk', feature_category: :tooling
 | 
			
		||||
  gem 'opentelemetry-instrumentation-http', feature_category: :tooling
 | 
			
		||||
  gem 'opentelemetry-instrumentation-active_model_serializers', feature_category: :tooling
 | 
			
		||||
  gem 'opentelemetry-instrumentation-concurrent_ruby', feature_category: :tooling
 | 
			
		||||
  gem 'opentelemetry-instrumentation-ethon', feature_category: :tooling
 | 
			
		||||
  gem 'opentelemetry-instrumentation-excon', feature_category: :tooling
 | 
			
		||||
| 
						 | 
				
			
			@ -592,7 +590,7 @@ gem 'ssh_data', '~> 1.3' # rubocop:todo Gemfile/MissingFeatureCategory
 | 
			
		|||
gem 'spamcheck', '~> 1.3.0' # rubocop:todo Gemfile/MissingFeatureCategory
 | 
			
		||||
 | 
			
		||||
# Gitaly GRPC protocol definitions
 | 
			
		||||
gem 'gitaly', '~> 16.11.0.pre.rc1', feature_category: :gitaly
 | 
			
		||||
gem 'gitaly', '~> 17.0.0.pre.rc2', feature_category: :gitaly
 | 
			
		||||
 | 
			
		||||
# KAS GRPC protocol definitions
 | 
			
		||||
gem 'kas-grpc', '~> 0.4.0', feature_category: :deployment_management
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -206,7 +206,7 @@
 | 
			
		|||
{"name":"gettext","version":"3.4.9","platform":"ruby","checksum":"292864fe6a15c224cee4125a4a72fab426fdbb280e4cff3cfe44935f549b009a"},
 | 
			
		||||
{"name":"gettext_i18n_rails","version":"1.12.0","platform":"ruby","checksum":"6ac4817731a9e2ce47e1e83381ac34f9142263bc2911aaaafb2526d2f1afc1be"},
 | 
			
		||||
{"name":"git","version":"1.18.0","platform":"ruby","checksum":"c9b80462e4565cd3d7a9ba8440c41d2c52244b17b0dad0bfddb46de70630c465"},
 | 
			
		||||
{"name":"gitaly","version":"16.11.0.pre.rc1","platform":"ruby","checksum":"24334f5f3fd5b6c3d278eea9fe2b6732dd08e87a4146cd4374615506b1a6e7ae"},
 | 
			
		||||
{"name":"gitaly","version":"17.0.0.pre.rc2","platform":"ruby","checksum":"2fa5998d3cbc37ba66bef428fb7150ab3f8b4105a4bd29ea48d965fae98ead43"},
 | 
			
		||||
{"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"},
 | 
			
		||||
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
 | 
			
		||||
{"name":"gitlab-dangerfiles","version":"4.7.0","platform":"ruby","checksum":"2576876a8dcb7290853fc3aef8048001cfe593b87318dd0016959d42e0e145ca"},
 | 
			
		||||
| 
						 | 
				
			
			@ -453,7 +453,6 @@
 | 
			
		|||
{"name":"opentelemetry-instrumentation-action_pack","version":"0.9.0","platform":"ruby","checksum":"c5df8472afc9cdbfc1425d9af7816b9cfc1a1a69b86621f1fc624974bd9acb9a"},
 | 
			
		||||
{"name":"opentelemetry-instrumentation-action_view","version":"0.7.0","platform":"ruby","checksum":"bc7c714be0b4bb76843085c29ecc9465e65cb7fe6722e34c71629e44f8c3cb75"},
 | 
			
		||||
{"name":"opentelemetry-instrumentation-active_job","version":"0.7.1","platform":"ruby","checksum":"da24806c9d92fe580db42638f6c763fe1324ff90aa147d45d4247f8052c68089"},
 | 
			
		||||
{"name":"opentelemetry-instrumentation-active_model_serializers","version":"0.20.1","platform":"ruby","checksum":"8c47f859fc925c4c078d37f5a13c55f4ba9751f880aa64d0c9568f3f59a3efaa"},
 | 
			
		||||
{"name":"opentelemetry-instrumentation-active_record","version":"0.7.0","platform":"ruby","checksum":"327ca53ebb74187b463ab05c1d89508552e9cd9122db0843ad1f27930ee91797"},
 | 
			
		||||
{"name":"opentelemetry-instrumentation-active_support","version":"0.5.1","platform":"ruby","checksum":"03898327e8284410b8935a3d3b980bda56e2063eb5a7d30acf75487dd6934a66"},
 | 
			
		||||
{"name":"opentelemetry-instrumentation-aws_sdk","version":"0.5.1","platform":"ruby","checksum":"496a8d13c59ff4d08dcd69b16db97c013398173295058593aa0c2f3ef3090cce"},
 | 
			
		||||
| 
						 | 
				
			
			@ -623,7 +622,6 @@
 | 
			
		|||
{"name":"selenium-webdriver","version":"4.19.0","platform":"ruby","checksum":"4c8bd1d6016a456154b4ba71a3bb4d532a0ae185a38acf9cec0acbd38b4e5066"},
 | 
			
		||||
{"name":"semver_dialects","version":"2.0.2","platform":"ruby","checksum":"60059c9f416f931b5212d862fad2879d6b9affb8e0b9afb0d91b793639c116fe"},
 | 
			
		||||
{"name":"sentry-rails","version":"5.10.0","platform":"ruby","checksum":"99aa2fac136c26942eb1897c65de65dac88ad43ac5eb183ff20711287a137ebd"},
 | 
			
		||||
{"name":"sentry-raven","version":"3.1.2","platform":"ruby","checksum":"103d3b122958810d34898ce2e705bcf549ddb9d855a70ce9a3970ee2484f364a"},
 | 
			
		||||
{"name":"sentry-ruby","version":"5.10.0","platform":"ruby","checksum":"115c24c0aee1309210f3a2988fb118e2bec1f11609feeda90e694388b1183619"},
 | 
			
		||||
{"name":"sentry-sidekiq","version":"5.10.0","platform":"ruby","checksum":"cc81018d0733fb1be3fb5641c9e0b61030bbeaa1d0b23ca64797d70def7aea1a"},
 | 
			
		||||
{"name":"sexp_processor","version":"4.17.1","platform":"ruby","checksum":"91110946720307f30bf1d549e90d9a529fef40d1fc471c069c8cca7667015da0"},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								Gemfile.lock
								
								
								
								
							
							
						
						
									
										11
									
								
								Gemfile.lock
								
								
								
								
							| 
						 | 
				
			
			@ -680,7 +680,7 @@ GEM
 | 
			
		|||
    git (1.18.0)
 | 
			
		||||
      addressable (~> 2.8)
 | 
			
		||||
      rchardet (~> 1.8)
 | 
			
		||||
    gitaly (16.11.0.pre.rc1)
 | 
			
		||||
    gitaly (17.0.0.pre.rc2)
 | 
			
		||||
      grpc (~> 1.0)
 | 
			
		||||
    gitlab (4.19.0)
 | 
			
		||||
      httparty (~> 0.20)
 | 
			
		||||
| 
						 | 
				
			
			@ -1253,9 +1253,6 @@ GEM
 | 
			
		|||
    opentelemetry-instrumentation-active_job (0.7.1)
 | 
			
		||||
      opentelemetry-api (~> 1.0)
 | 
			
		||||
      opentelemetry-instrumentation-base (~> 0.22.1)
 | 
			
		||||
    opentelemetry-instrumentation-active_model_serializers (0.20.1)
 | 
			
		||||
      opentelemetry-api (~> 1.0)
 | 
			
		||||
      opentelemetry-instrumentation-base (~> 0.22.1)
 | 
			
		||||
    opentelemetry-instrumentation-active_record (0.7.0)
 | 
			
		||||
      opentelemetry-api (~> 1.0)
 | 
			
		||||
      opentelemetry-instrumentation-base (~> 0.22.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -1669,8 +1666,6 @@ GEM
 | 
			
		|||
    sentry-rails (5.10.0)
 | 
			
		||||
      railties (>= 5.0)
 | 
			
		||||
      sentry-ruby (~> 5.10.0)
 | 
			
		||||
    sentry-raven (3.1.2)
 | 
			
		||||
      faraday (>= 1.0)
 | 
			
		||||
    sentry-ruby (5.10.0)
 | 
			
		||||
      concurrent-ruby (~> 1.0, >= 1.0.2)
 | 
			
		||||
    sentry-sidekiq (5.10.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2008,7 +2003,7 @@ DEPENDENCIES
 | 
			
		|||
  gdk-toogle (~> 0.9)
 | 
			
		||||
  gettext (~> 3.4, >= 3.4.9)
 | 
			
		||||
  gettext_i18n_rails (~> 1.12.0)
 | 
			
		||||
  gitaly (~> 16.11.0.pre.rc1)
 | 
			
		||||
  gitaly (~> 17.0.0.pre.rc2)
 | 
			
		||||
  gitlab-backup-cli!
 | 
			
		||||
  gitlab-chronic (~> 0.10.5)
 | 
			
		||||
  gitlab-dangerfiles (~> 4.7.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -2142,7 +2137,6 @@ DEPENDENCIES
 | 
			
		|||
  opentelemetry-instrumentation-action_pack
 | 
			
		||||
  opentelemetry-instrumentation-action_view
 | 
			
		||||
  opentelemetry-instrumentation-active_job
 | 
			
		||||
  opentelemetry-instrumentation-active_model_serializers
 | 
			
		||||
  opentelemetry-instrumentation-active_record
 | 
			
		||||
  opentelemetry-instrumentation-active_support
 | 
			
		||||
  opentelemetry-instrumentation-aws_sdk
 | 
			
		||||
| 
						 | 
				
			
			@ -2224,7 +2218,6 @@ DEPENDENCIES
 | 
			
		|||
  selenium-webdriver (~> 4.19)
 | 
			
		||||
  semver_dialects (~> 2.0, >= 2.0.2)
 | 
			
		||||
  sentry-rails (~> 5.10.0)
 | 
			
		||||
  sentry-raven (~> 3.1)
 | 
			
		||||
  sentry-ruby (~> 5.10.0)
 | 
			
		||||
  sentry-sidekiq (~> 5.10.0)
 | 
			
		||||
  shoulda-matchers (~> 5.1.0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
 | 
			
		|||
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
 | 
			
		||||
import { formatDate } from '~/lib/utils/datetime_utility';
 | 
			
		||||
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
 | 
			
		||||
import Markdown from '~/vue_shared/components/markdown/non_gfm_markdown.vue';
 | 
			
		||||
import CiVerificationBadge from '../shared/ci_verification_badge.vue';
 | 
			
		||||
import CiResourceAbout from './ci_resource_about.vue';
 | 
			
		||||
import CiResourceHeaderSkeletonLoader from './ci_resource_header_skeleton_loader.vue';
 | 
			
		||||
| 
						 | 
				
			
			@ -35,6 +36,7 @@ export default {
 | 
			
		|||
    GlDisclosureDropdown,
 | 
			
		||||
    GlDisclosureDropdownItem,
 | 
			
		||||
    GlLink,
 | 
			
		||||
    Markdown,
 | 
			
		||||
  },
 | 
			
		||||
  directives: {
 | 
			
		||||
    GlTooltip: GlTooltipDirective,
 | 
			
		||||
| 
						 | 
				
			
			@ -198,9 +200,7 @@ export default {
 | 
			
		|||
      v-if="isLoadingSharedData"
 | 
			
		||||
      class="gl-animate-skeleton-loader gl-h-4 gl-rounded-base gl-my-3 gl-max-w-20!"
 | 
			
		||||
    ></div>
 | 
			
		||||
    <p v-else class="gl-mt-2">
 | 
			
		||||
      {{ resource.description }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <markdown v-else class="gl-mt-2" :markdown="resource.description" />
 | 
			
		||||
    <abuse-category-selector
 | 
			
		||||
      v-if="hasLatestVersion && isReportAbuseDrawerOpen && reportAbusePath"
 | 
			
		||||
      :reported-user-id="authorId"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
 | 
			
		|||
import { formatDate, getTimeago } from '~/lib/utils/datetime_utility';
 | 
			
		||||
import { toNounSeriesText } from '~/lib/utils/grammar';
 | 
			
		||||
import { cleanLeadingSeparator } from '~/lib/utils/url_utility';
 | 
			
		||||
import Markdown from '~/vue_shared/components/markdown/non_gfm_markdown.vue';
 | 
			
		||||
import { CI_RESOURCE_DETAILS_PAGE_NAME } from '../../router/constants';
 | 
			
		||||
import CiVerificationBadge from '../shared/ci_verification_badge.vue';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,6 +31,7 @@ export default {
 | 
			
		|||
    GlLink,
 | 
			
		||||
    GlSprintf,
 | 
			
		||||
    GlTruncate,
 | 
			
		||||
    Markdown,
 | 
			
		||||
  },
 | 
			
		||||
  directives: {
 | 
			
		||||
    GlTooltip: GlTooltipDirective,
 | 
			
		||||
| 
						 | 
				
			
			@ -183,7 +185,10 @@ export default {
 | 
			
		|||
        class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-justify-content-space-between gl-font-sm"
 | 
			
		||||
      >
 | 
			
		||||
        <div>
 | 
			
		||||
          <span class="gl-display-flex gl-flex-basis-two-thirds">{{ resource.description }}</span>
 | 
			
		||||
          <markdown
 | 
			
		||||
            class="gl-display-flex gl-flex-basis-two-thirds"
 | 
			
		||||
            :markdown="resource.description"
 | 
			
		||||
          />
 | 
			
		||||
          <div
 | 
			
		||||
            v-if="hasComponents"
 | 
			
		||||
            data-testid="ci-resource-component-names"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,13 @@ function reportErrorAndThrow(e) {
 | 
			
		|||
  Sentry.captureException(e);
 | 
			
		||||
  throw e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** ****
 | 
			
		||||
 *
 | 
			
		||||
 * Provisioning API
 | 
			
		||||
 *
 | 
			
		||||
 * ***** */
 | 
			
		||||
 | 
			
		||||
// Provisioning API spec: https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/provisioning-api/pkg/provisioningapi/routes.go#L59
 | 
			
		||||
async function enableObservability(provisioningUrl) {
 | 
			
		||||
  try {
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +47,97 @@ async function isObservabilityEnabled(provisioningUrl) {
 | 
			
		|||
  return reportErrorAndThrow(new Error('Failed to check provisioning')); // eslint-disable-line @gitlab/require-i18n-strings
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** ****
 | 
			
		||||
 *
 | 
			
		||||
 * Common utils
 | 
			
		||||
 *
 | 
			
		||||
 * ***** */
 | 
			
		||||
 | 
			
		||||
const FILTER_OPERATORS_PREFIX = {
 | 
			
		||||
  '!=': 'not',
 | 
			
		||||
  '>': 'gt',
 | 
			
		||||
  '<': 'lt',
 | 
			
		||||
  '!~': 'not_like',
 | 
			
		||||
  '=~': 'like',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const SEARCH_FILTER_NAME = 'search';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return the query parameter name, given an operator and param key
 | 
			
		||||
 *
 | 
			
		||||
 * e.g
 | 
			
		||||
 *    if paramKey is 'foo' and operator is "=", param name is 'foo'
 | 
			
		||||
 *    if paramKey is 'foo' and operator is "!=", param name is 'not[foo]'
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} paramKey - The parameter name
 | 
			
		||||
 * @param {String} operator - The operator
 | 
			
		||||
 * @returns String | undefined - Query param name
 | 
			
		||||
 */
 | 
			
		||||
function getFilterParamName(filterName, operator, filterToQueryMapping) {
 | 
			
		||||
  const paramKey = filterToQueryMapping[filterName];
 | 
			
		||||
  if (!paramKey) return undefined;
 | 
			
		||||
 | 
			
		||||
  if (operator === '=' || filterName === SEARCH_FILTER_NAME) {
 | 
			
		||||
    return paramKey;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const prefix = FILTER_OPERATORS_PREFIX[operator];
 | 
			
		||||
  if (prefix) {
 | 
			
		||||
    return `${prefix}[${paramKey}]`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Process `filterValue` and append the proper query params to the  `searchParams` arg, using `nameParam` and `valueParam`
 | 
			
		||||
 *
 | 
			
		||||
 * It mutates `searchParams`
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} filterValue The filter value, in the format `attribute_name=attribute_value`
 | 
			
		||||
 * @param {String} filterOperator The filter operator
 | 
			
		||||
 * @param {URLSearchParams} searchParams The URLSearchParams object where to append the proper query params
 | 
			
		||||
 * @param {String} nameParam The query param name for the attribute name
 | 
			
		||||
 * @param {String} nameParam The query param name for the attribute value
 | 
			
		||||
 *
 | 
			
		||||
 * e.g.
 | 
			
		||||
 *
 | 
			
		||||
 *    handleAttributeFilter('foo=bar', '=', searchParams, 'attr_name', 'attr_value')
 | 
			
		||||
 *
 | 
			
		||||
 *        it adds { attr_name: 'foo', attr_value: 'bar'} to `searchParams`
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
function handleAttributeFilter(filterValue, filterOperator, searchParams, nameParam, valueParam) {
 | 
			
		||||
  const [attrName, attrValue] = filterValue.split('=');
 | 
			
		||||
  if (attrName && attrValue) {
 | 
			
		||||
    if (filterOperator === '=') {
 | 
			
		||||
      searchParams.append(nameParam, attrName);
 | 
			
		||||
      searchParams.append(valueParam, attrValue);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addDateRangeFilterToQueryParams(dateRangeFilter, params) {
 | 
			
		||||
  if (!dateRangeFilter || !params) return;
 | 
			
		||||
 | 
			
		||||
  const { value, endDate, startDate } = dateRangeFilter;
 | 
			
		||||
  if (value === CUSTOM_DATE_RANGE_OPTION) {
 | 
			
		||||
    if (isValidDate(startDate) && isValidDate(endDate)) {
 | 
			
		||||
      params.append('start_time', startDate.toISOString());
 | 
			
		||||
      params.append('end_time', endDate.toISOString());
 | 
			
		||||
    }
 | 
			
		||||
  } else if (typeof value === 'string') {
 | 
			
		||||
    params.append('period', value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** ****
 | 
			
		||||
 *
 | 
			
		||||
 * Tracing API
 | 
			
		||||
 *
 | 
			
		||||
 * ***** */
 | 
			
		||||
 | 
			
		||||
async function fetchTrace(tracingUrl, traceId) {
 | 
			
		||||
  try {
 | 
			
		||||
    if (!traceId) {
 | 
			
		||||
| 
						 | 
				
			
			@ -67,88 +165,23 @@ const SUPPORTED_TRACING_FILTERS = {
 | 
			
		|||
  traceId: ['=', '!='],
 | 
			
		||||
  attribute: ['='],
 | 
			
		||||
  status: ['=', '!='],
 | 
			
		||||
  // free-text 'search' temporarily ignored https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2309
 | 
			
		||||
  // 'search' temporarily ignored https://gitlab.com/gitlab-org/opstrace/opstrace/-/issues/2309
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mapping of filter name to query param
 | 
			
		||||
 * Mapping of filter name to tracing query param
 | 
			
		||||
 */
 | 
			
		||||
const TRACING_FILTER_TO_QUERY_PARAM = {
 | 
			
		||||
  durationMs: 'duration_nano',
 | 
			
		||||
  operation: 'operation',
 | 
			
		||||
  service: 'service_name',
 | 
			
		||||
  period: 'period',
 | 
			
		||||
  traceId: 'trace_id',
 | 
			
		||||
  attribute: 'attribute',
 | 
			
		||||
  status: 'status',
 | 
			
		||||
  // `attribute` is handled separately, see `handleAttributeFilter` method
 | 
			
		||||
  // `period` is handled separately, see `handleTracingPeriodFilter` method
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const FILTER_OPERATORS_PREFIX = {
 | 
			
		||||
  '!=': 'not',
 | 
			
		||||
  '>': 'gt',
 | 
			
		||||
  '<': 'lt',
 | 
			
		||||
  '!~': 'not_like',
 | 
			
		||||
  '=~': 'like',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return the query parameter name, given an operator and param key
 | 
			
		||||
 *
 | 
			
		||||
 * e.g
 | 
			
		||||
 *    if paramKey is 'foo' and operator is "=", param name is 'foo'
 | 
			
		||||
 *    if paramKey is 'foo' and operator is "!=", param name is 'not[foo]'
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} paramKey - The parameter name
 | 
			
		||||
 * @param {String} operator - The operator
 | 
			
		||||
 * @returns String | undefined - Query param name
 | 
			
		||||
 */
 | 
			
		||||
function getFilterParamName(paramKey, operator) {
 | 
			
		||||
  if (operator === '=') {
 | 
			
		||||
    return paramKey;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const prefix = FILTER_OPERATORS_PREFIX[operator];
 | 
			
		||||
  if (prefix) {
 | 
			
		||||
    return `${prefix}[${paramKey}]`;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return undefined;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Builds the tracing query param name for the given filter and operator
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} filterName - The filter name
 | 
			
		||||
 * @param {String} operator - The operator
 | 
			
		||||
 * @returns String | undefined - Query param name
 | 
			
		||||
 */
 | 
			
		||||
function getTracingFilterParamName(filterName, operator) {
 | 
			
		||||
  const paramKey = TRACING_FILTER_TO_QUERY_PARAM[filterName];
 | 
			
		||||
  if (!paramKey) return undefined;
 | 
			
		||||
 | 
			
		||||
  return getFilterParamName(paramKey, operator);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Process `filterValue` and append the proper query params to the  `searchParams` arg
 | 
			
		||||
 *
 | 
			
		||||
 * It mutates `searchParams`
 | 
			
		||||
 *
 | 
			
		||||
 * @param {String} filterValue The filter value, in the format `attribute_name=attribute_value`
 | 
			
		||||
 * @param {String} filterOperator The filter operator
 | 
			
		||||
 * @param {URLSearchParams} searchParams The URLSearchParams object where to append the proper query params
 | 
			
		||||
 */
 | 
			
		||||
function handleAttributeFilter(filterValue, filterOperator, searchParams) {
 | 
			
		||||
  const [attrName, attrValue] = filterValue.split('=');
 | 
			
		||||
  if (attrName && attrValue) {
 | 
			
		||||
    if (filterOperator === '=') {
 | 
			
		||||
      searchParams.append('attr_name', attrName);
 | 
			
		||||
      searchParams.append('attr_value', attrValue);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handlePeriodFilter(rawValue, filterName, filterParams) {
 | 
			
		||||
function handleTracingPeriodFilter(rawValue, filterName, filterParams) {
 | 
			
		||||
  if (rawValue.trim().indexOf(' ') < 0) {
 | 
			
		||||
    filterParams.append(filterName, rawValue.trim());
 | 
			
		||||
    return;
 | 
			
		||||
| 
						 | 
				
			
			@ -189,13 +222,14 @@ function tracingFilterObjToQueryParams(filterObj) {
 | 
			
		|||
    const validFilters = filterValues.filter((f) =>
 | 
			
		||||
      SUPPORTED_TRACING_FILTERS[filterName].includes(f.operator),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    validFilters.forEach(({ operator, value: rawValue }) => {
 | 
			
		||||
      if (filterName === 'attribute') {
 | 
			
		||||
        handleAttributeFilter(rawValue, operator, filterParams);
 | 
			
		||||
        handleAttributeFilter(rawValue, operator, filterParams, 'attr_name', 'attr_value');
 | 
			
		||||
      } else if (filterName === 'period') {
 | 
			
		||||
        handlePeriodFilter(rawValue, filterName, filterParams);
 | 
			
		||||
        handleTracingPeriodFilter(rawValue, filterName, filterParams);
 | 
			
		||||
      } else {
 | 
			
		||||
        const paramName = getTracingFilterParamName(filterName, operator);
 | 
			
		||||
        const paramName = getFilterParamName(filterName, operator, TRACING_FILTER_TO_QUERY_PARAM);
 | 
			
		||||
        let value = rawValue;
 | 
			
		||||
        if (filterName === 'durationMs') {
 | 
			
		||||
          // converting durationMs to duration_nano
 | 
			
		||||
| 
						 | 
				
			
			@ -318,6 +352,12 @@ function handleMetricsAttributeFilters(attributeFilters, params) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** ****
 | 
			
		||||
 *
 | 
			
		||||
 * Metrics API
 | 
			
		||||
 *
 | 
			
		||||
 * ***** */
 | 
			
		||||
 | 
			
		||||
async function fetchMetrics(metricsUrl, { filters = {}, limit } = {}) {
 | 
			
		||||
  try {
 | 
			
		||||
    const params = new URLSearchParams();
 | 
			
		||||
| 
						 | 
				
			
			@ -359,6 +399,7 @@ const SUPPORTED_METRICS_DIMENSIONS_OPERATORS = {
 | 
			
		|||
  '=~': 're',
 | 
			
		||||
  '!~': 'nre',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function addMetricsAttributeFilterToQueryParams(dimensionFilter, params) {
 | 
			
		||||
  if (!dimensionFilter || !params) return;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -374,21 +415,7 @@ function addMetricsAttributeFilterToQueryParams(dimensionFilter, params) {
 | 
			
		|||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addDateRangeFilterToQueryParams(dateRangeFilter, params) {
 | 
			
		||||
  if (!dateRangeFilter || !params) return;
 | 
			
		||||
 | 
			
		||||
  const { value, endDate, startDate } = dateRangeFilter;
 | 
			
		||||
  if (value === CUSTOM_DATE_RANGE_OPTION) {
 | 
			
		||||
    if (isValidDate(startDate) && isValidDate(endDate)) {
 | 
			
		||||
      params.append('start_time', startDate.toISOString());
 | 
			
		||||
      params.append('end_time', endDate.toISOString());
 | 
			
		||||
    }
 | 
			
		||||
  } else if (typeof value === 'string') {
 | 
			
		||||
    params.append('period', value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addGroupByFilterToQueryParams(groupByFilter, params) {
 | 
			
		||||
function addMetricsGroupByFilterToQueryParams(groupByFilter, params) {
 | 
			
		||||
  if (!groupByFilter || !params) return;
 | 
			
		||||
 | 
			
		||||
  const { func, attributes } = groupByFilter;
 | 
			
		||||
| 
						 | 
				
			
			@ -429,7 +456,7 @@ async function fetchMetric(searchUrl, name, type, options = {}) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (groupBy) {
 | 
			
		||||
      addGroupByFilterToQueryParams(groupBy, params);
 | 
			
		||||
      addMetricsGroupByFilterToQueryParams(groupBy, params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const { data } = await axios.get(searchUrl, {
 | 
			
		||||
| 
						 | 
				
			
			@ -470,15 +497,95 @@ async function fetchMetricSearchMetadata(searchMetadataUrl, name, type) {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** ****
 | 
			
		||||
 *
 | 
			
		||||
 * Logs API
 | 
			
		||||
 *
 | 
			
		||||
 * ***** */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Filters (and operators) allowed by logs query API
 | 
			
		||||
 */
 | 
			
		||||
const SUPPORTED_LOGS_FILTERS = {
 | 
			
		||||
  service: ['=', '!='],
 | 
			
		||||
  severityName: ['=', '!='],
 | 
			
		||||
  traceId: ['='],
 | 
			
		||||
  spanId: ['='],
 | 
			
		||||
  fingerprint: ['='],
 | 
			
		||||
  traceFlags: ['=', '!='],
 | 
			
		||||
  attribute: ['='],
 | 
			
		||||
  resourceAttribute: ['='],
 | 
			
		||||
  search: [], // 'search' filter does not have any operator
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Mapping of filter name to query param
 | 
			
		||||
 */
 | 
			
		||||
const LOGS_FILTER_TO_QUERY_PARAM = {
 | 
			
		||||
  service: 'service_name',
 | 
			
		||||
  severityName: 'severity_name',
 | 
			
		||||
  traceId: 'trace_id',
 | 
			
		||||
  spanId: 'span_id',
 | 
			
		||||
  fingerprint: 'fingerprint',
 | 
			
		||||
  traceFlags: 'trace_flags',
 | 
			
		||||
  search: 'body',
 | 
			
		||||
  // `attribute` and `resource_attribute` are handled separately
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Builds URLSearchParams from a filter object of type { [filterName]: undefined | null | Array<{operator: String, value: any} }
 | 
			
		||||
 *  e.g:
 | 
			
		||||
 *
 | 
			
		||||
 *  filterObj =  {
 | 
			
		||||
 *      severityName: [{operator: '=', value: 'info' }],
 | 
			
		||||
 *      service: [{operator: '!=', value: 'foo' }]
 | 
			
		||||
 *    }
 | 
			
		||||
 *
 | 
			
		||||
 * It handles converting the filter to the proper supported query params
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Object} filterObj : An Object representing handleAttributeFilter
 | 
			
		||||
 * @returns URLSearchParams
 | 
			
		||||
 */
 | 
			
		||||
function addLogsAttributesFiltersToQueryParams(filterObj, filterParams) {
 | 
			
		||||
  Object.keys(SUPPORTED_LOGS_FILTERS).forEach((filterName) => {
 | 
			
		||||
    const filterValues = Array.isArray(filterObj[filterName])
 | 
			
		||||
      ? filterObj[filterName].filter(({ value }) => Boolean(value)) // ignore empty strings
 | 
			
		||||
      : [];
 | 
			
		||||
    const validFilters = filterValues.filter(
 | 
			
		||||
      (f) =>
 | 
			
		||||
        (filterName === SEARCH_FILTER_NAME && SUPPORTED_LOGS_FILTERS[filterName]) ||
 | 
			
		||||
        SUPPORTED_LOGS_FILTERS[filterName].includes(f.operator),
 | 
			
		||||
    );
 | 
			
		||||
    validFilters.forEach(({ operator, value: rawValue }) => {
 | 
			
		||||
      if (filterName === 'attribute') {
 | 
			
		||||
        handleAttributeFilter(rawValue, operator, filterParams, 'log_attr_name', 'log_attr_value');
 | 
			
		||||
      } else if (filterName === 'resourceAttribute') {
 | 
			
		||||
        handleAttributeFilter(rawValue, operator, filterParams, 'res_attr_name', 'res_attr_value');
 | 
			
		||||
      } else {
 | 
			
		||||
        const paramName = getFilterParamName(filterName, operator, LOGS_FILTER_TO_QUERY_PARAM);
 | 
			
		||||
        const value = rawValue;
 | 
			
		||||
        if (paramName && value) {
 | 
			
		||||
          filterParams.append(paramName, value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  return filterParams;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function fetchLogs(logsSearchUrl, { pageToken, pageSize, filters = {} } = {}) {
 | 
			
		||||
  try {
 | 
			
		||||
    const params = new URLSearchParams();
 | 
			
		||||
 | 
			
		||||
    const { dateRange } = filters;
 | 
			
		||||
    const { dateRange, attributes } = filters;
 | 
			
		||||
    if (dateRange) {
 | 
			
		||||
      addDateRangeFilterToQueryParams(dateRange, params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (attributes) {
 | 
			
		||||
      addLogsAttributesFiltersToQueryParams(attributes, params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pageToken) {
 | 
			
		||||
      params.append('page_token', pageToken);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -501,6 +608,12 @@ export async function fetchLogs(logsSearchUrl, { pageToken, pageSize, filters =
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** ****
 | 
			
		||||
 *
 | 
			
		||||
 * ObservabilityClient
 | 
			
		||||
 *
 | 
			
		||||
 * ***** */
 | 
			
		||||
 | 
			
		||||
export function buildClient(config) {
 | 
			
		||||
  if (!config) {
 | 
			
		||||
    throw new Error('No options object provided'); // eslint-disable-line @gitlab/require-i18n-strings
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ export const avatarI18n = {
 | 
			
		|||
  uploadNewAvatar: s__('Profiles|Upload new avatar'),
 | 
			
		||||
  chooseFile: s__('Profiles|Choose file...'),
 | 
			
		||||
  noFileChosen: s__('Profiles|No file chosen.'),
 | 
			
		||||
  maximumFileSize: s__('Profiles|The maximum file size allowed is 200KB.'),
 | 
			
		||||
  maximumFileSize: s__('Profiles|The maximum file size allowed is 200 KiB.'),
 | 
			
		||||
  imageDimensions: s__('Profiles|The ideal image size is 192 x 192 pixels.'),
 | 
			
		||||
  removeAvatar: s__('Profiles|Remove avatar'),
 | 
			
		||||
  removeAvatarConfirmation: s__('Profiles|Avatar will be removed. Are you sure?'),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,15 +14,14 @@ import Vue from 'vue';
 | 
			
		|||
 * @returns {HTMLElement}
 | 
			
		||||
 */
 | 
			
		||||
export const renderVueComponentForLegacyJS = (Component, data, children) => {
 | 
			
		||||
  const mountEl = document.createElement('div');
 | 
			
		||||
 | 
			
		||||
  const vm = new Vue({
 | 
			
		||||
    el: mountEl,
 | 
			
		||||
    render(h) {
 | 
			
		||||
      return h(Component, data, children);
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  vm.$mount();
 | 
			
		||||
 | 
			
		||||
  // Ensure it's rendered
 | 
			
		||||
  vm.$forceUpdate();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ export default {
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <h5 :id="labelId" class="gl-mt-0 gl-mb-5 gl-font-sm">
 | 
			
		||||
    <h5 :id="labelId" class="gl-mt-0 gl-mb-2 gl-font-sm">
 | 
			
		||||
      {{ $options.i18n.groupFieldLabel }}
 | 
			
		||||
    </h5>
 | 
			
		||||
    <searchable-dropdown
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ export default {
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <h5 :id="labelId" class="gl-mt-0 gl-mb-5 gl-font-sm">
 | 
			
		||||
    <h5 :id="labelId" class="gl-mt-0 gl-mb-2 gl-font-sm">
 | 
			
		||||
      {{ $options.i18n.projectFieldLabel }}
 | 
			
		||||
    </h5>
 | 
			
		||||
    <searchable-dropdown
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ export default {
 | 
			
		|||
  i18n: {
 | 
			
		||||
    searchPlaceholder: s__(`GlobalSearch|Search for projects, issues, etc.`),
 | 
			
		||||
    searchLabel: s__(`GlobalSearch|What are you searching for?`),
 | 
			
		||||
    syntaxOptionsLabel: s__('GlobalSearch|Syntax options'),
 | 
			
		||||
    syntaxOptionsLabel: s__('GlobalSearch|View syntax options.'),
 | 
			
		||||
    groupFieldLabel: s__('GlobalSearch|Group'),
 | 
			
		||||
    projectFieldLabel: s__('GlobalSearch|Project'),
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			@ -102,35 +102,21 @@ export default {
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <section>
 | 
			
		||||
    <div
 | 
			
		||||
      class="gl-lg-display-flex gl-flex-direction-row gl-py-5"
 | 
			
		||||
      :class="{
 | 
			
		||||
        'gl-justify-content-space-between': showSyntaxOptions,
 | 
			
		||||
        'gl-justify-content-end': !showSyntaxOptions,
 | 
			
		||||
      }"
 | 
			
		||||
    >
 | 
			
		||||
    <div class="search-page-form gl-mt-5">
 | 
			
		||||
      <search-type-indicator />
 | 
			
		||||
      <template v-if="showSyntaxOptions">
 | 
			
		||||
        <div>
 | 
			
		||||
          <gl-button
 | 
			
		||||
            category="tertiary"
 | 
			
		||||
            variant="link"
 | 
			
		||||
            size="small"
 | 
			
		||||
            button-text-classes="gl-font-sm!"
 | 
			
		||||
            @click="onToggleDrawer"
 | 
			
		||||
        <div class="gl-display-inline-block">
 | 
			
		||||
          <gl-button category="tertiary" variant="link" @click="onToggleDrawer"
 | 
			
		||||
            >{{ $options.i18n.syntaxOptionsLabel }}
 | 
			
		||||
          </gl-button>
 | 
			
		||||
        </div>
 | 
			
		||||
        <markdown-drawer ref="markdownDrawer" :document-path="documentBasedOnSearchType" />
 | 
			
		||||
      </template>
 | 
			
		||||
      <search-type-indicator />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="search-page-form gl-lg-display-flex gl-flex-direction-column">
 | 
			
		||||
      <div class="gl-lg-display-flex gl-flex-direction-row gl-align-items-flex-start">
 | 
			
		||||
        <div class="gl-flex-grow-1 gl-pb-8 gl-lg-mb-0 gl-lg-mr-2">
 | 
			
		||||
      <gl-search-box-by-type
 | 
			
		||||
        id="dashboard_search"
 | 
			
		||||
        v-model="search"
 | 
			
		||||
        name="search"
 | 
			
		||||
        class="gl-mt-2"
 | 
			
		||||
        :regex-button-is-visible="isRegexButtonVisible"
 | 
			
		||||
        :regex-button-state="regexEnabled"
 | 
			
		||||
        :regex-button-handler="regexButtonHandler"
 | 
			
		||||
| 
						 | 
				
			
			@ -138,7 +124,5 @@ export default {
 | 
			
		|||
        @keydown.enter.stop.prevent="applyQuery"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ export default {
 | 
			
		|||
  },
 | 
			
		||||
  i18n: {
 | 
			
		||||
    zoekt_enabled: s__(
 | 
			
		||||
      'GlobalSearch|%{linkStart}Exact code search (powered by Zoekt)%{linkEnd} is enabled',
 | 
			
		||||
      'GlobalSearch|%{linkStart}Exact code search (powered by Zoekt)%{linkEnd} is enabled.',
 | 
			
		||||
    ),
 | 
			
		||||
    zoekt_disabled: s__(
 | 
			
		||||
      'GlobalSearch|%{linkStart}Exact code search (powered by Zoekt)%{linkEnd} is disabled since %{ref_elem} is not the default branch. %{docs_link}',
 | 
			
		||||
| 
						 | 
				
			
			@ -119,16 +119,16 @@ export default {
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="gl-text-gray-600">
 | 
			
		||||
    <div v-if="isBasicSearch" data-testid="basic"> </div>
 | 
			
		||||
    <div v-else-if="isEnabled" :data-testid="`${searchTypeTestId}-enabled`">
 | 
			
		||||
  <div class="gl-inline gl-text-gray-600">
 | 
			
		||||
    <div v-if="isBasicSearch" data-testid="basic"></div>
 | 
			
		||||
    <div v-else-if="isEnabled" :data-testid="`${searchTypeTestId}-enabled`" class="gl-inline">
 | 
			
		||||
      <gl-sprintf :message="enabledMessage">
 | 
			
		||||
        <template #link="{ content }">
 | 
			
		||||
          <gl-link :href="helpUrl" target="_blank" data-testid="docs-link">{{ content }}</gl-link>
 | 
			
		||||
        </template>
 | 
			
		||||
      </gl-sprintf>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-else :data-testid="`${searchTypeTestId}-disabled`">
 | 
			
		||||
    <div v-else :data-testid="`${searchTypeTestId}-disabled`" class="gl-inline">
 | 
			
		||||
      <gl-sprintf :message="disabledMessage">
 | 
			
		||||
        <template #link="{ content }">
 | 
			
		||||
          <gl-link :href="helpUrl" target="_blank" data-testid="docs-link">{{ content }}</gl-link>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
/* eslint-disable no-restricted-imports */
 | 
			
		||||
import {
 | 
			
		||||
  BrowserClient,
 | 
			
		||||
  getCurrentHub,
 | 
			
		||||
| 
						 | 
				
			
			@ -9,7 +10,7 @@ import {
 | 
			
		|||
  // exports
 | 
			
		||||
  captureException,
 | 
			
		||||
  SDK_VERSION,
 | 
			
		||||
} from 'sentrybrowser';
 | 
			
		||||
} from '@sentry/browser';
 | 
			
		||||
 | 
			
		||||
const initSentry = () => {
 | 
			
		||||
  if (!gon?.sentry_dsn) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,46 +0,0 @@
 | 
			
		|||
import { __ } from '~/locale';
 | 
			
		||||
 | 
			
		||||
// https://docs.sentry.io/platforms/javascript/configuration/filtering/#decluttering-sentry
 | 
			
		||||
export const IGNORE_ERRORS = [
 | 
			
		||||
  // Random plugins/extensions
 | 
			
		||||
  'top.GLOBALS',
 | 
			
		||||
  // See: http://blog.errorception.com/2012/03/tale-of-unfindable-js-error. html
 | 
			
		||||
  'originalCreateNotification',
 | 
			
		||||
  'canvas.contentDocument',
 | 
			
		||||
  'MyApp_RemoveAllHighlights',
 | 
			
		||||
  'http://tt.epicplay.com',
 | 
			
		||||
  __("Can't find variable: ZiteReader"),
 | 
			
		||||
  __('jigsaw is not defined'),
 | 
			
		||||
  __('ComboSearch is not defined'),
 | 
			
		||||
  'http://loading.retry.widdit.com/',
 | 
			
		||||
  'atomicFindClose',
 | 
			
		||||
  // Facebook borked
 | 
			
		||||
  'fb_xd_fragment',
 | 
			
		||||
  // ISP "optimizing" proxy - `Cache-Control: no-transform` seems to
 | 
			
		||||
  // reduce this. (thanks @acdha)
 | 
			
		||||
  'bmi_SafeAddOnload',
 | 
			
		||||
  'EBCallBackMessageReceived',
 | 
			
		||||
  // See http://toolbar.conduit.com/Developer/HtmlAndGadget/Methods/JSInjection.aspx
 | 
			
		||||
  'conduitPage',
 | 
			
		||||
  // Exclude errors from polling when navigating away from a page
 | 
			
		||||
  'TypeError: Failed to fetch',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const DENY_URLS = [
 | 
			
		||||
  // Facebook flakiness
 | 
			
		||||
  /graph\.facebook\.com/i,
 | 
			
		||||
  // Facebook blocked
 | 
			
		||||
  /connect\.facebook\.net\/en_US\/all\.js/i,
 | 
			
		||||
  // Woopra flakiness
 | 
			
		||||
  /eatdifferent\.com\.woopra-ns\.com/i,
 | 
			
		||||
  /static\.woopra\.com\/js\/woopra\.js/i,
 | 
			
		||||
  // Chrome extensions
 | 
			
		||||
  /extensions\//i,
 | 
			
		||||
  /^chrome:\/\//i,
 | 
			
		||||
  // Other plugins
 | 
			
		||||
  /127\.0\.0\.1:4001\/isrunning/i, // Cacaoweb
 | 
			
		||||
  /webappstoolbarba\.texthelp\.com\//i,
 | 
			
		||||
  /metrics\.itunes\.apple\.com\.edgesuite\.net\//i,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const SAMPLE_RATE = 0.95;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +0,0 @@
 | 
			
		|||
import '../webpack';
 | 
			
		||||
 | 
			
		||||
import * as Sentry5 from 'sentrybrowser5';
 | 
			
		||||
import LegacySentryConfig from './legacy_sentry_config';
 | 
			
		||||
 | 
			
		||||
const index = function index() {
 | 
			
		||||
  // Configuration for legacy versions of Sentry SDK (v5)
 | 
			
		||||
  LegacySentryConfig.init({
 | 
			
		||||
    dsn: gon.sentry_dsn,
 | 
			
		||||
    currentUserId: gon.current_user_id,
 | 
			
		||||
    whitelistUrls:
 | 
			
		||||
      process.env.NODE_ENV === 'production'
 | 
			
		||||
        ? [gon.gitlab_url]
 | 
			
		||||
        : [gon.gitlab_url, 'webpack-internal://'],
 | 
			
		||||
    environment: gon.sentry_environment,
 | 
			
		||||
    release: gon.revision,
 | 
			
		||||
    tags: {
 | 
			
		||||
      revision: gon.revision,
 | 
			
		||||
      feature_category: gon.feature_category,
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
index();
 | 
			
		||||
 | 
			
		||||
// The _Sentry object is globally exported so it can be used by
 | 
			
		||||
//   ./sentry_browser_wrapper.js
 | 
			
		||||
// This hack allows us to load a single version of `~/sentry/sentry_browser_wrapper`
 | 
			
		||||
// in the browser, see app/views/layouts/_head.html.haml to find how it is imported.
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line no-underscore-dangle
 | 
			
		||||
window._Sentry = Sentry5;
 | 
			
		||||
 | 
			
		||||
export default index;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,64 +0,0 @@
 | 
			
		|||
import * as Sentry5 from 'sentrybrowser5';
 | 
			
		||||
import $ from 'jquery';
 | 
			
		||||
import { __ } from '~/locale';
 | 
			
		||||
import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './legacy_constants';
 | 
			
		||||
 | 
			
		||||
const SentryConfig = {
 | 
			
		||||
  IGNORE_ERRORS,
 | 
			
		||||
  DENYLIST_URLS: DENY_URLS,
 | 
			
		||||
  SAMPLE_RATE,
 | 
			
		||||
  init(options = {}) {
 | 
			
		||||
    this.options = options;
 | 
			
		||||
 | 
			
		||||
    this.configure();
 | 
			
		||||
    this.bindSentryErrors();
 | 
			
		||||
    if (this.options.currentUserId) this.setUser();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  configure() {
 | 
			
		||||
    const { dsn, release, tags, whitelistUrls, environment } = this.options;
 | 
			
		||||
 | 
			
		||||
    Sentry5.init({
 | 
			
		||||
      dsn,
 | 
			
		||||
      release,
 | 
			
		||||
      whitelistUrls,
 | 
			
		||||
      environment,
 | 
			
		||||
      ignoreErrors: this.IGNORE_ERRORS, // TODO: Remove in favor of https://gitlab.com/gitlab-org/gitlab/issues/35144
 | 
			
		||||
      blacklistUrls: this.DENYLIST_URLS,
 | 
			
		||||
      sampleRate: SAMPLE_RATE,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    Sentry5.setTags(tags);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  setUser() {
 | 
			
		||||
    Sentry5.setUser({
 | 
			
		||||
      id: this.options.currentUserId,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  bindSentryErrors() {
 | 
			
		||||
    $(document).on('ajaxError.sentry', this.handleSentryErrors);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleSentryErrors(event, req, config, err) {
 | 
			
		||||
    const error = err || req.statusText;
 | 
			
		||||
    const { responseText = __('Unknown response text') } = req;
 | 
			
		||||
    const { type, url, data } = config;
 | 
			
		||||
    const { status } = req;
 | 
			
		||||
 | 
			
		||||
    Sentry5.captureMessage(error, {
 | 
			
		||||
      extra: {
 | 
			
		||||
        type,
 | 
			
		||||
        url,
 | 
			
		||||
        data,
 | 
			
		||||
        status,
 | 
			
		||||
        response: responseText,
 | 
			
		||||
        error,
 | 
			
		||||
        event,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default SentryConfig;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
import $ from 'jquery';
 | 
			
		||||
import { GlButton } from '@gitlab/ui';
 | 
			
		||||
import { createAlert } from '~/alert';
 | 
			
		||||
import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
 | 
			
		||||
import { renderVueComponentForLegacyJS } from '~/render_vue_component_for_legacy_js';
 | 
			
		||||
import { spriteIcon } from '~/lib/utils/common_utils';
 | 
			
		||||
import FilesCommentButton from './files_comment_button';
 | 
			
		||||
import initImageDiffHelper from './image_diff/helpers/init_image_diff';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,8 +16,15 @@ const ERROR_HTML = `<div class="nothing-here-block">${spriteIcon(
 | 
			
		|||
  'warning-solid',
 | 
			
		||||
  's16',
 | 
			
		||||
)} Could not load diff</div>`;
 | 
			
		||||
const COLLAPSED_HTML =
 | 
			
		||||
  '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <button class="click-to-expand btn btn-link gl-button">Click to expand it.</button></div>';
 | 
			
		||||
const CLICK_TO_EXPAND_BUTTON_HTML = renderVueComponentForLegacyJS(
 | 
			
		||||
  GlButton,
 | 
			
		||||
  {
 | 
			
		||||
    class: 'click-to-expand',
 | 
			
		||||
    props: { variant: 'link' },
 | 
			
		||||
  },
 | 
			
		||||
  __('Click to expand it.'),
 | 
			
		||||
).outerHTML;
 | 
			
		||||
const COLLAPSED_HTML = `<div class="nothing-here-block diff-collapsed">This diff is collapsed. ${CLICK_TO_EXPAND_BUTTON_HTML}</div>`;
 | 
			
		||||
 | 
			
		||||
export default class SingleFileDiff {
 | 
			
		||||
  constructor(file) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
 | 
			
		|||
export default {
 | 
			
		||||
  i18n: {
 | 
			
		||||
    uploadText: __('Drop or %{linkStart}upload%{linkEnd} an avatar.'),
 | 
			
		||||
    maxFileSize: s__('Profiles|The maximum file size allowed is 200KB.'),
 | 
			
		||||
    maxFileSize: s__('Profiles|The maximum file size allowed is 200 KiB.'),
 | 
			
		||||
    imageDimensions: s__('Profiles|The ideal image size is 192 x 192 pixels.'),
 | 
			
		||||
    removeAvatar: __('Remove avatar'),
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,15 @@
 | 
			
		|||
module ApplicationCable
 | 
			
		||||
  class Channel < ActionCable::Channel::Base
 | 
			
		||||
    include Logging
 | 
			
		||||
    include Gitlab::Auth::AuthFinders
 | 
			
		||||
 | 
			
		||||
    before_subscribe :validate_token_scope
 | 
			
		||||
 | 
			
		||||
    def validate_token_scope
 | 
			
		||||
      validate_access_token!(scopes: [:api, :read_api])
 | 
			
		||||
    rescue Gitlab::Auth::InsufficientScopeError
 | 
			
		||||
      reject
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,8 @@ class GraphqlChannel < ApplicationCable::Channel # rubocop:disable Gitlab/Namesp
 | 
			
		|||
  # Objects added to the context may also need to be reloaded in
 | 
			
		||||
  # `Subscriptions::BaseSubscription` so that they are not stale
 | 
			
		||||
  def context
 | 
			
		||||
    # is_sessionless_user is always false because we only support cookie auth in ActionCable
 | 
			
		||||
    { channel: self, current_user: current_user, is_sessionless_user: false }
 | 
			
		||||
    request_authenticator = Gitlab::Auth::RequestAuthenticator.new(request)
 | 
			
		||||
    scope_validator = ::Gitlab::Auth::ScopeValidator.new(current_user, request_authenticator)
 | 
			
		||||
    { channel: self, current_user: current_user, is_sessionless_user: false, scope_validator: scope_validator }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -222,6 +222,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		|||
    else
 | 
			
		||||
      fail_login(@user)
 | 
			
		||||
    end
 | 
			
		||||
  rescue Gitlab::Auth::OAuth::User::IdentityWithUntrustedExternUidError
 | 
			
		||||
    handle_identity_with_untrusted_extern_uid
 | 
			
		||||
  rescue Gitlab::Auth::OAuth::User::SigninDisabledForProviderError
 | 
			
		||||
    handle_disabled_provider
 | 
			
		||||
  rescue Gitlab::Auth::OAuth::User::SignupDisabledError
 | 
			
		||||
| 
						 | 
				
			
			@ -271,6 +273,13 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		|||
    redirect_to profile_account_path, notice: _('Request to link SAML account must be authorized')
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_identity_with_untrusted_extern_uid
 | 
			
		||||
    label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider'])
 | 
			
		||||
    flash[:alert] = format(_("Signing in using your %{label} account has been disabled for security reasons. Please sign in to your GitLab account using another authentication method and reconnect to your %{label} account."), label: label)
 | 
			
		||||
 | 
			
		||||
    redirect_to new_user_session_path
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_disabled_provider
 | 
			
		||||
    label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider'])
 | 
			
		||||
    flash[:alert] = _("Signing in using %{label} has been disabled") % { label: label }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,7 +174,7 @@ module Resolvers
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def self.authorized?(object, context)
 | 
			
		||||
      authorization.ok?(object, context[:current_user])
 | 
			
		||||
      authorization.ok?(object, context[:current_user], scope_validator: context[:scope_validator])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ module Types
 | 
			
		|||
      end
 | 
			
		||||
 | 
			
		||||
      def authorized?(object, context)
 | 
			
		||||
        authorization.ok?(object, context[:current_user])
 | 
			
		||||
        authorization.ok?(object, context[:current_user], scope_validator: context[:scope_validator])
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ module Types
 | 
			
		|||
    def field_authorized?(object, ctx)
 | 
			
		||||
      object = object.node if object.is_a?(GraphQL::Pagination::Connection::Edge)
 | 
			
		||||
 | 
			
		||||
      authorization.ok?(object, ctx[:current_user])
 | 
			
		||||
      authorization.ok?(object, ctx[:current_user], scope_validator: ctx[:scope_validator])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Historically our resolvers have used declarative permission checks only
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ module Types
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def self.authorized?(object, context)
 | 
			
		||||
      authorization.ok?(object, context[:current_user])
 | 
			
		||||
      authorization.ok?(object, context[:current_user], scope_validator: context[:scope_validator])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def current_user
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -411,6 +411,9 @@ module ApplicationSettingsHelper
 | 
			
		|||
      :throttle_unauthenticated_files_api_enabled,
 | 
			
		||||
      :throttle_unauthenticated_files_api_period_in_seconds,
 | 
			
		||||
      :throttle_unauthenticated_files_api_requests_per_period,
 | 
			
		||||
      :throttle_unauthenticated_git_http_enabled,
 | 
			
		||||
      :throttle_unauthenticated_git_http_period_in_seconds,
 | 
			
		||||
      :throttle_unauthenticated_git_http_requests_per_period,
 | 
			
		||||
      :throttle_unauthenticated_deprecated_api_enabled,
 | 
			
		||||
      :throttle_unauthenticated_deprecated_api_period_in_seconds,
 | 
			
		||||
      :throttle_unauthenticated_deprecated_api_requests_per_period,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -553,6 +553,8 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
 | 
			
		|||
      :throttle_unauthenticated_deprecated_api_requests_per_period,
 | 
			
		||||
      :throttle_unauthenticated_files_api_period_in_seconds,
 | 
			
		||||
      :throttle_unauthenticated_files_api_requests_per_period,
 | 
			
		||||
      :throttle_unauthenticated_git_http_period_in_seconds,
 | 
			
		||||
      :throttle_unauthenticated_git_http_requests_per_period,
 | 
			
		||||
      :throttle_unauthenticated_packages_api_period_in_seconds,
 | 
			
		||||
      :throttle_unauthenticated_packages_api_requests_per_period,
 | 
			
		||||
      :throttle_unauthenticated_period_in_seconds,
 | 
			
		||||
| 
						 | 
				
			
			@ -612,6 +614,11 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
 | 
			
		|||
  jsonb_accessor :service_ping_settings,
 | 
			
		||||
    gitlab_environment_toolkit_instance: [:boolean, { default: false }]
 | 
			
		||||
 | 
			
		||||
  jsonb_accessor :rate_limits_unauthenticated_git_http,
 | 
			
		||||
    throttle_unauthenticated_git_http_enabled: [:boolean, { default: false }],
 | 
			
		||||
    throttle_unauthenticated_git_http_requests_per_period: [:integer, { default: 3600 }],
 | 
			
		||||
    throttle_unauthenticated_git_http_period_in_seconds: [:integer, { default: 3600 }]
 | 
			
		||||
 | 
			
		||||
  validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" }
 | 
			
		||||
 | 
			
		||||
  validates :search_rate_limit_allowlist,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2148,8 +2148,12 @@ class MergeRequest < ApplicationRecord
 | 
			
		|||
    merge_request_reviewers.where(user_id: user_ids)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def has_changes_requested?
 | 
			
		||||
    merge_request_reviewers.exists?(state: :requested_changes)
 | 
			
		||||
  def create_requested_changes(user)
 | 
			
		||||
    # Overridden in EE
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy_requested_changes(user)
 | 
			
		||||
    # Overridden in EE
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def batch_update_reviewer_state(user_ids, state)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -320,7 +320,7 @@ class User < MainClusterwide::ApplicationRecord
 | 
			
		|||
  validates :name, presence: true, length: { maximum: 255 }
 | 
			
		||||
  validates :first_name, length: { maximum: 127 }
 | 
			
		||||
  validates :last_name, length: { maximum: 127 }
 | 
			
		||||
  validates :email, confirmation: true
 | 
			
		||||
  validates :email, confirmation: true, devise_email: true
 | 
			
		||||
  validates :notification_email, devise_email: true, allow_blank: true
 | 
			
		||||
  validates :public_email, uniqueness: true, devise_email: true, allow_blank: true
 | 
			
		||||
  validates :commit_email, devise_email: true, allow_blank: true, unless: ->(user) { user.commit_email == Gitlab::PrivateCommitEmail::TOKEN }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,7 +13,7 @@ module MergeRequests
 | 
			
		|||
 | 
			
		||||
      return success unless save_approval(approval)
 | 
			
		||||
 | 
			
		||||
      update_reviewer_state(merge_request, current_user, :approved)
 | 
			
		||||
      update_reviewer_state(merge_request, current_user, 'approved')
 | 
			
		||||
 | 
			
		||||
      reset_approvals_cache(merge_request)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ module MergeRequests
 | 
			
		|||
      trigger_approval_hooks(merge_request, skip_notification) do
 | 
			
		||||
        next unless approval.destroy_all # rubocop: disable Cop/DestroyAll
 | 
			
		||||
 | 
			
		||||
        update_reviewer_state(merge_request, current_user, :unapproved) unless skip_updating_state
 | 
			
		||||
        update_reviewer_state(merge_request, current_user, 'unapproved') unless skip_updating_state
 | 
			
		||||
        reset_approvals_cache(merge_request)
 | 
			
		||||
 | 
			
		||||
        unless skip_system_note
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,8 +12,12 @@ module MergeRequests
 | 
			
		|||
 | 
			
		||||
        trigger_merge_request_reviewers_updated(merge_request)
 | 
			
		||||
 | 
			
		||||
        destroy_requested_changes(merge_request) if state == 'approved'
 | 
			
		||||
 | 
			
		||||
        return success if state != 'requested_changes'
 | 
			
		||||
 | 
			
		||||
        create_requested_changes(merge_request)
 | 
			
		||||
 | 
			
		||||
        if merge_request.approved_by?(current_user) && !remove_approval(merge_request, current_user)
 | 
			
		||||
          return error("Failed to remove approval")
 | 
			
		||||
        end
 | 
			
		||||
| 
						 | 
				
			
			@ -23,5 +27,17 @@ module MergeRequests
 | 
			
		|||
        error("Reviewer not found")
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def create_requested_changes(merge_request)
 | 
			
		||||
      merge_request.create_requested_changes(current_user)
 | 
			
		||||
 | 
			
		||||
      trigger_merge_request_merge_status_updated(merge_request)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy_requested_changes(merge_request)
 | 
			
		||||
      merge_request.destroy_requested_changes(current_user)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,8 @@
 | 
			
		|||
#   end
 | 
			
		||||
class DeviseEmailValidator < ActiveModel::EachValidator
 | 
			
		||||
  DEFAULT_OPTIONS = {
 | 
			
		||||
    regexp: Devise.email_regexp
 | 
			
		||||
    regexp: Devise.email_regexp,
 | 
			
		||||
    invalid_characters_regexp: %r{[?!#$%&*\/=^<>]}
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  def initialize(options)
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +32,14 @@ class DeviseEmailValidator < ActiveModel::EachValidator
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_each(record, attribute, value)
 | 
			
		||||
    record.errors.add(attribute, :invalid) unless options[:regexp].match?(value)
 | 
			
		||||
    return if record.errors.include?(attribute)
 | 
			
		||||
 | 
			
		||||
    record.errors.add(attribute, :invalid) unless valid_email?(value)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def valid_email?(value)
 | 
			
		||||
    options[:regexp].match?(value) && !options[:invalid_characters_regexp].match?(value)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
= gitlab_ui_form_for @application_setting, url: network_admin_application_settings_path(anchor: 'js-git-http-limits-settings'), html: { class: 'fieldset-form' } do |f|
 | 
			
		||||
  = form_errors(@application_setting)
 | 
			
		||||
 | 
			
		||||
  %fieldset
 | 
			
		||||
    %h5
 | 
			
		||||
      = _('Unauthenticated Git HTTP request rate limit')
 | 
			
		||||
    .form-group
 | 
			
		||||
      = f.gitlab_ui_checkbox_component :throttle_unauthenticated_git_http_enabled,
 | 
			
		||||
        _('Enable unauthenticated Git HTTP request rate limit'),
 | 
			
		||||
        help_text: _('Helps reduce unauthenticated Git HTTP request volume for git paths.')
 | 
			
		||||
    .form-group
 | 
			
		||||
      = f.label :throttle_unauthenticated_git_http_requests_per_period, _('Maximum unauthenticated Git HTTP requests per period per IP'), class: 'gl-font-weight-bold'
 | 
			
		||||
      = f.number_field :throttle_unauthenticated_git_http_requests_per_period, class: 'form-control gl-form-input'
 | 
			
		||||
    .form-group
 | 
			
		||||
      = f.label :throttle_unauthenticated_git_http_period_in_seconds, _('Unauthenticated Git HTTP rate limit period in seconds'), class: 'gl-font-weight-bold'
 | 
			
		||||
      = f.number_field :throttle_unauthenticated_git_http_period_in_seconds, class: 'form-control gl-form-input'
 | 
			
		||||
 | 
			
		||||
  = f.submit _('Save changes'), pajamas_button: true
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,6 @@
 | 
			
		|||
= gitlab_ui_form_for @application_setting, url: metrics_and_profiling_admin_application_settings_path(anchor: 'js-sentry-settings'), html: { class: 'fieldset-form', id: 'sentry-settings' } do |f|
 | 
			
		||||
  = form_errors(@application_setting)
 | 
			
		||||
 | 
			
		||||
  - if Feature.disabled?(:enable_new_sentry_integration)
 | 
			
		||||
    %fieldset.gl-text-secondary
 | 
			
		||||
      = safe_format(s_('AdminSettings|GitLab uses the %{bold_start}Rails%{bold_end} and %{bold_start}Browser JavaScript%{bold_end} Sentry SDKs to send events to Sentry. For changes to Rails integration settings to take effect, enable the %{code_start}enable_new_sentry_integration%{code_end} feature flag and restart GitLab.'), tag_pair(tag.b, :bold_start, :bold_end), tag_pair(tag.code, :code_start, :code_end))
 | 
			
		||||
  - else
 | 
			
		||||
  %fieldset.gl-text-secondary
 | 
			
		||||
    = safe_format(s_('AdminSettings|GitLab uses the %{bold_start}Rails%{bold_end} and %{bold_start}Browser JavaScript%{bold_end} Sentry SDKs to send events to Sentry. For changes to Rails integration settings to take effect, restart GitLab.'), tag_pair(tag.b, :bold_start, :bold_end))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,18 @@
 | 
			
		|||
  .settings-content
 | 
			
		||||
    = render partial: 'network_rate_limits', locals: { anchor: 'js-deprecated-limits-settings', setting_fragment: 'deprecated_api' }
 | 
			
		||||
 | 
			
		||||
%section.settings.as-git-http-limits.no-animate#js-git-http-limits-settings{ class: ('expanded' if expanded_by_default?) }
 | 
			
		||||
  .settings-header
 | 
			
		||||
    %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
 | 
			
		||||
      = _('Git HTTP rate limits')
 | 
			
		||||
    = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
 | 
			
		||||
      = expanded_by_default? ? _('Collapse') : _('Expand')
 | 
			
		||||
    %p.gl-text-secondary
 | 
			
		||||
      = _('Configure specific limits for Git HTTP requests.')
 | 
			
		||||
      = link_to _('Learn more.'), help_page_path('administration/settings/git_http_rate_limits'), target: '_blank', rel: 'noopener noreferrer'
 | 
			
		||||
  .settings-content
 | 
			
		||||
    = render 'git_http_limits'
 | 
			
		||||
 | 
			
		||||
%section.settings.as-git-lfs-limits.no-animate#js-git-lfs-limits-settings{ class: ('expanded' if expanded_by_default?) }
 | 
			
		||||
  .settings-header
 | 
			
		||||
    %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,10 +48,8 @@
 | 
			
		|||
  = render 'layouts/loading_hints'
 | 
			
		||||
 | 
			
		||||
  = render_if_exists 'layouts/header/translations'
 | 
			
		||||
  - if Feature.enabled?(:enable_new_sentry_integration) && Gitlab::CurrentSettings.sentry_enabled
 | 
			
		||||
  - if Gitlab::CurrentSettings.sentry_enabled
 | 
			
		||||
    = webpack_bundle_tag 'sentry'
 | 
			
		||||
  - elsif Gitlab.config.sentry.enabled
 | 
			
		||||
    = webpack_bundle_tag 'legacy_sentry'
 | 
			
		||||
  = webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
 | 
			
		||||
 | 
			
		||||
  = yield :page_specific_javascripts
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,5 @@
 | 
			
		|||
.section{ class: ('gl-lg-display-none' if @search_objects.to_a.empty?) }
 | 
			
		||||
  .search-results-status
 | 
			
		||||
    .gl-display-flex.gl-flex-direction-column
 | 
			
		||||
      .gl-p-5.gl-display-flex.gl-flex-wrap
 | 
			
		||||
.search-results-status.gl-sm-display-flex.gl-flex-wrap.gl-justify-content-space-between.gl-my-4{ class: ('gl-lg-display-none' if @search_objects.to_a.empty?) }
 | 
			
		||||
  - unless @search_objects.to_a.empty?
 | 
			
		||||
          .gl-display-flex.gl-text-left.gl-flex-grow-1.gl-flex-shrink-1.gl-white-space-nowrap.gl-flex-wrap.gl-sm-w-half
 | 
			
		||||
    %p.gl-text-truncate.gl-my-auto
 | 
			
		||||
      - unless @search_service_presenter.without_count?
 | 
			
		||||
        = search_entries_info(@search_objects, @scope, @search_term)
 | 
			
		||||
| 
						 | 
				
			
			@ -21,10 +17,9 @@
 | 
			
		|||
        - elsif @group
 | 
			
		||||
          - link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
 | 
			
		||||
          = _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
 | 
			
		||||
        .gl-display-flex.gl-my-3.gl-flex-grow-1.gl-flex-shrink-1.gl-justify-content-end
 | 
			
		||||
  .gl-display-flex
 | 
			
		||||
    = render Pajamas::ButtonComponent.new(category: 'primary', icon: 'filter', button_options: {id: 'js-open-mobile-filters', class: 'gl-lg-display-none'}) do
 | 
			
		||||
      = s_('GlobalSearch|Filters')
 | 
			
		||||
    - if @search_service_presenter.show_sort_dropdown? && !@search_objects.to_a.empty?
 | 
			
		||||
      .gl-ml-3
 | 
			
		||||
        #js-search-sort{ data: { "search-sort-options" => search_sort_options.to_json } }
 | 
			
		||||
    %hr.gl-mb-5.gl-mt-0.gl-border-gray-100.gl-w-full
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
%div{ class: 'search-result-row gl-display-flex gl-sm-flex-direction-row gl-flex-direction-column gl-align-items-center gl-pb-5! gl-mt-5 gl-mb-0!' }
 | 
			
		||||
.search-result-row.row.gl-display-flex.gl-sm-flex-direction-row.gl-flex-direction-column.gl-align-items-center.gl-mt-5{ class: 'gl-pb-5! gl-mb-0!' }
 | 
			
		||||
  .col-sm-9
 | 
			
		||||
    %span.gl-display-flex.gl-align-items-center
 | 
			
		||||
      = gl_badge_tag issuable_state_text(issuable), variant: issuable_state_to_badge_class(issuable), size: :sm
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
= render 'shared/file_picker_button', f: f, field: :avatar, help_text: s_("Profiles|The ideal image size is 192 x 192 pixels.") + " " + s_("Profiles|The maximum file size allowed is 200KB.")
 | 
			
		||||
= render 'shared/file_picker_button', f: f, field: :avatar, help_text: s_("Profiles|The ideal image size is 192 x 192 pixels.") + " " + s_("Profiles|The maximum file size allowed is 200 KiB.")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@
 | 
			
		|||
        = f.file_field :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*'
 | 
			
		||||
      .gl-text-gray-500
 | 
			
		||||
        = s_("Profiles|The ideal image size is 192 x 192 pixels.")
 | 
			
		||||
        = s_("Profiles|The maximum file size allowed is 200KB.")
 | 
			
		||||
        = s_("Profiles|The maximum file size allowed is 200 KiB.")
 | 
			
		||||
      - if @user.avatar?
 | 
			
		||||
        = render Pajamas::ButtonComponent.new(variant: :danger,
 | 
			
		||||
          category: :secondary,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
name: enable_new_sentry_integration
 | 
			
		||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72428
 | 
			
		||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344832
 | 
			
		||||
milestone: '14.9'
 | 
			
		||||
type: development
 | 
			
		||||
group: group::pipeline execution
 | 
			
		||||
default_enabled: false
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
---
 | 
			
		||||
name: enable_old_sentry_integration
 | 
			
		||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72428
 | 
			
		||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344832
 | 
			
		||||
milestone: '14.9'
 | 
			
		||||
type: development
 | 
			
		||||
group: group::pipeline execution
 | 
			
		||||
default_enabled: true
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
---
 | 
			
		||||
name: native_header_anchors
 | 
			
		||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/440733
 | 
			
		||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144690
 | 
			
		||||
rollout_issue_url:
 | 
			
		||||
milestone: '17.0'
 | 
			
		||||
group: group::project management
 | 
			
		||||
type: gitlab_com_derisk
 | 
			
		||||
default_enabled: false
 | 
			
		||||
| 
						 | 
				
			
			@ -245,6 +245,16 @@ merge_request_metrics:
 | 
			
		|||
  - table: ci_pipelines
 | 
			
		||||
    column: pipeline_id
 | 
			
		||||
    on_delete: async_nullify
 | 
			
		||||
merge_request_requested_changes:
 | 
			
		||||
  - table: merge_requests
 | 
			
		||||
    column: merge_request_id
 | 
			
		||||
    on_delete: async_delete
 | 
			
		||||
  - table: projects
 | 
			
		||||
    column: project_id
 | 
			
		||||
    on_delete: async_delete
 | 
			
		||||
  - table: users
 | 
			
		||||
    column: user_id
 | 
			
		||||
    on_delete: async_delete
 | 
			
		||||
merge_requests:
 | 
			
		||||
  - table: ci_pipelines
 | 
			
		||||
    column: head_pipeline_id
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -261,7 +261,6 @@ module.exports = {
 | 
			
		|||
     */
 | 
			
		||||
    return {
 | 
			
		||||
      default: defaultEntries,
 | 
			
		||||
      legacy_sentry: './sentry/legacy_index.js',
 | 
			
		||||
      sentry: './sentry/index.js',
 | 
			
		||||
      performance_bar: './performance_bar/index.js',
 | 
			
		||||
      jira_connect_app: './jira_connect/subscriptions/index.js',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
- title: 'Runner `active` GraphQL fields replaced by `paused`'
 | 
			
		||||
  # The milestones for the deprecation announcement, and the removal.
 | 
			
		||||
  removal_milestone: '18.0'
 | 
			
		||||
  announcement_milestone: '14.8'
 | 
			
		||||
  # 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: pedropombeiro
 | 
			
		||||
  stage: Verify
 | 
			
		||||
  issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351109
 | 
			
		||||
  impact: low
 | 
			
		||||
  scope: # Can be one or a combination of: [instance, group, project]
 | 
			
		||||
  resolution_role: Developer
 | 
			
		||||
  manual_task: true
 | 
			
		||||
  body: | # (required) Don't change this line.
 | 
			
		||||
    Occurrences of the `active` identifier in the GitLab GraphQL API endpoints will be renamed to `paused` in GitLab 18.0:
 | 
			
		||||
 | 
			
		||||
    - The `CiRunner` property.
 | 
			
		||||
    - The `RunnerUpdateInput` input type for the `runnerUpdate` mutation.
 | 
			
		||||
    - The `runners`, `Group.runners`, and `Project.runners` queries.
 | 
			
		||||
 | 
			
		||||
  # ==============================
 | 
			
		||||
  # OPTIONAL END-OF-SUPPORT FIELDS
 | 
			
		||||
  # ==============================
 | 
			
		||||
  #
 | 
			
		||||
  # If an End of Support period applies:
 | 
			
		||||
  # 1) Share this announcement in the `#spt_managers` Support channel in Slack
 | 
			
		||||
  # 2) Mention `@gitlab-com/support` in this merge request.
 | 
			
		||||
  #
 | 
			
		||||
  # When support for this feature ends, in XX.YY milestone format.
 | 
			
		||||
  end_of_support_milestone:
 | 
			
		||||
  # Array of tiers the feature is currently available to,
 | 
			
		||||
  # like [Free, Silver, Gold, Core, Premium, Ultimate]
 | 
			
		||||
  tiers:
 | 
			
		||||
  # Links to documentation and thumbnail image
 | 
			
		||||
  documentation_url: https://docs.gitlab.com/ee/api/graphql/reference/index.html#cirunner
 | 
			
		||||
  image_url:
 | 
			
		||||
  # Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
 | 
			
		||||
  video_url:
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
  stage: ai-powered
 | 
			
		||||
  self-managed: true
 | 
			
		||||
  gitlab-com: true
 | 
			
		||||
  available_in: [Free, Premium, Ultimate]
 | 
			
		||||
  available_in: [Premium, Ultimate]
 | 
			
		||||
  documentation_link: https://docs.gitlab.com/ee/user/gitlab_duo_chat.html
 | 
			
		||||
  image_url: https://img.youtube.com/vi/ZQBAuf-CTAY/hqdefault.jpg
 | 
			
		||||
  published_at: 2024-04-18
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@
 | 
			
		|||
  stage: govern
 | 
			
		||||
  self-managed: true
 | 
			
		||||
  gitlab-com: true
 | 
			
		||||
  available_in: [Free, Premium, Ultimate]
 | 
			
		||||
  available_in: [Premium, Ultimate]
 | 
			
		||||
  documentation_link: https://docs.gitlab.com/ee/editor_extensions/jetbrains_ide/index.html
 | 
			
		||||
  image_url: https://about.gitlab.com/images/16_11/create-duo-chat-in-jetbrains.png
 | 
			
		||||
  published_at: 2024-04-18
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
---
 | 
			
		||||
migration_job_name: BackfillWorkspaceVariablesProjectId
 | 
			
		||||
description: Backfills sharding key `workspace_variables.project_id` from `workspaces`.
 | 
			
		||||
feature_category: remote_development
 | 
			
		||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150074
 | 
			
		||||
milestone: '17.0'
 | 
			
		||||
queued_migration_version: 20240419035360
 | 
			
		||||
finalize_after: '2024-05-22'
 | 
			
		||||
finalized_by: # version of the migration that finalized this BBM
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
---
 | 
			
		||||
table_name: merge_request_requested_changes
 | 
			
		||||
classes:
 | 
			
		||||
- MergeRequests::RequestedChange
 | 
			
		||||
feature_categories:
 | 
			
		||||
- code_review_workflow
 | 
			
		||||
description: Blocker for changes requested on a merge request
 | 
			
		||||
introduced_by_url: 
 | 
			
		||||
milestone: '17.0'
 | 
			
		||||
gitlab_schema: gitlab_main_cell
 | 
			
		||||
sharding_key:
 | 
			
		||||
  project_id: projects
 | 
			
		||||
| 
						 | 
				
			
			@ -23,3 +23,4 @@ desired_sharding_key:
 | 
			
		|||
        table: workspaces
 | 
			
		||||
        sharding_key: project_id
 | 
			
		||||
        belongs_to: workspace
 | 
			
		||||
desired_sharding_key_migration_job_name: BackfillWorkspaceVariablesProjectId
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AddThrottleUnauthenticatedGitHttpToApplicationSettings < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    add_column :application_settings, :rate_limits_unauthenticated_git_http, :jsonb, default: {}, null: false,
 | 
			
		||||
      if_not_exists: true
 | 
			
		||||
 | 
			
		||||
    add_check_constraint(
 | 
			
		||||
      :application_settings,
 | 
			
		||||
      "(jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object')",
 | 
			
		||||
      'check_application_settings_rate_limits_unauth_git_http_is_hash'
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    remove_column :application_settings, :rate_limits_unauthenticated_git_http, it_exists: true
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class UpdateThrottleUnauthenticatedGitHttpInApplicationSettings < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  restrict_gitlab_migration gitlab_schema: :gitlab_main
 | 
			
		||||
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    execute <<~SQL
 | 
			
		||||
      UPDATE application_settings
 | 
			
		||||
      SET rate_limits_unauthenticated_git_http = jsonb_build_object(
 | 
			
		||||
        'throttle_unauthenticated_git_http_enabled', throttle_unauthenticated_enabled,
 | 
			
		||||
        'throttle_unauthenticated_git_http_requests_per_period', throttle_unauthenticated_requests_per_period,
 | 
			
		||||
        'throttle_unauthenticated_git_http_period_in_seconds', throttle_unauthenticated_period_in_seconds
 | 
			
		||||
      );
 | 
			
		||||
    SQL
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    execute "UPDATE application_settings SET rate_limits_unauthenticated_git_http = CAST('{}' AS jsonb)"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AddTrustedExternUidToIdentities < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  enable_lock_retries!
 | 
			
		||||
 | 
			
		||||
  def change
 | 
			
		||||
    add_column :identities, :trusted_extern_uid, :boolean, default: true
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class IndexIdentitiesOnProvider < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  INDEX_NAME = 'index_identities_on_provider'
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    add_concurrent_index :identities, :provider, name: INDEX_NAME
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    remove_concurrent_index_by_name :identities, name: INDEX_NAME
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AddProjectIdToWorkspaceVariables < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  def change
 | 
			
		||||
    add_column :workspace_variables, :project_id, :bigint
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class IndexWorkspaceVariablesOnProjectId < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  INDEX_NAME = 'index_workspace_variables_on_project_id'
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    add_concurrent_index :workspace_variables, :project_id, name: INDEX_NAME
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    remove_concurrent_index_by_name :workspace_variables, INDEX_NAME
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AddWorkspaceVariablesProjectIdFk < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    add_concurrent_foreign_key :workspace_variables, :projects, column: :project_id, on_delete: :cascade
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    with_lock_retries do
 | 
			
		||||
      remove_foreign_key :workspace_variables, column: :project_id
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class CreateMergeRequestRequestedChanges < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  def change
 | 
			
		||||
    create_table :merge_request_requested_changes do |t|
 | 
			
		||||
      t.bigint :project_id, null: false
 | 
			
		||||
      t.bigint :user_id, null: false
 | 
			
		||||
      t.bigint :merge_request_id, null: false
 | 
			
		||||
 | 
			
		||||
      t.timestamps_with_timezone null: false
 | 
			
		||||
 | 
			
		||||
      t.index :project_id
 | 
			
		||||
      t.index :user_id
 | 
			
		||||
      t.index :merge_request_id
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AddWorkspaceVariablesProjectIdTrigger < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    install_sharding_key_assignment_trigger(
 | 
			
		||||
      table: :workspace_variables,
 | 
			
		||||
      sharding_key: :project_id,
 | 
			
		||||
      parent_table: :workspaces,
 | 
			
		||||
      parent_sharding_key: :project_id,
 | 
			
		||||
      foreign_key: :workspace_id
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    remove_sharding_key_assignment_trigger(
 | 
			
		||||
      table: :workspace_variables,
 | 
			
		||||
      sharding_key: :project_id,
 | 
			
		||||
      parent_table: :workspaces,
 | 
			
		||||
      parent_sharding_key: :project_id,
 | 
			
		||||
      foreign_key: :workspace_id
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class QueueBackfillWorkspaceVariablesProjectId < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
  restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
 | 
			
		||||
 | 
			
		||||
  MIGRATION = "BackfillWorkspaceVariablesProjectId"
 | 
			
		||||
  DELAY_INTERVAL = 2.minutes
 | 
			
		||||
  BATCH_SIZE = 1000
 | 
			
		||||
  SUB_BATCH_SIZE = 100
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    queue_batched_background_migration(
 | 
			
		||||
      MIGRATION,
 | 
			
		||||
      :workspace_variables,
 | 
			
		||||
      :id,
 | 
			
		||||
      :project_id,
 | 
			
		||||
      :workspaces,
 | 
			
		||||
      :project_id,
 | 
			
		||||
      :workspace_id,
 | 
			
		||||
      job_interval: DELAY_INTERVAL,
 | 
			
		||||
      batch_size: BATCH_SIZE,
 | 
			
		||||
      sub_batch_size: SUB_BATCH_SIZE
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    delete_batched_background_migration(
 | 
			
		||||
      MIGRATION,
 | 
			
		||||
      :workspace_variables,
 | 
			
		||||
      :id,
 | 
			
		||||
      [
 | 
			
		||||
        :project_id,
 | 
			
		||||
        :workspaces,
 | 
			
		||||
        :project_id,
 | 
			
		||||
        :workspace_id
 | 
			
		||||
      ]
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class SetTrustedExternUidToFalseForExistingBitbucketIdentities < Gitlab::Database::Migration[2.2]
 | 
			
		||||
  restrict_gitlab_migration gitlab_schema: :gitlab_main_clusterwide
 | 
			
		||||
 | 
			
		||||
  milestone '17.0'
 | 
			
		||||
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  BATCH_SIZE = 1000
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    define_batchable_model('identities').where(provider: 'bitbucket').each_batch(of: BATCH_SIZE) do |batch|
 | 
			
		||||
      batch.update_all(trusted_extern_uid: false)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
1f79208f10eac682970b91dd12159c9c7446fab637409d2f62dc91231af1dd13
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
c84be5380fb2c1e90aabd987b8a7c020ec17405a8d0b97f0ca44e4ea724b7c6d
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
66b22a6c730d44535b321e0dd626c1b47fa3206ff811acd16007e9587a4c5d65
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
8e74960909f458e3500f3857a4154b4b930dc21d4f5c1d7916f321f197220ba6
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
a1f5f62a9782df2887fea2f8f1bccca6759e9da59d9a2778d6e7d09fc998d690
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
ae763de6e4f8d746dce6d4c5d1aa68b1e756bbd0488d2ad705c016ecc7c04fcd
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
1867e85e95b2def01e9fc4ef4209e64f7afd5e71a1378a0024dadc3715cc07aa
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
0ed31058286c68932a683e6072002fd5fe6a4d785c113db22028262aafc47c86
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
6f571972797eee34572944fb18ecf389d97c5880838b9c3c0ccf7ebbe5937f1d
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
a845ee1d6e023d976f526e76d2d690ec2a168d8975eda3edb5a1e9932d26c16c
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
cab7740141a0b515fbaf0c6e38c3d2aea4ac5ff765a2978ccd89f4274d44c1d1
 | 
			
		||||
| 
						 | 
				
			
			@ -695,6 +695,22 @@ BEGIN
 | 
			
		|||
END;
 | 
			
		||||
$$;
 | 
			
		||||
 | 
			
		||||
CREATE FUNCTION trigger_56d49f4ed623() RETURNS trigger
 | 
			
		||||
    LANGUAGE plpgsql
 | 
			
		||||
    AS $$
 | 
			
		||||
BEGIN
 | 
			
		||||
IF NEW."project_id" IS NULL THEN
 | 
			
		||||
  SELECT "project_id"
 | 
			
		||||
  INTO NEW."project_id"
 | 
			
		||||
  FROM "workspaces"
 | 
			
		||||
  WHERE "workspaces"."id" = NEW."workspace_id";
 | 
			
		||||
END IF;
 | 
			
		||||
 | 
			
		||||
RETURN NEW;
 | 
			
		||||
 | 
			
		||||
END
 | 
			
		||||
$$;
 | 
			
		||||
 | 
			
		||||
CREATE FUNCTION trigger_94514aeadc50() RETURNS trigger
 | 
			
		||||
    LANGUAGE plpgsql
 | 
			
		||||
    AS $$
 | 
			
		||||
| 
						 | 
				
			
			@ -4319,6 +4335,7 @@ CREATE TABLE application_settings (
 | 
			
		|||
    include_optional_metrics_in_service_ping boolean DEFAULT true NOT NULL,
 | 
			
		||||
    zoekt_settings jsonb DEFAULT '{}'::jsonb NOT NULL,
 | 
			
		||||
    service_ping_settings jsonb DEFAULT '{}'::jsonb NOT NULL,
 | 
			
		||||
    rate_limits_unauthenticated_git_http jsonb DEFAULT '{}'::jsonb NOT NULL,
 | 
			
		||||
    CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
 | 
			
		||||
    CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
 | 
			
		||||
    CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
 | 
			
		||||
| 
						 | 
				
			
			@ -4371,6 +4388,7 @@ CREATE TABLE application_settings (
 | 
			
		|||
    CONSTRAINT check_app_settings_sentry_clientside_traces_sample_rate_range CHECK (((sentry_clientside_traces_sample_rate >= (0)::double precision) AND (sentry_clientside_traces_sample_rate <= (1)::double precision))),
 | 
			
		||||
    CONSTRAINT check_application_settings_clickhouse_is_hash CHECK ((jsonb_typeof(clickhouse) = 'object'::text)),
 | 
			
		||||
    CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)),
 | 
			
		||||
    CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)),
 | 
			
		||||
    CONSTRAINT check_application_settings_service_ping_settings_is_hash CHECK ((jsonb_typeof(service_ping_settings) = 'object'::text)),
 | 
			
		||||
    CONSTRAINT check_b8c74ea5b3 CHECK ((char_length(deactivation_email_additional_text) <= 1000)),
 | 
			
		||||
    CONSTRAINT check_cdfbd99405 CHECK ((char_length(security_txt_content) <= 2048)),
 | 
			
		||||
| 
						 | 
				
			
			@ -9764,7 +9782,8 @@ CREATE TABLE identities (
 | 
			
		|||
    created_at timestamp without time zone,
 | 
			
		||||
    updated_at timestamp without time zone,
 | 
			
		||||
    secondary_extern_uid character varying,
 | 
			
		||||
    saml_provider_id integer
 | 
			
		||||
    saml_provider_id integer,
 | 
			
		||||
    trusted_extern_uid boolean DEFAULT true
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE SEQUENCE identities_id_seq
 | 
			
		||||
| 
						 | 
				
			
			@ -11250,6 +11269,24 @@ CREATE SEQUENCE merge_request_predictions_merge_request_id_seq
 | 
			
		|||
 | 
			
		||||
ALTER SEQUENCE merge_request_predictions_merge_request_id_seq OWNED BY merge_request_predictions.merge_request_id;
 | 
			
		||||
 | 
			
		||||
CREATE TABLE merge_request_requested_changes (
 | 
			
		||||
    id bigint NOT NULL,
 | 
			
		||||
    project_id bigint NOT NULL,
 | 
			
		||||
    user_id bigint NOT NULL,
 | 
			
		||||
    merge_request_id bigint NOT NULL,
 | 
			
		||||
    created_at timestamp with time zone NOT NULL,
 | 
			
		||||
    updated_at timestamp with time zone NOT NULL
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE SEQUENCE merge_request_requested_changes_id_seq
 | 
			
		||||
    START WITH 1
 | 
			
		||||
    INCREMENT BY 1
 | 
			
		||||
    NO MINVALUE
 | 
			
		||||
    NO MAXVALUE
 | 
			
		||||
    CACHE 1;
 | 
			
		||||
 | 
			
		||||
ALTER SEQUENCE merge_request_requested_changes_id_seq OWNED BY merge_request_requested_changes.id;
 | 
			
		||||
 | 
			
		||||
CREATE TABLE merge_request_review_llm_summaries (
 | 
			
		||||
    id bigint NOT NULL,
 | 
			
		||||
    user_id bigint,
 | 
			
		||||
| 
						 | 
				
			
			@ -18123,6 +18160,7 @@ CREATE TABLE workspace_variables (
 | 
			
		|||
    key text NOT NULL,
 | 
			
		||||
    encrypted_value bytea NOT NULL,
 | 
			
		||||
    encrypted_value_iv bytea NOT NULL,
 | 
			
		||||
    project_id bigint,
 | 
			
		||||
    CONSTRAINT check_5545042100 CHECK ((char_length(key) <= 255))
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19403,6 +19441,8 @@ ALTER TABLE ONLY merge_request_metrics ALTER COLUMN id SET DEFAULT nextval('merg
 | 
			
		|||
 | 
			
		||||
ALTER TABLE ONLY merge_request_predictions ALTER COLUMN merge_request_id SET DEFAULT nextval('merge_request_predictions_merge_request_id_seq'::regclass);
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY merge_request_requested_changes ALTER COLUMN id SET DEFAULT nextval('merge_request_requested_changes_id_seq'::regclass);
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY merge_request_review_llm_summaries ALTER COLUMN id SET DEFAULT nextval('merge_request_review_llm_summaries_id_seq'::regclass);
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY merge_request_reviewers ALTER COLUMN id SET DEFAULT nextval('merge_request_reviewers_id_seq'::regclass);
 | 
			
		||||
| 
						 | 
				
			
			@ -21650,6 +21690,9 @@ ALTER TABLE ONLY merge_request_metrics
 | 
			
		|||
ALTER TABLE ONLY merge_request_predictions
 | 
			
		||||
    ADD CONSTRAINT merge_request_predictions_pkey PRIMARY KEY (merge_request_id);
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY merge_request_requested_changes
 | 
			
		||||
    ADD CONSTRAINT merge_request_requested_changes_pkey PRIMARY KEY (id);
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY merge_request_review_llm_summaries
 | 
			
		||||
    ADD CONSTRAINT merge_request_review_llm_summaries_pkey PRIMARY KEY (id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -25656,6 +25699,8 @@ CREATE INDEX index_historical_data_on_recorded_at ON historical_data USING btree
 | 
			
		|||
 | 
			
		||||
CREATE UNIQUE INDEX index_http_integrations_on_project_and_endpoint ON alert_management_http_integrations USING btree (project_id, endpoint_identifier);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_identities_on_provider ON identities USING btree (provider);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_identities_on_saml_provider_id ON identities USING btree (saml_provider_id) WHERE (saml_provider_id IS NOT NULL);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_identities_on_user_id ON identities USING btree (user_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -26068,6 +26113,12 @@ CREATE INDEX index_merge_request_metrics_on_merged_at ON merge_request_metrics U
 | 
			
		|||
 | 
			
		||||
CREATE INDEX index_merge_request_metrics_on_pipeline_id ON merge_request_metrics USING btree (pipeline_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_merge_request_requested_changes_on_merge_request_id ON merge_request_requested_changes USING btree (merge_request_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_merge_request_requested_changes_on_project_id ON merge_request_requested_changes USING btree (project_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_merge_request_requested_changes_on_user_id ON merge_request_requested_changes USING btree (user_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_merge_request_review_llm_summaries_on_mr_diff_id ON merge_request_review_llm_summaries USING btree (merge_request_diff_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_merge_request_review_llm_summaries_on_review_id ON merge_request_review_llm_summaries USING btree (review_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -27838,6 +27889,8 @@ CREATE UNIQUE INDEX index_work_item_widget_definitions_on_namespace_type_and_nam
 | 
			
		|||
 | 
			
		||||
CREATE INDEX index_work_item_widget_definitions_on_work_item_type_id ON work_item_widget_definitions USING btree (work_item_type_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_workspace_variables_on_project_id ON workspace_variables USING btree (project_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_workspace_variables_on_workspace_id ON workspace_variables USING btree (workspace_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX index_workspaces_on_cluster_agent_id ON workspaces USING btree (cluster_agent_id);
 | 
			
		||||
| 
						 | 
				
			
			@ -29722,6 +29775,8 @@ CREATE TRIGGER trigger_3857ca5ea4af BEFORE INSERT OR UPDATE ON merge_trains FOR
 | 
			
		|||
 | 
			
		||||
CREATE TRIGGER trigger_388e93f88fdd BEFORE INSERT OR UPDATE ON packages_build_infos FOR EACH ROW EXECUTE FUNCTION trigger_388e93f88fdd();
 | 
			
		||||
 | 
			
		||||
CREATE TRIGGER trigger_56d49f4ed623 BEFORE INSERT OR UPDATE ON workspace_variables FOR EACH ROW EXECUTE FUNCTION trigger_56d49f4ed623();
 | 
			
		||||
 | 
			
		||||
CREATE TRIGGER trigger_94514aeadc50 BEFORE INSERT OR UPDATE ON deployment_approvals FOR EACH ROW EXECUTE FUNCTION trigger_94514aeadc50();
 | 
			
		||||
 | 
			
		||||
CREATE TRIGGER trigger_b2d852e1e2cb BEFORE INSERT OR UPDATE ON ci_pipelines FOR EACH ROW EXECUTE FUNCTION trigger_b2d852e1e2cb();
 | 
			
		||||
| 
						 | 
				
			
			@ -30091,6 +30146,9 @@ ALTER TABLE ONLY todos
 | 
			
		|||
ALTER TABLE ONLY releases
 | 
			
		||||
    ADD CONSTRAINT fk_47fe2a0596 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY workspace_variables
 | 
			
		||||
    ADD CONSTRAINT fk_494e093520 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
 | 
			
		||||
 | 
			
		||||
ALTER TABLE ONLY geo_event_log
 | 
			
		||||
    ADD CONSTRAINT fk_4a99ebfd60 FOREIGN KEY (repositories_changed_event_id) REFERENCES geo_repositories_changed_events(id) ON DELETE CASCADE;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -177,8 +177,7 @@ WARNING:
 | 
			
		|||
In a multi-server setup you must use one of the options to
 | 
			
		||||
[eliminate local disk usage for job logs](job_logs.md#prevent-local-disk-usage), or job logs could be lost.
 | 
			
		||||
 | 
			
		||||
In GitLab 13.2 and later, you should use the
 | 
			
		||||
[consolidated object storage settings](object_storage.md#configure-a-single-storage-connection-for-all-object-types-consolidated-form).
 | 
			
		||||
You should use the [consolidated object storage settings](object_storage.md#configure-a-single-storage-connection-for-all-object-types-consolidated-form).
 | 
			
		||||
 | 
			
		||||
### Migrating to object storage
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,8 +23,7 @@ reasons are:
 | 
			
		|||
- Artifact files might be left on disk and not deleted by housekeeping. Run the
 | 
			
		||||
  [Rake task for _orphaned_ artifact files](../raketasks/cleanup.md#remove-orphan-artifact-files)
 | 
			
		||||
  to remove these. This script should always find work to do, as it also removes empty directories (see above).
 | 
			
		||||
- [Artifact housekeeping was changed significantly](#housekeeping-disabled-in-gitlab-146-to-152),
 | 
			
		||||
  and you might need to enable a feature flag to use the updated system.
 | 
			
		||||
- [Artifact housekeeping was changed significantly](#housekeeping-disabled-in-gitlab-150-to-152), and you might need to enable a feature flag to use the updated system.
 | 
			
		||||
- The [keep latest artifacts from most recent success jobs](../ci/jobs/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs)
 | 
			
		||||
  feature is enabled.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -37,15 +36,11 @@ space, and in some cases, manually delete job artifacts to reclaim disk space.
 | 
			
		|||
Artifacts housekeeping is the process that identifies which artifacts are expired
 | 
			
		||||
and can be deleted.
 | 
			
		||||
 | 
			
		||||
#### Housekeeping disabled in GitLab 14.6 to 15.2
 | 
			
		||||
#### Housekeeping disabled in GitLab 15.0 to 15.2
 | 
			
		||||
 | 
			
		||||
Artifact housekeeping was disabled in GitLab 14.6. It was significantly improved
 | 
			
		||||
in GitLab 14.10, and the changes were back ported to patch versions of GitLab 14.6 and later,
 | 
			
		||||
introduced behind [feature flags](feature_flags.md) disabled by default. The flags were
 | 
			
		||||
enabled by default [in GitLab 15.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92931).
 | 
			
		||||
Artifact housekeeping was significantly improved in GitLab 15.0, introduced behind [feature flags](feature_flags.md) disabled by default. The flags were enabled by default [in GitLab 15.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92931).
 | 
			
		||||
 | 
			
		||||
If artifacts housekeeping does not seem to be working in GitLab 14.6 to GitLab 15.2,
 | 
			
		||||
you should check if the feature flags are enabled.
 | 
			
		||||
If artifacts housekeeping does not seem to be working in GitLab 15.0 to GitLab 15.2, you should check if the feature flags are enabled.
 | 
			
		||||
 | 
			
		||||
To check if the feature flags are enabled:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -53,16 +48,6 @@ To check if the feature flags are enabled:
 | 
			
		|||
 | 
			
		||||
1. Check if the feature flags are enabled.
 | 
			
		||||
 | 
			
		||||
   - GitLab 14.10 and earlier:
 | 
			
		||||
 | 
			
		||||
     ```ruby
 | 
			
		||||
     Feature.enabled?(:ci_detect_wrongly_expired_artifacts, default_enabled: :yaml)
 | 
			
		||||
     Feature.enabled?(:ci_update_unlocked_job_artifacts, default_enabled: :yaml)
 | 
			
		||||
     Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
 | 
			
		||||
     ```
 | 
			
		||||
 | 
			
		||||
   - GitLab 15.0 and later:
 | 
			
		||||
 | 
			
		||||
   ```ruby
 | 
			
		||||
   Feature.enabled?(:ci_detect_wrongly_expired_artifacts)
 | 
			
		||||
   Feature.enabled?(:ci_update_unlocked_job_artifacts)
 | 
			
		||||
| 
						 | 
				
			
			@ -154,20 +139,12 @@ GitLab 15.3 and later. It analyzes the artifacts returned by the above database
 | 
			
		|||
determines which should be `locked` or `unlocked`. Artifacts are then deleted
 | 
			
		||||
by that worker if needed.
 | 
			
		||||
 | 
			
		||||
The worker can be enabled on self-managed instances running GitLab 14.10 and later:
 | 
			
		||||
The worker can be enabled on self-managed instances:
 | 
			
		||||
 | 
			
		||||
1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
 | 
			
		||||
 | 
			
		||||
1. Check if the feature is enabled.
 | 
			
		||||
   
 | 
			
		||||
   - GitLab 14.10:
 | 
			
		||||
 | 
			
		||||
     ```ruby
 | 
			
		||||
     Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
 | 
			
		||||
     ```
 | 
			
		||||
 | 
			
		||||
   - GitLab 15.0 and later:
 | 
			
		||||
 | 
			
		||||
   ```ruby
 | 
			
		||||
   Feature.enabled?(:ci_job_artifacts_backlog_work)
 | 
			
		||||
   ```
 | 
			
		||||
| 
						 | 
				
			
			@ -429,8 +406,6 @@ For more information, [see the investigation details](https://gitlab.com/gitlab-
 | 
			
		|||
 | 
			
		||||
## Usage quota shows incorrect artifact storage usage
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/238536) in GitLab 14.10.
 | 
			
		||||
 | 
			
		||||
Sometimes the [artifacts storage usage](../user/usage_quotas.md) displays an incorrect
 | 
			
		||||
value for the total storage space used by artifacts. To recalculate the artifact
 | 
			
		||||
usage statistics for all projects in the instance, you can run this background script:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,28 +119,25 @@ If you need support for namespace in the URL path to remove the requirement for
 | 
			
		|||
 | 
			
		||||
1. Enable the GitLab Pages flag for this feature by adding
 | 
			
		||||
   `gitlab_pages["namespace_in_path"] = true` to `/etc/gitlab/gitlab.rb`.
 | 
			
		||||
1. In your DNS provider, add entries for `example.io` and `projects.example.io`.
 | 
			
		||||
   In both lines, replace `example.io` with your domain name, and `192.0.0.0` with
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
   ```plaintext
 | 
			
		||||
   example.io          1800 IN A    192.0.0.0
 | 
			
		||||
   projects.example.io 1800 IN A    192.0.0.0
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
1. Optional. If your GitLab instance has an IPv6 address, add entries for it.
 | 
			
		||||
   In both lines, replace `example.io` with your domain name, and `2001:db8::1` with
 | 
			
		||||
   Replace `example.io` with your domain name, and `2001:db8::1` with
 | 
			
		||||
   the IPv6 version of your IP address. The entries look like this:
 | 
			
		||||
 | 
			
		||||
   ```plaintext
 | 
			
		||||
   example.io          1800 IN AAAA 2001:db8::1
 | 
			
		||||
   projects.example.io 1800 IN AAAA 2001:db8::1
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
This example contains the following:
 | 
			
		||||
 | 
			
		||||
- `example.io`: The domain GitLab Pages is served from.
 | 
			
		||||
- `projects.example.io`: An additional subdomain for GitLab Pages default authentication flow.
 | 
			
		||||
 | 
			
		||||
#### DNS configuration for custom domains
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -306,8 +303,7 @@ Prerequisites:
 | 
			
		|||
- Your instance must use the Linux package installation method.
 | 
			
		||||
- You have configured DNS setup
 | 
			
		||||
  [without a wildcard](#for-namespace-in-url-path-without-wildcard-dns).
 | 
			
		||||
- You have a single TLS certificate that covers your domain (like `example.io`)
 | 
			
		||||
  and the `projects.*` version of your domain, like `projects.example.io`.
 | 
			
		||||
- You have a TLS certificate that covers your domain (like `example.io`).
 | 
			
		||||
 | 
			
		||||
In this configuration, NGINX proxies all requests to the daemon. The GitLab Pages
 | 
			
		||||
daemon doesn't listen to the outside world:
 | 
			
		||||
| 
						 | 
				
			
			@ -337,17 +333,18 @@ daemon doesn't listen to the outside world:
 | 
			
		|||
   pages_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/pages-nginx.key"
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
 | 
			
		||||
1. If you're using [Pages Access Control](#access-control), update the redirect URI in the GitLab Pages
 | 
			
		||||
   [System OAuth application](../../integration/oauth_provider.md#create-an-instance-wide-application)
 | 
			
		||||
   to use the HTTPS protocol.
 | 
			
		||||
 | 
			
		||||
   WARNING:
 | 
			
		||||
   GitLab Pages does not update the OAuth application if changes are made to the redirect URI.
 | 
			
		||||
   GitLab Pages does not update the OAuth application, and
 | 
			
		||||
   the default `auth_redirect_uri` is updated to `https://example.io/projects/auth`.
 | 
			
		||||
   Before you reconfigure, remove the `gitlab_pages` section from `/etc/gitlab/gitlab-secrets.json`,
 | 
			
		||||
   then run `gitlab-ctl reconfigure`. For more information, see
 | 
			
		||||
   [GitLab Pages does not regenerate OAuth](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3947).
 | 
			
		||||
 | 
			
		||||
1. If you're using [Pages Access Control](#access-control), update the redirect URI in the GitLab Pages
 | 
			
		||||
   [System OAuth application](../../integration/oauth_provider.md#create-an-instance-wide-application)
 | 
			
		||||
   to use the HTTPS protocol.
 | 
			
		||||
1. [Reconfigure GitLab](../restart_gitlab.md#reconfigure-a-linux-package-installation).
 | 
			
		||||
 | 
			
		||||
NGINX uses the custom proxy header `X-Gitlab-Namespace-In-Path`
 | 
			
		||||
to send the namespace to the GitLab Pages daemon.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
---
 | 
			
		||||
stage: Create
 | 
			
		||||
group: Source Code
 | 
			
		||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
# Rate limits on Git HTTP
 | 
			
		||||
 | 
			
		||||
DETAILS:
 | 
			
		||||
**Tier:** Free, Premium, Ultimate
 | 
			
		||||
**Offering:** Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147112) in GitLab 17.0.
 | 
			
		||||
 | 
			
		||||
If you use Git HTTP in your repository,
 | 
			
		||||
common Git operations can generate many Git HTTP requests.
 | 
			
		||||
Some of these Git HTTP requests do not contain authentication parameter and
 | 
			
		||||
are considered unauthenticated. You can enforce rate limits on Git HTTP requests.
 | 
			
		||||
This can improve the security and durability of your web application.
 | 
			
		||||
[General user and IP rate limits](../settings/user_and_ip_rate_limits.md) aren't applied
 | 
			
		||||
to Git HTTP requests.
 | 
			
		||||
 | 
			
		||||
## Configure Git HTTP rate limits
 | 
			
		||||
 | 
			
		||||
Git HTTP rate limits are disabled by default. If enabled and configured, these limits
 | 
			
		||||
are applied to Git HTTP requests.
 | 
			
		||||
 | 
			
		||||
To configure Git HTTP rate limits:
 | 
			
		||||
 | 
			
		||||
1. On the left sidebar, at the bottom, select **Admin Area**.
 | 
			
		||||
1. Select **Settings > Network**.
 | 
			
		||||
1. Expand **Git HTTP rate limits**.
 | 
			
		||||
1. Select **Enable unauthenticated Git HTTP request rate limit**.
 | 
			
		||||
1. Enter a value for **Max unauthenticated Git HTTP requests per period per user**.
 | 
			
		||||
1. Enter a value for **Unauthenticated Git HTTP rate limit period in seconds**.
 | 
			
		||||
1. Select **Save changes**.
 | 
			
		||||
 | 
			
		||||
## Related topics
 | 
			
		||||
 | 
			
		||||
- [Rate limiting](../../security/rate_limits.md)
 | 
			
		||||
- [User and IP rate limits](../settings/user_and_ip_rate_limits.md)
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
 | 
			
		|||
You can change network settings to limit the rate of connections with your instance.
 | 
			
		||||
 | 
			
		||||
- [Deprecated API rate limits](deprecated_api_rate_limits.md)
 | 
			
		||||
- [Git HTTP](git_http_rate_limits.md)
 | 
			
		||||
- [Git LFS](git_lfs_rate_limits.md)
 | 
			
		||||
- [Git SSH operations](rate_limits_on_git_ssh_operations.md)
 | 
			
		||||
- [Incident management](incident_management_rate_limits.md)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,9 +15,6 @@ This API is in an [Experiment](../policy/experiment-beta-support.md#experiment)
 | 
			
		|||
The response payload may be subject to change or breakage
 | 
			
		||||
across GitLab releases.
 | 
			
		||||
 | 
			
		||||
> - Introduced in GitLab 12.1.
 | 
			
		||||
> - Pagination introduced in 14.4.
 | 
			
		||||
 | 
			
		||||
Every call to this endpoint requires authentication. To perform this call, user should be authorized to read repository.
 | 
			
		||||
To see vulnerabilities in response, user should be authorized to read
 | 
			
		||||
[Project Security Dashboard](../user/application_security/security_dashboard/index.md).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -316,9 +316,6 @@ If the artifacts were deleted successfully, a response with status `204 No Conte
 | 
			
		|||
 | 
			
		||||
## Delete project artifacts
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223793) in GitLab 14.7 [with a flag](../administration/feature_flags.md) named `bulk_expire_project_artifacts`. Enabled by default on GitLab self-managed. Enabled on GitLab.com.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/350609) in GitLab 14.10.
 | 
			
		||||
 | 
			
		||||
Delete artifacts eligible for deletion in a project. By default, artifacts from
 | 
			
		||||
[the most recent successful pipeline of each ref](../ci/jobs/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs)
 | 
			
		||||
are not deleted.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -184,9 +184,6 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
 | 
			
		|||
 | 
			
		||||
## The `filter` parameter
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34490) in GitLab 13.2.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/227052) in GitLab 13.4.
 | 
			
		||||
 | 
			
		||||
When multiple variables have the same `key`, [GET](#get-a-single-variable), [PUT](#update-a-variable),
 | 
			
		||||
or [DELETE](#delete-a-variable) requests might return:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -416,7 +416,6 @@ GET /projects/:id/releases/:tag_name/downloads/:direct_asset_path
 | 
			
		|||
|----------------------------| -------------- | -------- | ----------------------------------------------------------------------------------- |
 | 
			
		||||
| `id`                       | integer/string | yes      | The ID or [URL-encoded path of the project](../rest/index.md#namespaced-path-encoding).  |
 | 
			
		||||
| `tag_name`                 | string         | yes      | The Git tag the release is associated with.                                         |
 | 
			
		||||
| `filepath`                 | string         | yes      | Deprecated: Use `direct_asset_path` instead.                                        |
 | 
			
		||||
| `direct_asset_path`        | string         | yes      | Path to the release asset file as specified when [creating](links.md#create-a-release-link) or [updating](links.md#update-a-release-link) its link. |
 | 
			
		||||
 | 
			
		||||
Example request:
 | 
			
		||||
| 
						 | 
				
			
			@ -476,7 +475,6 @@ POST /projects/:id/releases
 | 
			
		|||
| `assets:links`     | array of hash   | no                          | An array of assets links.                                                                                                        |
 | 
			
		||||
| `assets:links:name`| string          | required by: `assets:links` | The name of the link. Link names must be unique within the release.                                                              |
 | 
			
		||||
| `assets:links:url` | string          | required by: `assets:links` | The URL of the link. Link URLs must be unique within the release.                                                                |
 | 
			
		||||
| `assets:links:filepath` | string     | no | Deprecated: Use `direct_asset_path` instead. |
 | 
			
		||||
| `assets:links:direct_asset_path` | string     | no | Optional path for a [direct asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
 | 
			
		||||
| `assets:links:link_type` | string     | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
 | 
			
		||||
| `released_at`      | datetime        | no                          | Date and time for the release. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). Only provide this field if creating an [upcoming](../../user/project/releases/index.md#upcoming-releases) or [historical](../../user/project/releases/index.md#historical-releases) release.  |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -100,7 +100,6 @@ POST /projects/:id/releases/:tag_name/assets/links
 | 
			
		|||
| `tag_name`           | string         | yes      | The tag associated with the Release.                                                                                      |
 | 
			
		||||
| `name`               | string         | yes      | The name of the link. Link names must be unique in the release.                                                           |
 | 
			
		||||
| `url`                | string         | yes      | The URL of the link. Link URLs must be unique in the release.                                                             |
 | 
			
		||||
| `filepath`           | string         | no       | Deprecated: Use `direct_asset_path` instead.                                                                              |
 | 
			
		||||
| `direct_asset_path`  | string         | no       | Optional path for a [direct asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
 | 
			
		||||
| `link_type`          | string         | no       | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`.                                        |
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +141,6 @@ PUT /projects/:id/releases/:tag_name/assets/links/:link_id
 | 
			
		|||
| `link_id`            | integer        | yes      | The ID of the link. |
 | 
			
		||||
| `name`               | string         | no       | The name of the link. |
 | 
			
		||||
| `url`                | string         | no       | The URL of the link. |
 | 
			
		||||
| `filepath`           | string         | no       | Deprecated: Use `direct_asset_path` instead. |
 | 
			
		||||
| `direct_asset_path`  | string         | no       | Optional path for a [direct asset link](../../user/project/releases/release_fields.md#permanent-links-to-release-assets). |
 | 
			
		||||
| `link_type`          | string         | no       | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`. |
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,6 @@ DETAILS:
 | 
			
		|||
**Tier:** Free, Premium, Ultimate
 | 
			
		||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78227) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `ci_secure_files`. Disabled by default.
 | 
			
		||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/350748) in GitLab 15.7. Feature flag `ci_secure_files` removed.
 | 
			
		||||
 | 
			
		||||
This feature is part of [Mobile DevOps](../ci/mobile_devops.md) developed by [GitLab Incubation Engineering](https://handbook.gitlab.com/handbook/engineering/development/incubation/).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,6 @@ DETAILS:
 | 
			
		|||
**Tier:** Free, Premium, Ultimate
 | 
			
		||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - `CI_JOB_JWT` variable for reading secrets from Vault [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) in GitLab 12.10.
 | 
			
		||||
> - `CI_JOB_JWT_V2` variable to support additional OIDC providers [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/346737) in GitLab 14.7.
 | 
			
		||||
> - [ID tokens](../yaml/index.md#id_tokens) to support any OIDC provider, including HashiCorp Vault, [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356986) in GitLab 15.7.
 | 
			
		||||
 | 
			
		||||
WARNING:
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +22,7 @@ Historically, teams stored secrets in projects or applied permissions on the Git
 | 
			
		|||
instance to build and deploy. OIDC capable [ID tokens](../yaml/index.md#id_tokens) are configurable
 | 
			
		||||
in the CI/CD job allowing you to follow a scalable and least-privilege security approach.
 | 
			
		||||
 | 
			
		||||
In GitLab 15.6 and earlier, you must use `CI_JOB_JWT_V2` instead of an ID token,
 | 
			
		||||
but it is not customizable. In GitLab 14.6 an earlier you must use the `CI_JOB_JWT`, which has limited support.
 | 
			
		||||
In GitLab 15.6 and earlier, you must use `CI_JOB_JWT_V2` instead of an ID token, but it is not customizable.
 | 
			
		||||
 | 
			
		||||
## Prerequisites
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,9 +58,9 @@ The following fields are included in the JWT:
 | 
			
		|||
| `ref_type`              | Always                       | Git ref type, either `branch` or `tag`                                                                                                                                                               |
 | 
			
		||||
| `ref_path`              | Always                       | Fully qualified ref for the job. For example, `refs/heads/main`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119075) in GitLab 16.0.                                          |
 | 
			
		||||
| `ref_protected`         | Always                       | `true` if this Git ref is protected, `false` otherwise                                                                                                                                               |
 | 
			
		||||
| `environment`           | Job specifies an environment | Environment this job specifies ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9)                                                                                   |
 | 
			
		||||
| `environment`           | Job specifies an environment | Environment this job specifies                                                                                   |
 | 
			
		||||
| `groups_direct`         | User is a direct member of 0 to 200 groups | The paths of the user's direct membership groups. Omitted if the user is a direct member of more than 200 groups. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435848) in GitLab 16.11). |
 | 
			
		||||
| `environment_protected` | Job specifies an environment | `true` if specified environment is protected, `false` otherwise ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9)                                                  |
 | 
			
		||||
| `environment_protected` | Job specifies an environment | `true` if specified environment is protected, `false` otherwise                                                  |
 | 
			
		||||
| `deployment_tier`       | Job specifies an environment | [Deployment tier](../../environments/index.md#deployment-tier-of-environments) of environment this job specifies ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363590) in GitLab 15.2) |
 | 
			
		||||
| `environment_action`    | Job specifies an environment | [Environment action (`environment:action`)](../../environments/index.md) specified in the job. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/) in GitLab 16.5)                                   |
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -187,10 +187,6 @@ proposes to change this behavior.
 | 
			
		|||
 | 
			
		||||
## Limit your project's job token access (deprecated)
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328553) in GitLab 14.1. [Deployed behind the `:ci_scoped_job_token` feature flag](../../user/feature_flags.md), disabled by default.
 | 
			
		||||
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/332272) in GitLab 14.4.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/332272) in GitLab 14.6.
 | 
			
		||||
 | 
			
		||||
NOTE:
 | 
			
		||||
The [**Limit access _from_ this project**](#configure-the-job-token-scope-deprecated)
 | 
			
		||||
setting is disabled by default for all new projects and is [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/383084)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -194,7 +194,6 @@ job:
 | 
			
		|||
 | 
			
		||||
## View all job artifacts in a project
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31271) in GitLab 12.4 [with a flag](../../administration/feature_flags.md) named `artifacts_management_page`. Disabled by default.
 | 
			
		||||
> - [Improved look](https://gitlab.com/gitlab-org/gitlab/-/issues/33418) in GitLab 15.6.
 | 
			
		||||
> - [Improved performance](https://gitlab.com/gitlab-org/gitlab/-/issues/387765) in GitLab 15.9.
 | 
			
		||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/407475) in GitLab 16.0. Feature flag `artifacts_management_page` removed.
 | 
			
		||||
| 
						 | 
				
			
			@ -362,9 +361,6 @@ With this configuration, GitLab adds **artifact 1** as a link to `file.txt` to t
 | 
			
		|||
 | 
			
		||||
## Keep artifacts from most recent successful jobs
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16267) in GitLab 13.0.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/229936) in GitLab 13.4.
 | 
			
		||||
> - [Made optional with a CI/CD setting](https://gitlab.com/gitlab-org/gitlab/-/issues/241026) in GitLab 13.8.
 | 
			
		||||
> - Artifacts for [blocked](https://gitlab.com/gitlab-org/gitlab/-/issues/387087) or [failed](https://gitlab.com/gitlab-org/gitlab/-/issues/266958) pipelines no longer kept indefinitely in GitLab 16.7.
 | 
			
		||||
 | 
			
		||||
By default artifacts are always kept for successful pipelines for the most recent commit on each ref.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,8 +73,8 @@ The token also includes custom claims provided by GitLab:
 | 
			
		|||
| `ref_path`              | Always                       | Fully qualified ref for the job. For example, `refs/heads/main`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/119075) in GitLab 16.0.                                                                                                                                                      |
 | 
			
		||||
| `ref_protected`         | Always                       | `true` if the Git ref is protected, `false` otherwise.                                                                                                                                                                                                                                                           |
 | 
			
		||||
| `groups_direct`         | User is a direct member of 0 to 200 groups | The paths of the user's direct membership groups. Omitted if the user is a direct member of more than 200 groups. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435848) in GitLab 16.11). |
 | 
			
		||||
| `environment`           | Job specifies an environment | Environment this job deploys to ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9).                                                                                                                                                                                             |
 | 
			
		||||
| `environment_protected` | Job specifies an environment | `true` if deployed environment is protected, `false` otherwise ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/294440) in GitLab 13.9).                                                                                                                                                              |
 | 
			
		||||
| `environment`           | Job specifies an environment | Environment this job deploys to.                                                                                                                                                                                             |
 | 
			
		||||
| `environment_protected` | Job specifies an environment | `true` if deployed environment is protected, `false` otherwise.                                                                                                                                                              |
 | 
			
		||||
| `deployment_tier`       | Job specifies an environment | [Deployment tier](../environments/index.md#deployment-tier-of-environments) of the environment the job specifies. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363590) in GitLab 15.2.                                                                                                             |
 | 
			
		||||
| `environment_action`    | Job specifies an environment | [Environment action (`environment:action`)](../environments/index.md) specified in the job. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/) in GitLab 16.5)                                                                                                                                               |
 | 
			
		||||
| `runner_id`             | Always                       | ID of the runner executing the job. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/404722) in GitLab 16.0.                                                                                                                                                                                           |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,10 +10,6 @@ DETAILS:
 | 
			
		|||
**Tier:** Free, Premium, Ultimate
 | 
			
		||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218746) in GitLab 13.4 and GitLab Runner 13.4.
 | 
			
		||||
> - `file` setting [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250695) in GitLab 14.1 and GitLab Runner 14.1.
 | 
			
		||||
> - `VAULT_NAMESPACE` setting [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255619) in GitLab 14.9 and GitLab Runner 14.9.
 | 
			
		||||
 | 
			
		||||
Secrets represent sensitive information your CI job needs to complete work. This
 | 
			
		||||
sensitive information can be items like API tokens, database credentials, or private keys.
 | 
			
		||||
Secrets are sourced from your secrets provider.
 | 
			
		||||
| 
						 | 
				
			
			@ -125,8 +121,6 @@ DETAILS:
 | 
			
		|||
**Tier:** Premium, Ultimate
 | 
			
		||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/28321) in GitLab 13.4 and GitLab Runner 13.4.
 | 
			
		||||
 | 
			
		||||
After [configuring your Vault server](#configure-your-vault-server), you can use
 | 
			
		||||
the secrets stored in Vault by defining them with the [`vault` keyword](../yaml/index.md#secretsvault):
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,6 @@ DETAILS:
 | 
			
		|||
**Tier:** Free, Premium, Ultimate
 | 
			
		||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78227) in GitLab 14.8 [with a flag](../../administration/feature_flags.md) named `ci_secure_files`. Disabled by default.
 | 
			
		||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/350748) in GitLab 15.7. Feature flag `ci_secure_files` removed.
 | 
			
		||||
 | 
			
		||||
This feature is part of [Mobile DevOps](../mobile_devops.md) developed by [GitLab Incubation Engineering](https://handbook.gitlab.com/handbook/engineering/development/incubation/).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -201,9 +201,6 @@ DETAILS:
 | 
			
		|||
**Tier:** Free, Premium, Ultimate
 | 
			
		||||
**Offering:** Self-managed, GitLab Dedicated
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14108) in GitLab 13.0.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/299879) in GitLab 13.11.
 | 
			
		||||
 | 
			
		||||
You can make a CI/CD variable available to all projects and groups in a GitLab instance.
 | 
			
		||||
 | 
			
		||||
Prerequisites:
 | 
			
		||||
| 
						 | 
				
			
			@ -216,9 +213,8 @@ To add an instance variable:
 | 
			
		|||
1. Select **Settings > CI/CD** and expand the **Variables** section.
 | 
			
		||||
1. Select **Add variable** and fill in the details:
 | 
			
		||||
   - **Key**: Must be one line, with no spaces, using only letters, numbers, or `_`.
 | 
			
		||||
   - **Value**: In [GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/220028),
 | 
			
		||||
     the value is limited to 10,000 characters, but also bounded by any limits in the
 | 
			
		||||
     runner's operating system. In GitLab 13.0 to 13.2, the value is limited to 700 characters.
 | 
			
		||||
   - **Value**: The value is limited to 10,000 characters, but also bounded by any limits in the
 | 
			
		||||
     runner's operating system.
 | 
			
		||||
   - **Type**: `Variable` (default) or [`File`](#use-file-type-cicd-variables).
 | 
			
		||||
   - **Protect variable** Optional. If selected, the variable is only available
 | 
			
		||||
     in pipelines that run on protected branches or tags.
 | 
			
		||||
| 
						 | 
				
			
			@ -267,8 +263,6 @@ valid [secrets file](../../administration/backup_restore/troubleshooting_backup_
 | 
			
		|||
 | 
			
		||||
### Mask a CI/CD variable
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330650) in GitLab 13.12, the `~` character can be used in masked variables.
 | 
			
		||||
 | 
			
		||||
WARNING:
 | 
			
		||||
Masking a CI/CD variable is not a guaranteed way to prevent malicious users from
 | 
			
		||||
accessing variable values. The masking feature is "best-effort" and there to
 | 
			
		||||
| 
						 | 
				
			
			@ -473,9 +467,6 @@ variables:
 | 
			
		|||
 | 
			
		||||
### Pass an environment variable to another job
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/22638) in GitLab 13.0.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/217834) in GitLab 13.1.
 | 
			
		||||
 | 
			
		||||
You can create a new environment variables in a job, and pass it to another job
 | 
			
		||||
in a later stage. These variables cannot be used as CI/CD variables to configure a pipeline,
 | 
			
		||||
but they can be used in job scripts.
 | 
			
		||||
| 
						 | 
				
			
			@ -712,8 +703,6 @@ can cause the pipeline to behave unexpectedly.
 | 
			
		|||
 | 
			
		||||
### Restrict who can override variables
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/295234) in GitLab 13.8.
 | 
			
		||||
 | 
			
		||||
You can limit the ability to override variables to only users with the Maintainer role.
 | 
			
		||||
When other users try to run a pipeline with overridden variables, they receive the
 | 
			
		||||
`Insufficient permissions to set pipeline variables` error message.
 | 
			
		||||
| 
						 | 
				
			
			@ -951,9 +940,6 @@ if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then
 | 
			
		|||
 | 
			
		||||
#### Restrict access to debug logging
 | 
			
		||||
 | 
			
		||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213159) in GitLab 13.7.
 | 
			
		||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/292661) in GitLab 13.8.
 | 
			
		||||
 | 
			
		||||
You can restrict access to debug logging. When restricted, only users with
 | 
			
		||||
at least the Developer role
 | 
			
		||||
can view job logs when debug logging is enabled with a variable in:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -125,7 +125,7 @@ as it can cause the pipeline to behave unexpectedly.
 | 
			
		|||
| `CI_RUNNER_EXECUTABLE_ARCH`       | Jobs only   | all    | 10.6   | The OS/architecture of the GitLab Runner executable. Might not be the same as the environment of the executor. |
 | 
			
		||||
| `CI_RUNNER_ID`                    | Jobs only   | 8.10   | 0.5    | The unique ID of the runner being used. |
 | 
			
		||||
| `CI_RUNNER_REVISION`              | Jobs only   | all    | 10.6   | The revision of the runner running the job. |
 | 
			
		||||
| `CI_RUNNER_SHORT_TOKEN`           | Jobs only   | all    | 12.3   | The runner's unique ID, used to authenticate new job requests. In [GitLab 14.9](https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/2251) and later, the token contains a prefix, and the first 17 characters are used. Prior to 14.9, the first eight characters are used. |
 | 
			
		||||
| `CI_RUNNER_SHORT_TOKEN`           | Jobs only   | all    | 12.3   | The runner's unique ID, used to authenticate new job requests. The token contains a prefix, and the first 17 characters are used. |
 | 
			
		||||
| `CI_RUNNER_TAGS`                  | Jobs only   | 8.10   | 0.5    | A comma-separated list of the runner tags. |
 | 
			
		||||
| `CI_RUNNER_VERSION`               | Jobs only   | all    | 10.6   | The version of the GitLab Runner running the job. |
 | 
			
		||||
| `CI_SERVER_FQDN`                  | Pipeline    | 16.10  | all    | The fully qualified domain name (FQDN) of the instance. For example `gitlab.example.com:8080`. |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ There are two places defined variables can be used. On the:
 | 
			
		|||
| [`script`](../yaml/index.md#script)                                   | yes              | Script execution shell | The variable expansion is made by the [execution shell environment](#execution-shell-environment). |
 | 
			
		||||
| [`services:name`](../yaml/index.md#services)                          | yes              | Runner                 | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
 | 
			
		||||
| [`services`](../yaml/index.md#services)                               | yes              | Runner                 | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
 | 
			
		||||
| [`tags`](../yaml/index.md#tags)                                       | yes              | GitLab                 | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35742) in GitLab 14.1. |
 | 
			
		||||
| [`tags`](../yaml/index.md#tags)                                       | yes              | GitLab                 | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab.  |
 | 
			
		||||
| [`trigger` and `trigger:project`](../yaml/index.md#trigger)           | yes              | GitLab                 | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. Variable expansion for `trigger:project` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367660) in GitLab 15.3. |
 | 
			
		||||
| [`variables`](../yaml/index.md#variables)                             | yes              | GitLab/Runner          | The variable expansion is first made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab, and then any unrecognized or unavailable variables are expanded by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
 | 
			
		||||
| [`workflow:name`](../yaml/index.md#workflowname)                      | yes              | GitLab                 | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab.<br/><br/>Supported are all variables available in `workflow`:<br/>- Project/Group variables.<br/>- Global `variables` and `workflow:rules:variables` (when matching the rule).<br/>- Variables inherited from parent pipelines.<br/>- Variables from triggers.<br/>- Variables from pipeline schedules.<br/><br/>Not supported are variables defined in the GitLab Runner `config.toml`, variables defined in jobs, or [Persisted variables](#persisted-variables). |
 | 
			
		||||
| 
						 | 
				
			
			@ -81,11 +81,6 @@ because the expansion is done in GitLab before any runner gets the job.
 | 
			
		|||
 | 
			
		||||
#### Nested variable expansion
 | 
			
		||||
 | 
			
		||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48627) in GitLab 13.10. [Deployed behind the `variable_inside_variable` feature flag](../../user/feature_flags.md), disabled by default.
 | 
			
		||||
- [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/297382) in GitLab 14.3.
 | 
			
		||||
- [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/297382) in GitLab 14.4.
 | 
			
		||||
- Feature flag `variable_inside_variable` removed in GitLab 14.5.
 | 
			
		||||
 | 
			
		||||
GitLab expands job variable values recursively before sending them to the runner. For example, in the following scenario:
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,17 +7,18 @@ source: /doc/user/search/exact_code_search.md
 | 
			
		|||
 | 
			
		||||
# Search tips
 | 
			
		||||
 | 
			
		||||
| Query                | Description                                                                           |
 | 
			
		||||
| -------------------- |-------------------------------------------------------------------------------------- |
 | 
			
		||||
| `foo`                | Returns files that contain `foo`                                                      |
 | 
			
		||||
| `"class foo"`        | Returns files that contain the exact string `class foo`                               |
 | 
			
		||||
| `class foo`          | Returns files that contain both `class` and `foo`                                     |
 | 
			
		||||
| `foo or bar`         | Returns files that contain either `foo` or `bar`                                      |
 | 
			
		||||
| `class Foo`          | Returns files that contain `class` (case insensitive) and `Foo` (case sensitive)      |
 | 
			
		||||
| `class Foo case:yes` | Returns files that contain `class` and `Foo` (both case sensitive)                    |
 | 
			
		||||
| `foo -bar`           | Returns files that contain `foo` but not `bar`                                        |
 | 
			
		||||
| `foo file:js`        | Searches for `foo` in files with names that contain `js`                              |
 | 
			
		||||
| `foo -file:test`     | Searches for `foo` in files with names that do not contain `test`                     |
 | 
			
		||||
| `foo lang:ruby`      | Searches for `foo` in Ruby source code                                                |
 | 
			
		||||
| `foo f:\.js$`        | Searches for `foo` in files with names that end with `.js`                            |
 | 
			
		||||
| `foo.*bar`           | Searches for strings that match the regular expression `foo.*bar`                     |
 | 
			
		||||
| Query                | Regular expression mode                               | Exact match mode               |
 | 
			
		||||
| -------------------- | ----------------------------------------------------- | ------------------------------ |
 | 
			
		||||
| `"foo"`              | `foo`                                                 | `"foo"`                        |
 | 
			
		||||
| `foo file:^doc/`     | `foo` in directories that start with `/doc`           | `foo` in directories that start with `/doc` |
 | 
			
		||||
| `"class foo"`        | `class foo`                                           | `"class foo"`                  |
 | 
			
		||||
| `class foo`          | `class` and `foo`                                     | `class foo`                    |
 | 
			
		||||
| `foo or bar`         | `foo` or `bar`                                        | `foo or bar`                   |
 | 
			
		||||
| `class Foo`          | `class` (case insensitive) and `Foo` (case sensitive) | `class Foo` (case insensitive) |
 | 
			
		||||
| `class Foo case:yes` | `class` and `Foo` (both case sensitive)               | `class Foo` (case sensitive)   |
 | 
			
		||||
| `foo -bar`           | `foo` but not `bar`                                   | `foo -bar`                     |
 | 
			
		||||
| `foo file:js`        | `foo` in files with names that contain `js`           | `foo` in files with names that contain `js` |
 | 
			
		||||
| `foo -file:test`     | `foo` in files with names that do not contain `test`  | `foo` in files with names that do not contain `test` |
 | 
			
		||||
| `foo lang:ruby`      | `foo` in Ruby source code                             | `foo` in Ruby source code      |
 | 
			
		||||
| `foo file:\.js$`     | `foo` in files with names that end with `.js`         | `foo` in files with names that end with `.js` |
 | 
			
		||||
| `foo.*bar`           | `foo.*bar` (regular expression)                       | None                           |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -325,6 +325,24 @@ This change is a breaking change. You should [create a runner in the UI](https:/
 | 
			
		|||
 | 
			
		||||
<div class="deprecation breaking-change" data-milestone="18.0">
 | 
			
		||||
 | 
			
		||||
### Runner `active` GraphQL fields replaced by `paused`
 | 
			
		||||
 | 
			
		||||
<div class="deprecation-notes">
 | 
			
		||||
- Announced in GitLab <span class="milestone">14.8</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/gitlab-org/gitlab/-/issues/351109).
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
Occurrences of the `active` identifier in the GitLab GraphQL API endpoints will be renamed to `paused` in GitLab 18.0:
 | 
			
		||||
 | 
			
		||||
- The `CiRunner` property.
 | 
			
		||||
- The `RunnerUpdateInput` input type for the `runnerUpdate` mutation.
 | 
			
		||||
- The `runners`, `Group.runners`, and `Project.runners` queries.
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<div class="deprecation breaking-change" data-milestone="18.0">
 | 
			
		||||
 | 
			
		||||
### Running a single database is deprecated
 | 
			
		||||
 | 
			
		||||
<div class="deprecation-notes">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue