Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-03-17 18:09:34 +00:00
parent a1e798edcd
commit de560337ef
46 changed files with 1139 additions and 735 deletions

View File

@ -15,7 +15,7 @@ include:
- local: .gitlab/ci/global.gitlab-ci.yml
.build-cng-env:
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}-alpine3.20
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}-slim-bookworm
stage: prepare
needs:
# We need this job because we need its `cached-assets-hash.txt` artifact, so that we can pass the assets image tag to the downstream CNG pipeline.
@ -23,19 +23,27 @@ include:
job: build-assets-image
variables:
BUILD_ENV: build.env
CNG_PROJECT_PATH: "${CI_PROJECT_NAMESPACE}/$[[ inputs.cng_path ]]"
CNG_SKIP_REDUNDANT_JOBS: "false"
CNG_VAR_SETUP_LOG_FILE: "tmp/build-cng-env.log"
before_script:
- source ./scripts/utils.sh
- install_gitlab_gem
script:
- 'ruby -r./scripts/trigger-build.rb -e "puts Trigger.variables_for_env_file(Trigger::CNG.new.variables)" > $BUILD_ENV'
- echo "GITLAB_ASSETS_TAG=$(assets_image_tag)" >> $BUILD_ENV
- ruby -e 'puts "FULL_RUBY_VERSION=#{RUBY_VERSION}"' >> $BUILD_ENV
- echo -e "section_start:`date +%s`:cng_var_setup_log[collapsed=true]\r\e[0KCNG Variables Script Log Output"
- cat $CNG_VAR_SETUP_LOG_FILE
- echo -e "section_end:`date +%s`:cng_var_setup_log\r\e[0K"
- echo -e "section_start:`date +%s`:build_env[collapsed=true]\r\e[0KBuild Environment Variables"
- cat $BUILD_ENV
- echo -e "section_end:`date +%s`:build_env\r\e[0K"
artifacts:
reports:
dotenv: $BUILD_ENV
paths:
- $BUILD_ENV
- $CNG_VAR_SETUP_LOG_FILE
expire_in: 7 days
when: always
@ -66,11 +74,9 @@ include:
TOP_UPSTREAM_SOURCE_SHA: "${TOP_UPSTREAM_SOURCE_SHA}"
TOP_UPSTREAM_SOURCE_REF_SLUG: "${TOP_UPSTREAM_SOURCE_REF_SLUG}"
# prevent cache invalidation between pipeline runs
CACHE_BUSTER: "false"
CACHE_BUSTER: "${CACHE_BUSTER}"
# link component version shas to current project instead of default CI_PIPELINE_CREATED_AT which forces rebuilds on each pipeline run
CONTAINER_VERSION_SUFFIX: "${CI_PROJECT_NAME}"
# skip no-op final-images-listing job
SKIP_JOB_REGEX: /final-images-listing/
CONTAINER_VERSION_SUFFIX: "${CONTAINER_VERSION_SUFFIX}"
# disable buildx cluster while it's not supported on mirrors
DISABLE_BUILDX_CLUSTER: "true"
# disable external gem caching and rely on docker layer caching
@ -79,9 +85,18 @@ include:
SKIP_IMAGE_SIGNING: "true"
SKIP_IMAGE_VERIFICATION: "true"
# set specific arch list
ARCH_LIST: amd64
ARCH_LIST: "${ARCH_LIST}"
# use larger runner for complex rails build jobs
HIGH_CAPACITY_RUNNER_TAG: high-cpu
# skip no-op final-images-listing job or additionally jobs that don't produce new artifacts if skip jobs is enabled
SKIP_JOB_REGEX: "${SKIP_JOB_REGEX}"
# base images and additional args, these are required because jobs that set them might be skipped
DEBIAN_IMAGE: "${DEBIAN_IMAGE}"
DEBIAN_DIGEST: "${DEBIAN_DIGEST}"
DEBIAN_BUILD_ARGS: "${DEBIAN_BUILD_ARGS}"
ALPINE_IMAGE: "${ALPINE_IMAGE}"
ALPINE_DIGEST: "${ALPINE_DIGEST}"
ALPINE_BUILD_ARGS: "${ALPINE_BUILD_ARGS}"
trigger:
project: '${CI_PROJECT_NAMESPACE}/$[[ inputs.cng_path ]]'
branch: $TRIGGER_BRANCH

View File

@ -2378,7 +2378,7 @@
- !reference [".rails:rules:ee-gitlab-duo-chat-base", rules]
- <<: *if-merge-request
changes: *backend-patterns
when: manual
when: never
allow_failure: true
.rails:rules:ee-gitlab-duo-chat-always:
@ -2392,7 +2392,7 @@
- !reference [".rails:rules:ee-gitlab-duo-chat-optional", rules]
- <<: *if-default-branch-refs
changes: *setup-test-env-patterns
when: manual
when: never
allow_failure: true
.rails:rules:db:check-schema:

View File

@ -35,6 +35,7 @@ workflow:
- .e2e-test-base
- .cng-qa-cache # cng-cache includes additional cached helm chart
needs:
- build-cng-env
- build-cng
tags:
- e2e

View File

@ -7,7 +7,6 @@ import LinksLayer from '../../../common/private/job_links_layer.vue';
import { DOWNSTREAM, MAIN, UPSTREAM, ONE_COL_WIDTH, STAGE_VIEW } from '../constants';
import { validateConfigPaths } from '../utils';
import LinkedGraphWrapper from './linked_graph_wrapper.vue';
import LinkedPipelinesColumn from './linked_pipelines_column.vue';
import StageColumnComponent from './stage_column_component.vue';
export default {
@ -15,7 +14,8 @@ export default {
components: {
LinksLayer,
LinkedGraphWrapper,
LinkedPipelinesColumn,
LinkedPipelinesColumn: () =>
import(/* webpackChunkName: 'linked_pipelines_column' */ './linked_pipelines_column.vue'),
StageColumnComponent,
},
props: {

View File

@ -16,7 +16,7 @@ import LinkedPipeline from './linked_pipeline.vue';
export default {
components: {
LinkedPipeline,
PipelineGraph: () => import('./graph_component.vue'),
PipelineGraph: () => import(/* webpackChunkName: 'pipeline_graph' */ './graph_component.vue'),
},
props: {
columnTitle: {

View File

@ -41,7 +41,7 @@ class Admin::SessionsController < ApplicationController
private
def user_is_admin!
render_404 unless current_user&.admin?
render_404 unless current_user&.can_access_admin_area?
end
def two_factor_enabled_for_user?

View File

@ -71,10 +71,7 @@ module SidebarsHelper
admin_mode_active: current_user_mode.admin_mode?,
enter_admin_mode_url: new_admin_session_path,
leave_admin_mode_url: destroy_admin_session_path,
# Usually, using current_user.admin? is discouraged because it does not
# check for admin mode, but since here we want to check admin? and admin mode
# separately, we'll have to ignore the cop rule.
user_is_admin: user.admin? # rubocop: disable Cop/UserAdmin
user_is_admin: user.can_access_admin_area?
},
avatar_url: user.avatar_url,
has_link_to_profile: current_user_menu?(:profile),

View File

@ -8,7 +8,7 @@ module Editable
end
def last_edited_by
return if last_edited_at.blank?
return unless edited?
super || Users::Internal.ghost
end

View File

@ -5,13 +5,8 @@ module Notes
extend ActiveSupport::Concern
included do
# Aliases to make application_helper#edited_time_ago_with_tooltip helper work properly with notes.
# See https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/10392/diffs#note_28719102
alias_attribute :last_edited_by, :updated_by
belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
belongs_to :last_edited_by, class_name: 'User'
has_many :todos
@ -22,13 +17,21 @@ module Notes
validates :author, presence: true
validates :discussion_id, presence: true, format: { with: /\A\h{40}\z/ }
validate :validate_created_after
end
def validate_created_after
return unless created_at
return if created_at >= '1970-01-01'
# Alias to make application_helper#edited_time_ago_with_tooltip helper work properly with notes.
# See https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/10392/diffs#note_28719102
def last_edited_by
updated_by
end
errors.add(:created_at, s_('Note|The created date provided is too far in the past.'))
end
private
def validate_created_after
return unless created_at
return if created_at >= '1970-01-01'
errors.add(:created_at, s_('Note|The created date provided is too far in the past.'))
end
end
end

View File

@ -456,7 +456,7 @@ class Note < ApplicationRecord
# Since we used `updated_at` as `last_edited_at`, it could be touched by transforming / resolving a note.
# This makes sure it is only marked as edited when the note body is updated.
def edited?
return false if updated_by.blank?
return false if read_attribute(:last_edited_at).blank? && updated_by.blank?
super
end

View File

@ -2605,6 +2605,10 @@ class User < ApplicationRecord
support_pin_data&.fetch(:expires_at, nil)
end
def can_access_admin_area?
admin?
end
protected
# override, from Devise::Validatable

View File

@ -8,7 +8,7 @@ class BasePolicy < DeclarativePolicy::Base
next true if user_is_user? && @user.admin_bot?
if Gitlab::CurrentSettings.admin_mode
Gitlab::Auth::CurrentUserMode.new(@user).admin_mode?
@user&.admin? && Gitlab::Auth::CurrentUserMode.new(@user).admin_mode?
else
@user&.admin?
end

View File

@ -21,6 +21,10 @@ module PolicyActor
false
end
def can_access_admin_area?
false
end
def external?
false
end

View File

@ -28,8 +28,6 @@ if (!process.env.DISABLE_EXCLUSIONS) {
// Merge request widget & tabs
'app/assets/javascripts/vue_merge_request_widget/components/checks/constants.js',
'app/assets/javascripts/merge_request_tabs.js',
// CI pipeline
'app/assets/javascripts/ci/pipeline_details/graph/components/graph_component.vue',
// Nested Group projects list
'app/assets/javascripts/vue_shared/components/nested_groups_projects_list/nested_groups_projects_list_item.vue',
]);
@ -65,6 +63,7 @@ module.exports = {
See https://github.com/sverweij/dependency-cruiser/blob/main/doc/options-reference.md#exclude-exclude-dependencies-from-being-cruised
*/
exclude: {
dynamic: true,
path: [],
},
// NOTE: This option is required to resolve aliases from the webpack config

View File

@ -1,8 +0,0 @@
---
name: global_search_issues_tab
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68640
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339207
milestone: '14.3'
type: ops
group: group::global search
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: global_search_merge_requests_tab
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68640
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339207
milestone: '14.3'
type: ops
group: group::global search
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: global_search_snippet_titles_tab
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123668
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/415353
milestone: '16.1'
type: ops
group: group::global search
default_enabled: true

View File

@ -1,8 +0,0 @@
---
name: global_search_users_tab
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84186
rollout_issue_url:
milestone: '14.10'
type: ops
group: group::global search
default_enabled: true

View File

@ -9,36 +9,11 @@ class MigrateGlobalSearchSettingsInApplicationSettings < Gitlab::Database::Migra
end
def up
ApplicationSetting.reset_column_information
application_setting = ApplicationSetting.last
return unless application_setting
# rubocop:disable Gitlab/FeatureFlagWithoutActor -- Does not execute in user context
search = {
global_search_issues_enabled: Feature.enabled?(:global_search_issues_tab, type: :ops),
global_search_merge_requests_enabled: Feature.enabled?(:global_search_merge_requests_tab, type: :ops),
global_search_snippet_titles_enabled: Feature.enabled?(:global_search_snippet_titles_tab, type: :ops),
global_search_users_enabled: Feature.enabled?(:global_search_users_tab, type: :ops)
}
if Gitlab.ee?
search.merge!(
global_search_code_enabled: Feature.enabled?(:global_search_code_tab, type: :ops),
global_search_commits_enabled: Feature.enabled?(:global_search_commits_tab, type: :ops),
global_search_epics_enabled: Feature.enabled?(:global_search_epics_tab, type: :ops),
global_search_wiki_enabled: Feature.enabled?(:global_search_wiki_tab, type: :ops)
)
end
# rubocop:enable Gitlab/FeatureFlagWithoutActor
application_setting.update_columns(search: search, updated_at: Time.current)
# no-op this was just a data migration which is already done in 17.9. The plan is to remove the feature-flags used
# in this migration. So better to disable this migration in 17.11 to avoid any migration issues.
end
def down
application_setting = ApplicationSetting.last
return unless application_setting
application_setting.update_column(:search, {})
# No op
end
end

View File

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

View File

@ -17,240 +17,6 @@ This page contains information about the settings that are used on GitLab.com, a
See some of these settings on the [instance configuration page](https://gitlab.com/help/instance_configuration) of GitLab.com.
## Email confirmation
GitLab.com has the:
- [`email_confirmation_setting`](../../administration/settings/sign_up_restrictions.md#confirm-user-email)
setting set to **Hard**.
- [`unconfirmed_users_delete_after_days`](../../administration/moderate_users.md#automatically-delete-unconfirmed-users)
setting set to three days.
## Password requirements
GitLab.com has the following requirements for passwords on new accounts and password changes:
- Minimum character length 8 characters.
- Maximum character length 128 characters.
- All characters are accepted. For example, `~`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `()`,
`[]`, `_`, `+`, `=`, and `-`.
## SSH key restrictions
GitLab.com uses the default [SSH key restrictions](../../security/ssh_keys_restrictions.md).
## SSH host keys fingerprints
Go to the current instance configuration to see the SSH host key fingerprints on
GitLab.com.
1. Sign in to GitLab.
1. On the left sidebar, select **Help** ({{< icon name="question-o" >}}) > **Help**.
1. On the Help page, select **Check the current instance configuration**.
In the instance configuration, you see the **SSH host key fingerprints**:
| Algorithm | MD5 (deprecated) | SHA256 |
|------------------|------------------|---------|
| ECDSA | `f1:d0:fb:46:73:7a:70:92:5a:ab:5d:ef:43:e2:1c:35` | `SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw` |
| ED25519 | `2e:65:6a:c8:cf:bf:b2:8b:9a:bd:6d:9f:11:5c:12:16` | `SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8` |
| RSA | `b6:03:0e:39:97:9e:d0:e7:24:ce:a3:77:3e:01:42:09` | `SHA256:ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ` |
The first time you connect to a GitLab.com repository, one of these keys is
displayed in the output.
## SSH `known_hosts` entries
Add the following to `.ssh/known_hosts` to skip manual fingerprint
confirmation in SSH:
```plaintext
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
```
## Mail configuration
GitLab.com sends emails from the `mg.gitlab.com` domain by using [Mailgun](https://www.mailgun.com/),
and has its own dedicated IP addresses:
- `23.253.183.236`
- `69.72.35.190`
- `69.72.44.107`
- `159.135.226.146`
- `161.38.202.219`
- `192.237.158.143`
- `192.237.159.239`
- `198.61.254.136`
- `198.61.254.160`
- `209.61.151.122`
The IP addresses for `mg.gitlab.com` are subject to change at any time.
### Service Desk alias email address
On GitLab.com, there's a mailbox configured for Service Desk with the email address:
`contact-project+%{key}@incoming.gitlab.com`. To use this mailbox, configure the
[custom suffix](../project/service_desk/configure.md#configure-a-suffix-for-service-desk-alias-email) in project
settings.
## Backups
[See our backup strategy](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/#backups).
To back up an entire project on GitLab.com, you can export it either:
- [Through the UI](../project/settings/import_export.md).
- [Through the API](../../api/project_import_export.md#schedule-an-export). You
can also use the API to programmatically upload exports to a storage platform,
such as Amazon S3.
With exports, be aware of [what is and is not](../project/settings/import_export.md#project-items-that-are-exported)
included in a project export.
GitLab is built on Git, so you can back up just the repository of a project by cloning it to another computer.
Similarly, you can clone a project's wiki to back it up. All files
[uploaded after August 22, 2020](../project/wiki/_index.md#create-a-new-wiki-page)
are included when cloning.
## Delayed group deletion
{{< details >}}
- Tier: Premium, Ultimate
- Offering: GitLab.com
{{< /details >}}
After May 08, 2023, all groups have delayed deletion enabled by default.
Groups are permanently deleted after a seven-day delay.
If you are on the Free tier, your groups are immediately deleted, and you will not be able to restore them.
You can [view and restore groups marked for deletion](../group/_index.md#restore-a-group).
## Delayed project deletion
{{< details >}}
- Tier: Premium, Ultimate
- Offering: GitLab.com
{{< /details >}}
After May 08, 2023, all groups have delayed project deletion enabled by default.
Projects are permanently deleted after a seven-day delay.
If you are on the Free tier, your projects are immediately deleted, and you will not be able to restore them.
You can [view and restore projects marked for deletion](../project/working_with_projects.md#restore-a-project).
## Inactive project deletion
[Inactive project deletion](../../administration/inactive_project_deletion.md) is disabled on GitLab.com.
## Alternative SSH port
GitLab.com can be reached by using a [different SSH port](https://about.gitlab.com/blog/2016/02/18/gitlab-dot-com-now-supports-an-alternate-git-plus-ssh-port/) for `git+ssh`.
| Setting | Value |
|------------|---------------------|
| `Hostname` | `altssh.gitlab.com` |
| `Port` | `443` |
An example `~/.ssh/config` is the following:
```plaintext
Host gitlab.com
Hostname altssh.gitlab.com
User git
Port 443
PreferredAuthentications publickey
IdentityFile ~/.ssh/gitlab
```
## GitLab Pages
Some settings for [GitLab Pages](../project/pages/_index.md) differ from the
[defaults for self-managed instances](../../administration/pages/_index.md):
| Setting | GitLab.com |
|:--------------------------------------------------|:-----------------------|
| Domain name | `gitlab.io` |
| IP address | `35.185.44.232` |
| Support for custom domains | {{< icon name="check-circle" >}} Yes |
| Support for TLS certificates | {{< icon name="check-circle" >}} Yes |
| Maximum site size | 1 GB |
| Number of custom domains for each GitLab Pages website | 150 |
The maximum size of your Pages site depends on the maximum artifact size,
which is part of [GitLab CI/CD](#gitlab-cicd).
[Rate limits](#gitlabcom-specific-rate-limits) also exist for GitLab Pages.
## GitLab container registry
| Setting | GitLab.com | Default (self-managed) |
|:---------------------------------------|:---------------------------------|------------------------|
| Domain name | `registry.gitlab.com` | |
| IP address | `35.227.35.254` | |
| CDN domain name | `cdn.registry.gitlab-static.net` | |
| CDN IP address | `34.149.22.116` | |
| Authorization token duration (minutes) | `15` | See [increase container registry token duration](../../administration/packages/container_registry.md#increase-token-duration). |
To use the GitLab container registry, Docker clients must have access to:
- The registry endpoint and GitLab.com for authorization.
- Google Cloud Storage or Google Cloud Content Delivery Network to download images.
GitLab.com is fronted by Cloudflare.
For incoming connections to GitLab.com, you must allow CIDR blocks of Cloudflare
([IPv4](https://www.cloudflare.com/ips-v4/) and [IPv6](https://www.cloudflare.com/ips-v6/)).
## GitLab CI/CD
Below are the current settings regarding [GitLab CI/CD](../../ci/_index.md).
Any settings or feature limits not listed here are using the defaults listed in
the related documentation.
| Setting | GitLab.com | Default (GitLab Self-Managed) |
|----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|------------------------|
| Artifacts maximum size (compressed) | 1 GB | See [Maximum artifacts size](../../administration/settings/continuous_integration.md#maximum-artifacts-size). |
| Artifacts [expiry time](../../ci/yaml/_index.md#artifactsexpire_in) | 30 days unless otherwise specified | See [Default artifacts expiration](../../administration/settings/continuous_integration.md#default-artifacts-expiration). Artifacts created before June 22, 2020 have no expiry. |
| Scheduled Pipeline Cron | `*/5 * * * *` | See [Pipeline schedules advanced configuration](../../administration/cicd/_index.md#change-maximum-scheduled-pipeline-frequency). |
| Maximum jobs in active pipelines | `500` for Free tier, `1000` for all trial tiers, `20000` for Premium, and `100000` for Ultimate. | See [Number of jobs in active pipelines](../../administration/instance_limits.md#number-of-jobs-in-active-pipelines). |
| Maximum CI/CD subscriptions to a project | `2` | See [Number of CI/CD subscriptions to a project](../../administration/instance_limits.md#number-of-cicd-subscriptions-to-a-project). |
| Maximum number of pipeline triggers in a project | `25000` | See [Limit the number of pipeline triggers](../../administration/instance_limits.md#limit-the-number-of-pipeline-triggers). |
| Maximum pipeline schedules in projects | `10` for Free tier, `50` for all paid tiers | See [Number of pipeline schedules](../../administration/instance_limits.md#number-of-pipeline-schedules). |
| Maximum pipelines for each schedule | `24` for Free tier, `288` for all paid tiers | See [Limit the number of pipelines created by a pipeline schedule each day](../../administration/instance_limits.md#limit-the-number-of-pipelines-created-by-a-pipeline-schedule-each-day). |
| Maximum number of schedule rules defined for each security policy project | Unlimited for all paid tiers | See [Number of schedule rules defined for each security policy project](../../administration/instance_limits.md#limit-the-number-of-schedule-rules-defined-for-security-policy-project). |
| Scheduled job archiving | 3 months | Never. Jobs created before June 22, 2020 were archived after September 22, 2020. |
| Maximum test cases for each [unit test report](../../ci/testing/unit_test_reports.md) | `500000` | Unlimited. |
| Maximum registered runners | Free tier: `50` for each group and `50`for each project<br/>All paid tiers: `1000` for each group and `1000` for each project | See [Number of registered runners for each scope](../../administration/instance_limits.md#number-of-registered-runners-for-each-scope). |
| Limit of dotenv variables | Free tier: `50`<br>Premium tier: `100`<br>Ultimate tier: `150` | See [Limit dotenv variables](../../administration/instance_limits.md#limit-dotenv-variables). |
| Maximum downstream pipeline trigger rate (for a given project, user, and commit) | `350` each minute | See [Maximum downstream pipeline trigger rate](../../administration/settings/continuous_integration.md#maximum-downstream-pipeline-trigger-rate). |
## Package registry limits
The [maximum file size](../../administration/instance_limits.md#file-size-limits)
for a package uploaded to the [GitLab package registry](../packages/package_registry/_index.md)
varies by format:
| Package type | GitLab.com |
|------------------------|------------------------------------|
| Conan | 5 GB |
| Generic | 5 GB |
| Helm | 5 MB |
| Maven | 5 GB |
| npm | 5 GB |
| NuGet | 5 GB |
| PyPI | 5 GB |
| Terraform | 1 GB |
| Machine learning model | 10 GB (uploads are capped at 5 GB) |
## Account and limit settings
GitLab.com has the following account limits enabled. If a setting is not listed,
@ -280,104 +46,172 @@ this limit. Repository limits apply to both public and private projects.
{{< /alert >}}
## Default import sources
## Backups
The [import sources](../project/import/_index.md#supported-import-sources) that are available to you by default depend on
which GitLab you use:
[See our backup strategy](https://handbook.gitlab.com/handbook/engineering/infrastructure/production/#backups).
- GitLab.com: All available import sources are enabled by default.
- GitLab Self-Managed: No import sources are enabled by default and must be
[enabled](../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
To back up an entire project on GitLab.com, you can export it either:
## Import placeholder user limits
- [Through the UI](../project/settings/import_export.md).
- [Through the API](../../api/project_import_export.md#schedule-an-export). You
can also use the API to programmatically upload exports to a storage platform,
such as Amazon S3.
The number of [placeholder users](../project/import/_index.md#placeholder-users) created during an import on GitLab.com is limited for each top-level namespace. The limits
differ depending on your plan and seat count.
For more information, see the [table of placeholder user limits for GitLab.com](../project/import/_index.md#placeholder-user-limits).
With exports, be aware of [what is and is not](../project/settings/import_export.md#project-items-that-are-exported)
included in a project export.
## IP range
GitLab is built on Git, so you can back up just the repository of a project by cloning it to another computer.
Similarly, you can clone a project's wiki to back it up. All files
[uploaded after August 22, 2020](../project/wiki/_index.md#create-a-new-wiki-page)
are included when cloning.
GitLab.com uses the IP ranges `34.74.90.64/28` and `34.74.226.0/24` for traffic from its Web/API
fleet. This whole range is solely allocated to GitLab. You can expect connections from webhooks or repository mirroring to come
from those IPs and allow them.
## Email confirmation
GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com, you might need to allow CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4/) and [IPv6](https://www.cloudflare.com/ips-v6/)).
GitLab.com has the:
For outgoing connections from CI/CD runners, we are not providing static IP addresses.
Most GitLab.com instance runners are deployed into Google Cloud in `us-east1`, except _Linux GPU-enabled_ and _Linux Arm64_, hosted in `us-central1`.
You can configure any IP-based firewall by looking up
[IP address ranges or CIDR blocks for GCP](https://cloud.google.com/compute/docs/faq#find_ip_range).
MacOS runners are hosted on AWS with runner managers hosted on Google Cloud. To configure IP-based firewall, you must allow both [AWS IP address ranges](https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html) and [Google Cloud](https://cloud.google.com/compute/docs/faq#find_ip_range).
- [`email_confirmation_setting`](../../administration/settings/sign_up_restrictions.md#confirm-user-email)
setting set to **Hard**.
- [`unconfirmed_users_delete_after_days`](../../administration/moderate_users.md#automatically-delete-unconfirmed-users)
setting set to three days.
## Hostname list
## GitLab CI/CD
Add these hostnames when you configure allow-lists in local HTTP(S) proxies,
or other web-blocking software that governs end-user computers. Pages on
GitLab.com load content from these hostnames:
Below are the current settings regarding [GitLab CI/CD](../../ci/_index.md).
Any settings or feature limits not listed here are using the defaults listed in
the related documentation.
- `gitlab.com`
- `*.gitlab.com`
- `*.gitlab-static.net`
- `*.gitlab.io`
- `*.gitlab.net`
| Setting | GitLab.com | Default (GitLab Self-Managed) |
|----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------|------------------------|
| Artifacts maximum size (compressed) | 1 GB | See [Maximum artifacts size](../../administration/settings/continuous_integration.md#maximum-artifacts-size). |
| Artifacts [expiry time](../../ci/yaml/_index.md#artifactsexpire_in) | 30 days unless otherwise specified | See [Default artifacts expiration](../../administration/settings/continuous_integration.md#default-artifacts-expiration). Artifacts created before June 22, 2020 have no expiry. |
| Scheduled Pipeline Cron | `*/5 * * * *` | See [Pipeline schedules advanced configuration](../../administration/cicd/_index.md#change-maximum-scheduled-pipeline-frequency). |
| Maximum jobs in active pipelines | `500` for Free tier, `1000` for all trial tiers, `20000` for Premium, and `100000` for Ultimate. | See [Number of jobs in active pipelines](../../administration/instance_limits.md#number-of-jobs-in-active-pipelines). |
| Maximum CI/CD subscriptions to a project | `2` | See [Number of CI/CD subscriptions to a project](../../administration/instance_limits.md#number-of-cicd-subscriptions-to-a-project). |
| Maximum number of pipeline triggers in a project | `25000` | See [Limit the number of pipeline triggers](../../administration/instance_limits.md#limit-the-number-of-pipeline-triggers). |
| Maximum pipeline schedules in projects | `10` for Free tier, `50` for all paid tiers | See [Number of pipeline schedules](../../administration/instance_limits.md#number-of-pipeline-schedules). |
| Maximum pipelines for each schedule | `24` for Free tier, `288` for all paid tiers | See [Limit the number of pipelines created by a pipeline schedule each day](../../administration/instance_limits.md#limit-the-number-of-pipelines-created-by-a-pipeline-schedule-each-day). |
| Maximum number of schedule rules defined for each security policy project | Unlimited for all paid tiers | See [Number of schedule rules defined for each security policy project](../../administration/instance_limits.md#limit-the-number-of-schedule-rules-defined-for-security-policy-project). |
| Scheduled job archiving | 3 months | Never. Jobs created before June 22, 2020 were archived after September 22, 2020. |
| Maximum test cases for each [unit test report](../../ci/testing/unit_test_reports.md) | `500000` | Unlimited. |
| Maximum registered runners | Free tier: `50` for each group and `50`for each project<br/>All paid tiers: `1000` for each group and `1000` for each project | See [Number of registered runners for each scope](../../administration/instance_limits.md#number-of-registered-runners-for-each-scope). |
| Limit of dotenv variables | Free tier: `50`<br>Premium tier: `100`<br>Ultimate tier: `150` | See [Limit dotenv variables](../../administration/instance_limits.md#limit-dotenv-variables). |
| Maximum downstream pipeline trigger rate (for a given project, user, and commit) | `350` each minute | See [Maximum downstream pipeline trigger rate](../../administration/settings/continuous_integration.md#maximum-downstream-pipeline-trigger-rate). |
Documentation and Company pages served over `docs.gitlab.com` and `about.gitlab.com`
also load certain page content directly from common public CDN hostnames.
## GitLab container registry
## Webhooks
| Setting | GitLab.com | Default (self-managed) |
|:---------------------------------------|:---------------------------------|------------------------|
| Domain name | `registry.gitlab.com` | |
| IP address | `35.227.35.254` | |
| CDN domain name | `cdn.registry.gitlab-static.net` | |
| CDN IP address | `34.149.22.116` | |
| Authorization token duration (minutes) | `15` | See [increase container registry token duration](../../administration/packages/container_registry.md#increase-token-duration). |
The following limits apply for [webhooks](../project/integrations/webhooks.md).
To use the GitLab container registry, Docker clients must have access to:
### Rate limits
- The registry endpoint and GitLab.com for authorization.
- Google Cloud Storage or Google Cloud Content Delivery Network to download images.
For each top-level namespace, the number of times each minute that a webhook can be called.
The limit varies depending on your plan and the number of seats in your subscription.
GitLab.com is fronted by Cloudflare.
For incoming connections to GitLab.com, you must allow CIDR blocks of Cloudflare
([IPv4](https://www.cloudflare.com/ips-v4/) and [IPv6](https://www.cloudflare.com/ips-v6/)).
| Plan | Default for GitLab.com |
|----------------------|-------------------------|
| Free | `500` |
| Premium | `99` seats or fewer: `1,600`<br>`100-399` seats: `2,800`<br>`400` seats or more: `4,000` |
| Ultimate and open source |`999` seats or fewer: `6,000`<br>`1,000-4,999` seats: `9,000`<br>`5,000` seats or more: `13,000` |
## GitLab Pages
### Other limits
Some settings for [GitLab Pages](../project/pages/_index.md) differ from the
[defaults for self-managed instances](../../administration/pages/_index.md):
| Setting | Default for GitLab.com |
|:--------------------------------------------------------------------|:-----------------------|
| Number of webhooks | 100 for each project, 50 for each group (subgroup webhooks are not counted towards parent group limits ) |
| Maximum payload size | 25 MB |
| Timeout | 10 seconds |
| [Parallel Pages deployments](../project/pages/parallel_deployments.md#limits) | 100 extra deployments (Premium tier), 500 extra deployments (Ultimate tier) |
| Setting | GitLab.com |
|:--------------------------------------------------|:-----------------------|
| Domain name | `gitlab.io` |
| IP address | `35.185.44.232` |
| Support for custom domains | {{< icon name="check-circle" >}} Yes |
| Support for TLS certificates | {{< icon name="check-circle" >}} Yes |
| Maximum site size | 1 GB |
| Number of custom domains for each GitLab Pages website | 150 |
For self-managed instance limits, see:
The maximum size of your Pages site depends on the maximum artifact size,
which is part of [GitLab CI/CD](#gitlab-cicd).
- [Webhook rate limit](../../administration/instance_limits.md#webhook-rate-limit).
- [Number of webhooks](../../administration/instance_limits.md#number-of-webhooks).
- [Webhook timeout](../../administration/instance_limits.md#webhook-timeout).
- [Parallel Pages deployments](../../administration/instance_limits.md#number-of-parallel-pages-deployments).
[Rate limits](#gitlabcom-specific-rate-limits) also exist for GitLab Pages.
## GitLab-hosted runners
## GitLab.com at scale
You can use GitLab-hosted runners to run your CI/CD jobs on GitLab.com and GitLab Dedicated to seamlessly build, test, and deploy your application on different environments.
In addition to the GitLab Enterprise Edition Linux package install, GitLab.com uses
the following applications and settings to achieve scale. All settings are
publicly available, as [Kubernetes configuration](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com)
or [Chef cookbooks](https://gitlab.com/gitlab-cookbooks).
For more information, see [GitLab-hosted runners](../../ci/runners/_index.md).
### Elastic cluster
## Puma
We use Elasticsearch and Kibana for part of our monitoring solution:
GitLab.com uses the default of 60 seconds for [Puma request timeouts](../../administration/operations/puma.md#change-the-worker-timeout).
- [`gitlab-cookbooks` / `gitlab-elk` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-elk)
- [`gitlab-cookbooks` / `gitlab_elasticsearch` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab_elasticsearch)
## Maximum number of reviewers and assignees
### Fluentd
{{< history >}}
We use Fluentd to unify our GitLab logs:
- Maximum assignees [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368936) in GitLab 15.6.
- Maximum reviewers [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366485) in GitLab 15.9.
- [`gitlab-cookbooks` / `gitlab_fluentd` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab_fluentd)
{{< /history >}}
### Prometheus
Merge requests enforce these maximums:
Prometheus complete our monitoring stack:
- Maximum assignees: 200
- Maximum reviewers: 200
- [`gitlab-cookbooks` / `gitlab-prometheus` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-prometheus)
### Grafana
For the visualization of monitoring data:
- [`gitlab-cookbooks` / `gitlab-grafana` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-grafana)
### Sentry
Open source error tracking:
- [`gitlab-cookbooks` / `gitlab-sentry` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-sentry)
### Consul
Service discovery:
- [`gitlab-cookbooks` / `gitlab_consul` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab_consul)
### HAProxy
High Performance TCP/HTTP Load Balancer:
- [`gitlab-cookbooks` / `gitlab-haproxy` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-haproxy)
## GitLab.com logging
We use [Fluentd](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#fluentd)
to parse our logs. Fluentd sends our logs to
[Stackdriver Logging](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#stackdriver)
and [Cloud Pub/Sub](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#cloud-pubsub).
Stackdriver is used for storing logs long-term in Google Cold Storage (GCS).
Cloud Pub/Sub is used to forward logs to an [Elastic cluster](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#elastic) using [`pubsubbeat`](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#pubsubbeat-vms).
You can view more information in our runbooks such as:
- A [detailed list of what we're logging](https://gitlab.com/gitlab-com/runbooks/-/tree/master/docs/logging#what-are-we-logging)
- Our [current log retention policies](https://gitlab.com/gitlab-com/runbooks/-/tree/master/docs/logging#retention)
- A [diagram of our logging infrastructure](https://gitlab.com/gitlab-com/runbooks/-/tree/master/docs/logging#logging-infrastructure-overview)
### Job logs
By default, GitLab does not expire job logs. Job logs are retained indefinitely,
and can't be configured on GitLab.com to expire. You can erase job logs
[manually with the Jobs API](../../api/jobs.md#erase-a-job) or by
[deleting a pipeline](../../ci/pipelines/_index.md#delete-a-pipeline)
## GitLab.com-specific Gitaly RPC concurrency limits
Per-repository Gitaly RPC concurrency and queuing limits are configured for different types of Git operations such as `git clone`. When these limits are exceeded, a `fatal: remote error: GitLab is currently unable to handle this request due to load` message is returned to the client.
For administrator documentation, see [limit RPC concurrency](../../administration/gitaly/concurrency_limiting.md#limit-rpc-concurrency).
## GitLab.com-specific rate limits
@ -534,90 +368,98 @@ See [non-configurable limits](../../security/rate_limits.md#non-configurable-lim
for information on rate limits that are not configurable, and therefore also
used on GitLab.com.
## GitLab.com-specific Gitaly RPC concurrency limits
## GitLab-hosted runners
Per-repository Gitaly RPC concurrency and queuing limits are configured for different types of Git operations such as `git clone`. When these limits are exceeded, a `fatal: remote error: GitLab is currently unable to handle this request due to load` message is returned to the client.
You can use GitLab-hosted runners to run your CI/CD jobs on GitLab.com and GitLab Dedicated to seamlessly build, test, and deploy your application on different environments.
For administrator documentation, see [limit RPC concurrency](../../administration/gitaly/concurrency_limiting.md#limit-rpc-concurrency).
For more information, see [GitLab-hosted runners](../../ci/runners/_index.md).
## GitLab.com logging
## Hostname list
We use [Fluentd](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#fluentd)
to parse our logs. Fluentd sends our logs to
[Stackdriver Logging](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#stackdriver)
and [Cloud Pub/Sub](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#cloud-pubsub).
Stackdriver is used for storing logs long-term in Google Cold Storage (GCS).
Cloud Pub/Sub is used to forward logs to an [Elastic cluster](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#elastic) using [`pubsubbeat`](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#pubsubbeat-vms).
Add these hostnames when you configure allow-lists in local HTTP(S) proxies,
or other web-blocking software that governs end-user computers. Pages on
GitLab.com load content from these hostnames:
You can view more information in our runbooks such as:
- `gitlab.com`
- `*.gitlab.com`
- `*.gitlab-static.net`
- `*.gitlab.io`
- `*.gitlab.net`
- A [detailed list of what we're logging](https://gitlab.com/gitlab-com/runbooks/-/tree/master/docs/logging#what-are-we-logging)
- Our [current log retention policies](https://gitlab.com/gitlab-com/runbooks/-/tree/master/docs/logging#retention)
- A [diagram of our logging infrastructure](https://gitlab.com/gitlab-com/runbooks/-/tree/master/docs/logging#logging-infrastructure-overview)
Documentation and Company pages served over `docs.gitlab.com` and `about.gitlab.com`
also load certain page content directly from common public CDN hostnames.
### Job logs
## Imports
By default, GitLab does not expire job logs. Job logs are retained indefinitely,
and can't be configured on GitLab.com to expire. You can erase job logs
[manually with the Jobs API](../../api/jobs.md#erase-a-job) or by
[deleting a pipeline](../../ci/pipelines/_index.md#delete-a-pipeline).
Settings related to importing data into GitLab.
## GitLab.com at scale
### Default import sources
In addition to the GitLab Enterprise Edition Linux package install, GitLab.com uses
the following applications and settings to achieve scale. All settings are
publicly available, as [Kubernetes configuration](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com)
or [Chef cookbooks](https://gitlab.com/gitlab-cookbooks).
The [import sources](../project/import/_index.md#supported-import-sources) that are available to you by default depend on
which GitLab you use:
### Elastic cluster
- GitLab.com: All available import sources are enabled by default.
- GitLab Self-Managed: No import sources are enabled by default and must be
[enabled](../../administration/settings/import_and_export_settings.md#configure-allowed-import-sources).
We use Elasticsearch and Kibana for part of our monitoring solution:
### Import placeholder user limits
- [`gitlab-cookbooks` / `gitlab-elk` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-elk)
- [`gitlab-cookbooks` / `gitlab_elasticsearch` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab_elasticsearch)
The number of [placeholder users](../project/import/_index.md#placeholder-users) created during an import on GitLab.com is limited for each top-level namespace. The limits
differ depending on your plan and seat count.
For more information, see the [table of placeholder user limits for GitLab.com](../project/import/_index.md#placeholder-user-limits).
### Fluentd
## IP range
We use Fluentd to unify our GitLab logs:
GitLab.com uses the IP ranges `34.74.90.64/28` and `34.74.226.0/24` for traffic from its Web/API
fleet. This whole range is solely allocated to GitLab. You can expect connections from webhooks or repository mirroring to come
from those IPs and allow them.
- [`gitlab-cookbooks` / `gitlab_fluentd` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab_fluentd)
GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com, you might need to allow CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4/) and [IPv6](https://www.cloudflare.com/ips-v6/)).
### Prometheus
For outgoing connections from CI/CD runners, we are not providing static IP addresses.
Most GitLab.com instance runners are deployed into Google Cloud in `us-east1`, except _Linux GPU-enabled_ and _Linux Arm64_, hosted in `us-central1`.
You can configure any IP-based firewall by looking up
[IP address ranges or CIDR blocks for GCP](https://cloud.google.com/compute/docs/faq#find_ip_range).
MacOS runners are hosted on AWS with runner managers hosted on Google Cloud. To configure IP-based firewall, you must allow both [AWS IP address ranges](https://docs.aws.amazon.com/vpc/latest/userguide/aws-ip-ranges.html) and [Google Cloud](https://cloud.google.com/compute/docs/faq#find_ip_range).
Prometheus complete our monitoring stack:
## Mail configuration
- [`gitlab-cookbooks` / `gitlab-prometheus` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-prometheus)
GitLab.com sends emails from the `mg.gitlab.com` domain by using [Mailgun](https://www.mailgun.com/),
and has its own dedicated IP addresses:
### Grafana
- `23.253.183.236`
- `69.72.35.190`
- `69.72.44.107`
- `159.135.226.146`
- `161.38.202.219`
- `192.237.158.143`
- `192.237.159.239`
- `198.61.254.136`
- `198.61.254.160`
- `209.61.151.122`
For the visualization of monitoring data:
The IP addresses for `mg.gitlab.com` are subject to change at any time.
- [`gitlab-cookbooks` / `gitlab-grafana` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-grafana)
### Service Desk alias email address
### Sentry
On GitLab.com, there's a mailbox configured for Service Desk with the email address:
`contact-project+%{key}@incoming.gitlab.com`. To use this mailbox, configure the
[custom suffix](../project/service_desk/configure.md#configure-a-suffix-for-service-desk-alias-email) in project
settings.
Open source error tracking:
## Maximum number of reviewers and assignees
- [`gitlab-cookbooks` / `gitlab-sentry` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-sentry)
{{< history >}}
### Consul
- Maximum assignees [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/368936) in GitLab 15.6.
- Maximum reviewers [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366485) in GitLab 15.9.
Service discovery:
{{< /history >}}
- [`gitlab-cookbooks` / `gitlab_consul` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab_consul)
Merge requests enforce these maximums:
### HAProxy
High Performance TCP/HTTP Load Balancer:
- [`gitlab-cookbooks` / `gitlab-haproxy` · GitLab](https://gitlab.com/gitlab-cookbooks/gitlab-haproxy)
## Sidekiq
GitLab.com runs [Sidekiq](https://sidekiq.org) as an [external process](../../administration/sidekiq/_index.md)
for Ruby job scheduling.
The current settings are in the [GitLab.com Kubernetes pod configuration](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com/-/blob/master/releases/gitlab/values/gprd.yaml.gotmpl).
- Maximum assignees: 200
- Maximum reviewers: 200
## Merge request limits
@ -639,3 +481,174 @@ This feature is available for testing, but not ready for production use.
GitLab limits each merge request to 1000 [diff versions](../project/merge_requests/versions.md).
Merge requests that reach this limit cannot be updated further. Instead,
close the affected merge request and create a new merge request.
## Password requirements
GitLab.com has the following requirements for passwords on new accounts and password changes:
- Minimum character length 8 characters.
- Maximum character length 128 characters.
- All characters are accepted. For example, `~`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `()`,
`[]`, `_`, `+`, `=`, and `-`.
## Project and group deletion
Settings related to the deletion of projects and groups.
### Delayed group deletion
{{< details >}}
- Tier: Premium, Ultimate
- Offering: GitLab.com
{{< /details >}}
After May 08, 2023, all groups have delayed deletion enabled by default.
Groups are permanently deleted after a seven-day delay.
If you are on the Free tier, your groups are immediately deleted, and you will not be able to restore them.
You can [view and restore groups marked for deletion](../group/_index.md#restore-a-group).
### Delayed project deletion
{{< details >}}
- Tier: Premium, Ultimate
- Offering: GitLab.com
{{< /details >}}
After May 08, 2023, all groups have delayed project deletion enabled by default.
Projects are permanently deleted after a seven-day delay.
If you are on the Free tier, your projects are immediately deleted, and you will not be able to restore them.
You can [view and restore projects marked for deletion](../project/working_with_projects.md#restore-a-project).
### Inactive project deletion
[Inactive project deletion](../../administration/inactive_project_deletion.md) is disabled on GitLab.com.
## Package registry limits
The [maximum file size](../../administration/instance_limits.md#file-size-limits)
for a package uploaded to the [GitLab package registry](../packages/package_registry/_index.md)
varies by format:
| Package type | GitLab.com |
|------------------------|------------------------------------|
| Conan | 5 GB |
| Generic | 5 GB |
| Helm | 5 MB |
| Maven | 5 GB |
| npm | 5 GB |
| NuGet | 5 GB |
| PyPI | 5 GB |
| Terraform | 1 GB |
| Machine learning model | 10 GB (uploads are capped at 5 GB) |
## Puma
GitLab.com uses the default of 60 seconds for [Puma request timeouts](../../administration/operations/puma.md#change-the-worker-timeout).
## Sidekiq
GitLab.com runs [Sidekiq](https://sidekiq.org) as an [external process](../../administration/sidekiq/_index.md)
for Ruby job scheduling.
The current settings are in the [GitLab.com Kubernetes pod configuration](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com/-/blob/master/releases/gitlab/values/gprd.yaml.gotmpl).
## SSH keys and authentication
Settings related to authentication with SSH. For information about maximum connections,
see [SSH maximum number of connections](#ssh-maximum-number-of-connections).
### Alternative SSH port
GitLab.com can be reached by using a [different SSH port](https://about.gitlab.com/blog/2016/02/18/gitlab-dot-com-now-supports-an-alternate-git-plus-ssh-port/) for `git+ssh`.
| Setting | Value |
|------------|---------------------|
| `Hostname` | `altssh.gitlab.com` |
| `Port` | `443` |
An example `~/.ssh/config` is the following:
```plaintext
Host gitlab.com
Hostname altssh.gitlab.com
User git
Port 443
PreferredAuthentications publickey
IdentityFile ~/.ssh/gitlab
```
### SSH host keys fingerprints
Go to the current instance configuration to see the SSH host key fingerprints on
GitLab.com.
1. Sign in to GitLab.
1. On the left sidebar, select **Help** ({{< icon name="question-o" >}}) > **Help**.
1. On the Help page, select **Check the current instance configuration**.
In the instance configuration, you see the **SSH host key fingerprints**:
| Algorithm | MD5 (deprecated) | SHA256 |
|------------------|------------------|---------|
| ECDSA | `f1:d0:fb:46:73:7a:70:92:5a:ab:5d:ef:43:e2:1c:35` | `SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw` |
| ED25519 | `2e:65:6a:c8:cf:bf:b2:8b:9a:bd:6d:9f:11:5c:12:16` | `SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8` |
| RSA | `b6:03:0e:39:97:9e:d0:e7:24:ce:a3:77:3e:01:42:09` | `SHA256:ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ` |
The first time you connect to a GitLab.com repository, one of these keys is
displayed in the output.
### SSH key restrictions
GitLab.com uses the default [SSH key restrictions](../../security/ssh_keys_restrictions.md).
### SSH `known_hosts` entries
Add the following to `.ssh/known_hosts` to skip manual fingerprint
confirmation in SSH:
```plaintext
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
```
## Webhooks
The following limits apply for [webhooks](../project/integrations/webhooks.md).
### Rate limits
For each top-level namespace, the number of times each minute that a webhook can be called.
The limit varies depending on your plan and the number of seats in your subscription.
| Plan | Default for GitLab.com |
|----------------------|-------------------------|
| Free | `500` |
| Premium | `99` seats or fewer: `1,600`<br>`100-399` seats: `2,800`<br>`400` seats or more: `4,000` |
| Ultimate and open source |`999` seats or fewer: `6,000`<br>`1,000-4,999` seats: `9,000`<br>`5,000` seats or more: `13,000` |
### Other limits
| Setting | Default for GitLab.com |
|:--------------------------------------------------------------------|:-----------------------|
| Number of webhooks | 100 for each project, 50 for each group (subgroup webhooks are not counted towards parent group limits ) |
| Maximum payload size | 25 MB |
| Timeout | 10 seconds |
| [Parallel Pages deployments](../project/pages/parallel_deployments.md#limits) | 100 extra deployments (Premium tier), 500 extra deployments (Ultimate tier) |
For self-managed instance limits, see:
- [Webhook rate limit](../../administration/instance_limits.md#webhook-rate-limit).
- [Number of webhooks](../../administration/instance_limits.md#number-of-webhooks).
- [Webhook timeout](../../administration/instance_limits.md#webhook-timeout).
- [Parallel Pages deployments](../../administration/instance_limits.md#number-of-parallel-pages-deployments)..

View File

@ -19,7 +19,7 @@ design files, videos, and other non-text content.
GitLab supports two different types of file locking:
- [Exclusive file locks](../../topics/git/file_management.md#file-locks): Applied through the
command line with Git LFS and `.gitattributes`.
command line with Git LFS and [`.gitattributes`](../../user/project/repository/files/git_attributes.md).
These locks prevent modifications to locked files on any branch.
- [Default branch file and directory locks](#default-branch-file-and-directory-locks): Applied
through the GitLab UI. These locks prevent modifications to files and directories on the
@ -27,7 +27,7 @@ GitLab supports two different types of file locking:
## Permissions
You can create file locks if you have at least the Developer role for the project.
You must have at least the Developer role for the project to create, view, or manage file locks.
For more information, see [Roles and permissions](../../user/permissions.md).
## Default branch file and directory locks
@ -60,6 +60,10 @@ to be aware of in-flight work without restricting their workflow on other branch
## Lock a file or directory
Prerequisites:
- You must have at least the Developer role for the project.
To lock a file or directory:
1. On the left sidebar, select **Search or go to** and find your project.
@ -74,17 +78,41 @@ for locked files, see [issue 4623](https://gitlab.com/gitlab-org/gitlab/-/issues
## View and remove locks
Locks can be removed by:
- The user who created the lock.
- Any user with at least the Maintainer role for the project.
To view and manage file locks:
To view locked files:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Locked files**.
This list displays all files locked either through Git LFS exclusive locks or the GitLab UI.
The **Locked files** page displays all files locked with either Git LFS exclusive locks or the GitLab UI.
Prerequisites:
- You must be the user who created the lock.
- You must have at least the Maintainer role for the project.
To remove a lock:
{{< tabs >}}
{{< tab title="From a file" >}}
1. On the left sidebar, select **Search or go to** and find your project.
1. Go to the file you want to unlock.
1. Select **Unlock**.
1. On the confirmation dialog, select **Unlock**.
{{< /tab >}}
{{< tab title="From the Locked file page" >}}
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Code > Locked files**.
1. To the right of the file you want to unlock, select **Unlock**.
1. On the confirmation dialog, select **OK**.
{{< /tab >}}
{{< /tabs >}}
## Related topics

View File

@ -91,7 +91,7 @@ module Gitlab
def optionally_run_in_admin_mode(user)
raise NonSidekiqEnvironmentError unless Gitlab::Runtime.sidekiq?
return yield unless Gitlab::CurrentSettings.admin_mode && user.admin?
return yield unless Gitlab::CurrentSettings.admin_mode && user.can_access_admin_area?
bypass_session!(user.id) do
with_current_admin(user) do
@ -110,7 +110,7 @@ module Gitlab
return false unless user
Gitlab::SafeRequestStore.fetch(admin_mode_rs_key) do
user.admin? && (privileged_runtime? || session_with_admin_mode?)
user.can_access_admin_area? && (privileged_runtime? || session_with_admin_mode?)
end
end
@ -118,12 +118,12 @@ module Gitlab
return false unless user
Gitlab::SafeRequestStore.fetch(admin_mode_requested_rs_key) do
user.admin? && admin_mode_requested_in_grace_period?
user.can_access_admin_area? && admin_mode_requested_in_grace_period?
end
end
def enable_admin_mode!(password: nil, skip_password_validation: false)
return false unless user&.admin?
return false unless user&.can_access_admin_area?
return false unless skip_password_validation || user&.valid_password?(password)
raise NotRequestedError unless admin_mode_requested?
@ -139,7 +139,7 @@ module Gitlab
end
def disable_admin_mode!
return unless user&.admin?
return unless user&.can_access_admin_area?
reset_request_store_cache_entries
@ -148,7 +148,7 @@ module Gitlab
end
def request_admin_mode!
return unless user&.admin?
return unless user&.can_access_admin_area?
reset_request_store_cache_entries

View File

@ -305,7 +305,7 @@
"swagger-cli": "^4.0.4",
"tailwindcss": "^3.4.1",
"timezone-mock": "^1.0.8",
"vite": "^6.2.1",
"vite": "^6.2.2",
"vite-plugin-ruby": "^5.1.1",
"vue-loader-vue3": "npm:vue-loader@17.4.2",
"vue-test-utils-compat": "0.0.14",

View File

@ -45,29 +45,29 @@ module Gitlab
# Key value pairs for ci specific component version values
#
# This is defined as key value pairs to allow constructing example cli args for easier reproducability
# This is defined as key value pairs to allow constructing example cli args for easier reproducibility
#
# @return [Hash]
def component_ci_versions
{
"gitlab.gitaly.image.repository" => "#{IMAGE_REPOSITORY}/gitaly",
"gitlab.gitaly.image.tag" => semver?(gitaly_version) ? "v#{gitaly_version}" : gitaly_version,
"gitlab.gitaly.image.tag" => with_semver_prefix(gitaly_version),
"gitlab.gitlab-shell.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-shell",
"gitlab.gitlab-shell.image.tag" => "v#{gitlab_shell_version}",
"gitlab.gitlab-shell.image.tag" => with_semver_prefix(gitlab_shell_version),
"gitlab.migrations.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-toolbox-ee",
"gitlab.migrations.image.tag" => commit_sha,
"gitlab.migrations.image.tag" => toolbox_version,
"gitlab.toolbox.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-toolbox-ee",
"gitlab.toolbox.image.tag" => commit_sha,
"gitlab.toolbox.image.tag" => toolbox_version,
"gitlab.sidekiq.annotations.commit" => commit_short_sha,
"gitlab.sidekiq.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-sidekiq-ee",
"gitlab.sidekiq.image.tag" => commit_sha,
"gitlab.sidekiq.image.tag" => sidekiq_version,
"gitlab.webservice.annotations.commit" => commit_short_sha,
"gitlab.webservice.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-webservice-ee",
"gitlab.webservice.image.tag" => commit_sha,
"gitlab.webservice.image.tag" => webservice_version,
"gitlab.webservice.workhorse.image" => "#{IMAGE_REPOSITORY}/gitlab-workhorse-ee",
"gitlab.webservice.workhorse.tag" => commit_sha,
"gitlab.webservice.workhorse.tag" => workhorse_version,
"gitlab.kas.image.repository" => "#{IMAGE_REPOSITORY}/gitlab-kas",
"gitlab.kas.image.tag" => semver?(kas_version) ? "v#{kas_version}" : kas_version
"gitlab.kas.image.tag" => with_semver_prefix(kas_version)
}
end
@ -77,8 +77,10 @@ module Gitlab
#
# @param [String] version
# @return [Boolean]
def semver?(version)
version.match?(/^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?(-ee)?$/)
def with_semver_prefix(version)
return version unless version.match?(/^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?(-ee)?$/)
"v#{version}"
end
end
end

View File

@ -8,6 +8,10 @@ module Gitlab
module CI
extend self
def ci_project_dir
@ci_project_dir ||= ENV["CI_PROJECT_DIR"] || raise("CI_PROJECT_DIR is not set")
end
def commit_sha
@commit_sha ||= ENV["CI_COMMIT_SHA"] || raise("CI_COMMIT_SHA is not set")
end
@ -17,19 +21,37 @@ module Gitlab
end
def gitaly_version
@gitaly_version ||= File.read(File.join(ci_project_dir, "GITALY_SERVER_VERSION")).strip
@gitaly_version ||= ENV["GITALY_TAG"].presence || File.read(
File.join(ci_project_dir, "GITALY_SERVER_VERSION")
).strip
end
def gitlab_shell_version
@gitlab_shell_version ||= File.read(File.join(ci_project_dir, "GITLAB_SHELL_VERSION")).strip
@gitlab_shell_version ||= ENV["GITLAB_SHELL_TAG"].presence || File.read(
File.join(ci_project_dir, "GITLAB_SHELL_VERSION")
).strip
end
def sidekiq_version
@sidekiq_version ||= ENV["GITLAB_SIDEKIQ_TAG"].presence || commit_sha
end
def toolbox_version
@toolbox_version ||= ENV["GITLAB_TOOLBOX_TAG"].presence || commit_sha
end
def webservice_version
@webservice_version ||= ENV["GITLAB_WEBSERVICE_TAG"].presence || commit_sha
end
def workhorse_version
@workhorse_version ||= ENV["GITLAB_WORKHORSE_TAG"].presence || commit_sha
end
def kas_version
@kas_version ||= File.read(File.join(ci_project_dir, "GITLAB_KAS_VERSION")).strip
end
def ci_project_dir
@ci_project_dir ||= ENV["CI_PROJECT_DIR"] || raise("CI_PROJECT_DIR is not set")
@kas_version ||= ENV["GITLAB_KAS_TAG"].presence || File.read(
File.join(ci_project_dir, "GITLAB_KAS_VERSION")
).strip
end
end
end

View File

@ -8,6 +8,7 @@ RSpec.describe Gitlab::Orchestrator::Deployment::DefaultValues do
let(:gitaly_version) { "7aa06a578d76bdc294ee8e9acb4f063e7d9f1d5f" }
let(:kas_version) { "7aa06a578d76bdc294ee8e9acb4f063e7d9f1d5f" }
let(:shell_version) { "14.0.5" }
let(:image_tags) { {} }
let(:env) do
{
@ -17,10 +18,21 @@ RSpec.describe Gitlab::Orchestrator::Deployment::DefaultValues do
}
end
let(:memoized_variables) do
[
:@ci_project_dir,
:@gitaly_version,
:@kas_version,
:@toolbox_version,
:@webservice_version,
:@workhorse_version,
:@gitlab_shell_version,
:@sidekiq_version
]
end
before do
described_class.instance_variable_set(:@ci_project_dir, nil)
described_class.instance_variable_set(:@gitaly_version, nil)
described_class.instance_variable_set(:@kas_version, nil)
memoized_variables.each { |variable| described_class.instance_variable_set(variable, nil) }
allow(File).to receive(:read).with(File.join(ci_project_dir, "GITALY_SERVER_VERSION")).and_return(gitaly_version)
allow(File).to receive(:read).with(File.join(ci_project_dir, "GITLAB_SHELL_VERSION")).and_return(shell_version)
@ -28,7 +40,7 @@ RSpec.describe Gitlab::Orchestrator::Deployment::DefaultValues do
end
around do |example|
ClimateControl.modify(env) { example.run }
ClimateControl.modify({ **env, **image_tags }) { example.run }
end
it "returns correct common values" do
@ -91,4 +103,30 @@ RSpec.describe Gitlab::Orchestrator::Deployment::DefaultValues do
expect(described_class.component_ci_versions["gitlab.kas.image.tag"]).to eq("v#{kas_version}")
end
end
context "with explicitly provided image tags" do
let(:image_tags) do
{
"GITALY_TAG" => "13b6c124a0fe566c7e3db4477600e0f004ab69bc",
"GITLAB_SHELL_TAG" => "e6daa09dbb6ded5529224acdd1fd24000866aaaf",
"GITLAB_TOOLBOX_TAG" => "e6ce8d7f67c0787c706d5968a1f84c5e2d4f2368",
"GITLAB_SIDEKIQ_TAG" => "1088d209ac5dd8d245b00946de0760eb8fc9a181",
"GITLAB_WEBSERVICE_TAG" => "b0ccc088a766801c8db9e7c564ad28472f33916c",
"GITLAB_WORKHORSE_TAG" => "4a3990fb621ba6f6b7ddf36089868b24e22bb598",
"GITLAB_KAS_TAG" => "03faf0a4227405febb714c4eaa78e4f16f5d0a37"
}
end
it "uses explicitly provided image tags" do
expect(described_class.component_ci_versions).to include({
"gitlab.gitaly.image.tag" => image_tags["GITALY_TAG"],
"gitlab.gitlab-shell.image.tag" => image_tags["GITLAB_SHELL_TAG"],
"gitlab.toolbox.image.tag" => image_tags["GITLAB_TOOLBOX_TAG"],
"gitlab.sidekiq.image.tag" => image_tags["GITLAB_SIDEKIQ_TAG"],
"gitlab.webservice.image.tag" => image_tags["GITLAB_WEBSERVICE_TAG"],
"gitlab.webservice.workhorse.tag" => image_tags["GITLAB_WORKHORSE_TAG"],
"gitlab.kas.image.tag" => image_tags["GITLAB_KAS_TAG"]
})
end
end
end

View File

@ -5,6 +5,27 @@
#
# See https://docs.gitlab.com/ee/development/pipelines/internals.html#using-the-gitlab-ruby-gem-in-the-canonical-project.
require 'gitlab'
require 'yaml'
require 'json'
require 'open3'
require 'tempfile'
require 'httparty'
require 'logger'
# Monkeypatch gitlab gem in order to increase per_page size when fetching registry repositories
# rubocop:disable Style/ClassAndModuleChildren, Gitlab/NoCodeCoverageComment -- monkeypatch
# :nocov:
#
# TODO: Remove this monkeypatch once https://github.com/NARKOZ/gitlab/pull/710 is part of a new gem release (currently v5.1.0 doens't contain it) and the release is used in this project.
class Gitlab::Client
module ContainerRegistry
def registry_repositories(project, options = {})
get("/projects/#{url_encode project}/registry/repositories", query: options)
end
end
end
# :nocov:
# rubocop:enable Style/ClassAndModuleChildren, Gitlab/NoCodeCoverageComment
module Trigger
def self.ee?
@ -158,7 +179,7 @@ module Trigger
# Read version files from all components
def version_file_variables
Dir.glob("*_VERSION").each_with_object({}) do |version_file, params| # rubocop:disable Rails/IndexWith
Dir.glob("*_VERSION").each_with_object({}) do |version_file, params| # rubocop:disable Rails/IndexWith -- Non-rails CI script
params[version_file] = version_param_value(version_file)
end
end
@ -170,19 +191,77 @@ module Trigger
end
end
# Variable creation for downstream CNG build triggers
#
# This class additionally contains logic to check if component versions are already present in the container registry
# If they are, it adds those jobs to the SKIP_JOB_REGEX variable to skip them in the CNG build pipeline
#
# In order to correctly compute container versions and skip jobs, following actions are performed:
# * container version shell script is fetched from upstream
# * versions.yml file is fetched which contains most of variables required for container version calculation
# * image digest of stable Debian and Alpine images are fetched (alpine-stable and alpine-debian jobs functionality)
# * all container versions are computed using same logic as CNG build pipeline
# * registry is checked for image existence and appropriate jobs are added to skip regex pattern
#
class CNG < Base
ASSETS_HASH = "cached-assets-hash.txt"
DEFAULT_DEBIAN_IMAGE = "debian:bookworm-slim"
DEFAULT_ALPINE_IMAGE = "alpine:3.20"
DEFAULT_SKIPPED_JOBS = %w[final-images-listing].freeze
STABLE_BASE_JOBS = %w[alpine-stable debian-stable].freeze
def variables
hash = super.dup
# Delete variables that aren't useful when using native triggers.
super.tap do |hash|
hash.delete('TRIGGER_SOURCE')
hash.delete('TRIGGERED_USER')
hash.delete('TRIGGER_SOURCE')
hash.delete('TRIGGERED_USER')
unless skip_redundant_jobs?
logger.info("Skipping redundant jobs is disabled, skipping existing container image check")
return hash
end
begin
hash.merge({
**deploy_component_tag_variables,
'SKIP_JOB_REGEX' => skip_job_regex,
'DEBIAN_IMAGE' => debian_image,
'DEBIAN_DIGEST' => debian_image.split('@').last,
'DEBIAN_BUILD_ARGS' => "--build-arg DEBIAN_IMAGE=#{ENV['GITLAB_DEPENDENCY_PROXY']}#{debian_image}",
'ALPINE_IMAGE' => alpine_image,
'ALPINE_DIGEST' => alpine_image.split('@').last,
'ALPINE_BUILD_ARGS' => "--build-arg ALPINE_IMAGE=#{ENV['GITLAB_DEPENDENCY_PROXY']}#{alpine_image}"
})
rescue StandardError => e
logger.error("Error while calculating variables, err: #{e.message}")
logger.error(e.backtrace.join("\n"))
logger.error("Falling back to default variables")
hash
end
end
private
def logger
@logger ||= Logger.new(ENV["CNG_VAR_SETUP_LOG_FILE"] || "tmp/cng-var-setup.log")
end
def downstream_project_path
ENV.fetch('CNG_PROJECT_PATH', 'gitlab-org/build/CNG-mirror')
end
def skip_redundant_jobs?
ENV["CNG_SKIP_REDUNDANT_JOBS"] == "true"
end
def default_skip_job_regex
"/#{DEFAULT_SKIPPED_JOBS.join('|')}/"
end
def skip_job_regex
"/#{[*DEFAULT_SKIPPED_JOBS, *STABLE_BASE_JOBS, *skippable_jobs].join('|')}/"
end
def ref_param_name
'CNG_BRANCH'
end
@ -205,20 +284,35 @@ module Trigger
end
end
def gitlab_version
ENV['CI_COMMIT_SHA']
end
def base_variables
super.merge(
'GITLAB_REF_SLUG' => gitlab_ref_slug
)
super.merge('GITLAB_REF_SLUG' => gitlab_ref_slug)
end
def default_build_vars
@default_build_vars ||= {
"CONTAINER_VERSION_SUFFIX" => ENV["CI_PROJECT_PATH_SLUG"] || "upstream-trigger",
"CACHE_BUSTER" => "false",
"ARCH_LIST" => ENV["ARCH_LIST"] || "amd64"
}
end
def extra_variables
{
"TRIGGER_BRANCH" => ref,
"GITLAB_VERSION" => ENV['CI_COMMIT_SHA'],
"GITLAB_VERSION" => gitlab_version,
"GITLAB_TAG" => ENV['CI_COMMIT_TAG'], # Always set a value, even an empty string, so that the downstream pipeline can correctly check it.
"FORCE_RAILS_IMAGE_BUILDS" => 'true',
"CE_PIPELINE" => Trigger.ee? ? nil : "true", # Always set a value, even an empty string, so that the downstream pipeline can correctly check it.
"EE_PIPELINE" => Trigger.ee? ? "true" : nil # Always set a value, even an empty string, so that the downstream pipeline can correctly check it.
"EE_PIPELINE" => Trigger.ee? ? "true" : nil, # Always set a value, even an empty string, so that the downstream pipeline can correctly check it.
"FULL_RUBY_VERSION" => RUBY_VERSION,
"SKIP_JOB_REGEX" => default_skip_job_regex,
"DEBIAN_IMAGE" => DEFAULT_DEBIAN_IMAGE, # Make sure default values are always set to not end up as empty string
"ALPINE_IMAGE" => DEFAULT_ALPINE_IMAGE, # Make sure default values are always set to not end up as empty string
**default_build_vars
}
end
@ -238,6 +332,174 @@ module Trigger
raw_version
end
end
# Repository file tree in form of the output of `git ls-tree` command
#
# @return [String]
def repo_tree
logger.info("Fetching repo tree for ref '#{ref}'")
downstream_client
.repo_tree(downstream_project_path, ref: ref, per_page: 100).auto_paginate
.select { |node| node["type"] == "tree" }
.map { |node| "#{node['mode']} #{node['type']} #{node['id']} #{node['path']}" }
.join("\n")
end
# Script used for container version calculations in CNG build jobs
#
# @return [String]
def container_versions_script
logger.info("Fetching container versions script for ref '#{ref}'")
downstream_client.file_contents(
downstream_project_path,
"build-scripts/container_versions.sh",
ref
)
end
# Debian image with digest
#
# @return [String]
def debian_image
@debian_image ||= docker_image_with_digest(cng_versions["DEBIAN_IMAGE"])
end
# Alpine image with digest
#
# @return [String]
def alpine_image
@alpine_image ||= docker_image_with_digest(cng_versions["ALPINE_IMAGE"])
end
# Edition postfix
#
# @return [String]
def edition
@edition ||= Trigger.ee? ? "ee" : "ce"
end
# Component versions used in CNG builds
#
# @return [Hash]
def cng_versions
@cng_versions ||= YAML
.safe_load(downstream_client.file_contents(downstream_project_path, "ci_files/variables.yml", ref))
.fetch("variables")
end
# Environment variables required for container version fetching
# All these variables influence final container version values
#
# @return [Hash]
def version_fetch_env_variables
{
**cng_versions,
**version_file_variables,
**default_build_vars,
"GITLAB_VERSION" => gitlab_version,
"RUBY_VERSION" => RUBY_VERSION,
"DEBIAN_DIGEST" => debian_image.split("@").last,
"ALPINE_DIGEST" => alpine_image.split("@").last,
"REPOSITORY_TREE" => repo_tree
}
end
# Image tags used by CNG deployments
#
# @return [Hash]
def deploy_component_tag_variables
{
"GITALY_TAG" => container_versions["gitaly"],
"GITLAB_SHELL_TAG" => container_versions["gitlab-shell"],
"GITLAB_TOOLBOX_TAG" => container_versions["gitlab-toolbox-#{edition}"],
"GITLAB_SIDEKIQ_TAG" => container_versions["gitlab-sidekiq-#{edition}"],
"GITLAB_WEBSERVICE_TAG" => container_versions["gitlab-webservice-#{edition}"],
"GITLAB_WORKHORSE_TAG" => container_versions["gitlab-workhorse-#{edition}"],
"GITLAB_KAS_TAG" => container_versions["gitlab-kas"]
}
end
# Container versions for all components in CNG build pipeline
#
# @return [Hash]
def container_versions
@container_versions ||= Tempfile.create('container-versions') do |file|
file.write(container_versions_script)
file.close
build_vars = version_fetch_env_variables
logger.info("Computing container versions using following env variables:\n#{JSON.pretty_generate(build_vars)}")
out, status = Open3.capture2e(build_vars, "bash -c 'source #{file.path} && get_all_versions'")
raise "Failed to fetch container versions! #{out}" unless status.success?
component_versions = out.split("\n")
unless component_versions.all? { |line| line.match?(/^[A-Za-z0-9_\-]+=[^=]+$/) }
raise "Invalid container versions output format! Expected key=value pairs got:\n#{out}"
end
component_versions
.to_h { |entry| entry.split("=") }
.reject { |name, _version| Trigger.ee? ? name.end_with?("-ce") : name.end_with?("-ee") }
.tap { |versions| logger.info("Computed container versions:\n#{JSON.pretty_generate(versions)}") }
end
end
# List of jobs that can be skipped because tag is already present in the registry
#
# @return [Array]
def skippable_jobs
jobs = container_versions.keys
logger.info("Fetching container registry repositories for project '#{downstream_project_path}'")
repositories = downstream_client.registry_repositories(downstream_project_path, per_page: 100).auto_paginate
build_repositories = repositories.each_with_object({}) do |repo, hash|
job = jobs.find { |job| repo.name.end_with?(job) }
next unless job
hash[job] = repo.id
end
logger.info("Checking repositories (#{build_repositories.keys.join(', ')}) for existing tags")
existing_tags = container_versions.select do |job, tag|
downstream_client.registry_repository_tag(downstream_project_path, build_repositories[job], tag)
logger.info("Tag '#{tag}' exists in the registry, job '#{job}' will be skipped")
rescue Gitlab::Error::ResponseError => e
if e.is_a?(Gitlab::Error::NotFound)
logger.info("Tag '#{tag}' does not exist in the registry, job '#{job}' will not skipped")
else
logger.error("Failed to do a tag '#{tag}' lookup, err: #{e.message}, job '#{job}' will not be skipped")
end
false
end
existing_tags.keys
end
# rubocop:disable Gitlab/HTTParty -- CI script
# Fetch Docker image with digest from DockerHub
#
# @param docker_image [String]
# @return [String]
def docker_image_with_digest(docker_image)
image, tag = docker_image.split(":")
logger.info("Fetching digest for image '#{docker_image}'")
auth_url = "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/#{image}:pull"
auth_response = HTTParty.get(auth_url)
raise "Failed to get auth token" unless auth_response.success?
token = JSON.parse(auth_response.body)['token']
manifest_url = "https://registry.hub.docker.com/v2/library/#{image}/manifests/#{tag}"
response = HTTParty.head(manifest_url, headers: {
'Authorization' => "Bearer #{token}",
'Accept' => 'application/vnd.docker.distribution.manifest.v2+json'
})
raise "Failed to fetch image '#{docker_image}' digest" unless response.success?
digest = response.headers['docker-content-digest'] || raise("Failed to get image digest")
"#{image}:#{tag}@#{digest}"
end
# rubocop:enable Gitlab/HTTParty -- CI script
end
# For GitLab documentation review apps
@ -342,21 +604,25 @@ module Trigger
pipeline = super
project_path = variables['TOP_UPSTREAM_SOURCE_PROJECT']
merge_request_id = variables['TOP_UPSTREAM_MERGE_REQUEST_IID']
comment = "<!-- #{IDENTIFIABLE_NOTE_TAG} --> \nStarted database testing [pipeline](https://ops.gitlab.net/#{downstream_project_path}/-/pipelines/#{pipeline.id}) " \
"(limited access). This comment will be updated once the pipeline has finished running."
comment = <<~COMMENT.strip
<!-- #{IDENTIFIABLE_NOTE_TAG} -->
Started database testing [pipeline](https://ops.gitlab.net/#{downstream_project_path}/-/pipelines/#{pipeline.id}) (limited access). This comment will be updated once the pipeline has finished running.
COMMENT
# Look for an existing note
db_testing_notes = com_gitlab_client.merge_request_notes(project_path, merge_request_id).auto_paginate.select do |note|
note.body.include?(IDENTIFIABLE_NOTE_TAG)
end
db_testing_notes = com_gitlab_client
.merge_request_notes(project_path, merge_request_id)
.auto_paginate.select do |note|
note.body.include?(IDENTIFIABLE_NOTE_TAG)
end
if db_testing_notes.empty?
# This is the first note
note = com_gitlab_client.create_merge_request_note(project_path, merge_request_id, comment)
return unless db_testing_notes.empty?
puts "Posted comment to:\n"
puts "https://gitlab.com/#{project_path}/-/merge_requests/#{merge_request_id}#note_#{note.id}"
end
# This is the first note
note = com_gitlab_client.create_merge_request_note(project_path, merge_request_id, comment)
puts "Posted comment to:\n"
puts "https://gitlab.com/#{project_path}/-/merge_requests/#{merge_request_id}#note_#{note.id}"
end
private

View File

@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import { LAYER_VIEW, STAGE_VIEW } from '~/ci/pipeline_details/graph/constants';
import PipelineGraph from '~/ci/pipeline_details/graph/components/graph_component.vue';
import JobItem from '~/ci/pipeline_details/graph/components/job_item.vue';
@ -14,7 +14,6 @@ import { generateResponse, pipelineWithUpstreamDownstream } from '../mock_data';
describe('graph component', () => {
let wrapper;
const findDownstreamColumn = () => wrapper.findByTestId('downstream-pipelines');
const findLinkedColumns = () => wrapper.findAllComponents(LinkedPipelinesColumn);
const findLinksLayer = () => wrapper.findComponent(LinksLayer);
const findStageColumns = () => wrapper.findAllComponents(StageColumnComponent);
@ -43,7 +42,7 @@ describe('graph component', () => {
const createComponent = ({
data = {},
mountFn = shallowMount,
mountFn = shallowMountExtended,
props = {},
stubOverride = {},
} = {}) => {
@ -123,8 +122,10 @@ describe('graph component', () => {
});
describe('when linked pipelines are not present', () => {
beforeEach(() => {
beforeEach(async () => {
createComponent({ mountFn: mountExtended });
await nextTick();
});
it('should not render a linked pipelines column', () => {
@ -133,11 +134,13 @@ describe('graph component', () => {
});
describe('when linked pipelines are present', () => {
beforeEach(() => {
beforeEach(async () => {
createComponent({
mountFn: mountExtended,
props: { pipeline: pipelineWithUpstreamDownstream(mockPipelineResponse) },
});
await nextTick();
});
it('should render linked pipelines columns', () => {
@ -175,11 +178,13 @@ describe('graph component', () => {
});
});
it('filters pipelines spawned from the same trigger job', () => {
// The mock data has one downstream with `retried: true and one
// with retried false. We filter the `retried: true` out so we
// should only pass one downstream
expect(findDownstreamColumn().props().linkedPipelines).toHaveLength(1);
it('filters pipelines spawned from the same trigger job', async () => {
const DownstreamColumn = (
await import('~/ci/pipeline_details/graph/components/linked_pipelines_column.vue')
).default;
expect(wrapper.findComponent(DownstreamColumn).exists()).toBe(true);
expect(wrapper.findComponent(DownstreamColumn).props('linkedPipelines')).toHaveLength(1);
});
});

View File

@ -1,3 +1,4 @@
// Fixture located at spec/frontend/fixtures/pipeline_details.rb
import mockPipelineResponse from 'test_fixtures/pipelines/pipeline_details.json';
import { unwrapPipelineData } from '~/ci/pipeline_details/graph/utils';
import {

View File

@ -124,141 +124,15 @@ RSpec.describe Gitlab::Auth::CurrentUserMode, :request_store, feature_category:
context 'when the user is an admin' do
let(:user) { build_stubbed(:user, :admin) }
context 'when admin mode not requested' do
it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'raises exception if we try to enable it' do
expect do
subject.enable_admin_mode!(password: user.password)
end.to raise_error(::Gitlab::Auth::CurrentUserMode::NotRequestedError)
expect(subject.admin_mode?).to be(false)
end
end
context 'when admin mode requested first' do
before do
subject.request_admin_mode!
end
it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
subject.enable_admin_mode!(password: nil)
expect(subject.admin_mode?).to be(false)
end
it 'can be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true)
end
it 'can be disabled' do
subject.enable_admin_mode!(password: user.password)
subject.disable_admin_mode!
expect(subject.admin_mode?).to be(false)
end
it 'will expire in the future' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true), 'admin mode is not active in the present'
travel_to(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
# in the future this will be a new request, simulate by clearing the RequestStore
Gitlab::SafeRequestStore.clear!
expect(subject.admin_mode?).to be(false), 'admin mode did not expire in the future'
end
end
context 'skipping password validation' do
it 'can be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
expect(subject.admin_mode?).to be(true)
end
it 'can be enabled with an invalid password' do
subject.enable_admin_mode!(skip_password_validation: true)
expect(subject.admin_mode?).to be(true)
end
end
context 'with two independent sessions' do
let(:another_session) { {} }
let(:another_subject) { described_class.new(user) }
before do
allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session, another_session])
end
it 'cannot be enabled in one and seen in the other' do
Gitlab::Session.with_session(another_session) do
another_subject.request_admin_mode!
another_subject.enable_admin_mode!(password: user.password)
end
expect(subject.admin_mode?).to be(false)
end
end
end
context 'bypassing session' do
it 'is active by default' do
described_class.bypass_session!(user.id) do
expect(subject.admin_mode?).to be(true)
end
end
it 'enable has no effect' do
described_class.bypass_session!(user.id) do
subject.request_admin_mode!
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true)
end
end
it 'disable has no effect' do
described_class.bypass_session!(user.id) do
subject.disable_admin_mode!
expect(subject.admin_mode?).to be(true)
end
end
end
it_behaves_like 'admin_mode? check if admin_mode can be enabled'
end
end
describe '#enable_admin_mode!' do
let(:user) { build_stubbed(:user, :admin) }
context 'when the user is an admin' do
let(:user) { build_stubbed(:user, :admin) }
it 'creates a timestamp in the session' do
subject.request_admin_mode!
subject.enable_admin_mode!(password: user.password)
expect(session).to include(expected_session_entry(be_within(1.second).of(Time.now)))
end
it 'returns true after successful enable' do
subject.request_admin_mode!
expect(subject.enable_admin_mode!(password: user.password)).to eq(true)
end
it 'returns false after unsuccessful enable' do
subject.request_admin_mode!
expect(subject.enable_admin_mode!(password: 'wrong password')).to eq(false)
it_behaves_like 'enabling admin_mode when it can be enabled'
end
context 'when user is not an admin' do
@ -270,25 +144,12 @@ RSpec.describe Gitlab::Auth::CurrentUserMode, :request_store, feature_category:
expect(subject.enable_admin_mode!(password: user.password)).to eq(false)
end
end
context 'when admin mode is not requested' do
it 'raises error' do
expect do
subject.enable_admin_mode!(password: user.password)
end.to raise_error(Gitlab::Auth::CurrentUserMode::NotRequestedError)
end
end
end
describe '#disable_admin_mode!' do
let(:user) { build_stubbed(:user, :admin) }
it 'sets the session timestamp to nil' do
subject.request_admin_mode!
subject.disable_admin_mode!
expect(session).to include(expected_session_entry(be_nil))
end
it_behaves_like 'disabling admin_mode'
end
describe '.with_current_request_admin_mode' do
@ -331,13 +192,6 @@ RSpec.describe Gitlab::Auth::CurrentUserMode, :request_store, feature_category:
end
end
end
def expected_session_entry(value_matcher)
{
Gitlab::Auth::CurrentUserMode::SESSION_STORE_KEY => a_hash_including(
Gitlab::Auth::CurrentUserMode::ADMIN_MODE_START_TIME_KEY => value_matcher)
}
end
end
context 'when no session available' do

View File

@ -1,55 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe MigrateGlobalSearchSettingsInApplicationSettings, feature_category: :global_search do
let!(:application_setting) { table(:application_settings).create! }
describe '#down' do
let(:migration) { described_class.new }
context 'when search settings is already set' do
it 'does not update the search settings' do
migration.up
expect { migration.down }.to change { application_setting.reload.search }.to({})
end
end
end
describe '#up' do
context 'when search is not already set' do
before do
stub_feature_flags(global_search_code_tab: false)
stub_feature_flags(global_search_commits_tab: false)
stub_feature_flags(global_search_issues_tab: false)
end
it 'migrates search from the feature flags in the application_settings successfully' do
expected_search = if ::Gitlab.ee?
{
'global_search_code_enabled' => false,
'global_search_commits_enabled' => false,
'global_search_epics_enabled' => true,
'global_search_issues_enabled' => false,
'global_search_merge_requests_enabled' => true,
'global_search_snippet_titles_enabled' => true,
'global_search_users_enabled' => true,
'global_search_wiki_enabled' => true
}
else
{
'global_search_issues_enabled' => false,
'global_search_merge_requests_enabled' => true,
'global_search_snippet_titles_enabled' => true,
'global_search_users_enabled' => true
}
end
expect { migrate! }.to change {
application_setting.reload.search
}.from({}).to(expected_search)
end
end
end
end

View File

@ -164,6 +164,12 @@ RSpec.describe DeployKey, :mailer, feature_category: :continuous_delivery do
it { expect(subject.can?(:push_code, project)).to be false }
end
end
describe '#can_access_admin_area?' do
it 'returns false' do
expect(subject.can_access_admin_area?).to be_falsey
end
end
end
describe '#audit_details' do

View File

@ -726,6 +726,56 @@ RSpec.describe Note, feature_category: :team_planning do
end
end
describe '#last_edited_by' do
let_it_be(:note, reload: true) do
create_timestamp = 1.day.ago
create(:note, created_at: create_timestamp, updated_at: create_timestamp)
end
let(:editor) { note.author }
context 'when the note is not edited' do
it 'returns nil' do
expect(note.last_edited_by).to be_nil
end
end
def update_note(note, **attributes)
# Update updated_at manually because of ThrottledTouch concern
note.update!(attributes.merge(updated_at: Time.current))
end
context 'with an edited note' do
before do
update_note(note, last_edited_at: Time.current, updated_by: editor)
end
it 'returns the updated_by user' do
expect(note.last_edited_by).to eq(editor)
end
end
context 'with an edited note by a deleted user' do
before do
update_note(note, last_edited_at: Time.current, updated_by: nil)
end
it 'returns the ghost user' do
expect(note.last_edited_by).to eq(Users::Internal.ghost)
end
end
context 'with a legacy edited note where last_edited_at is not set' do
before do
update_note(note, updated_by: editor)
end
it 'returns the updated_by user' do
expect(note.last_edited_by).to eq(editor)
end
end
end
describe '#confidential?' do
context 'when note is not confidential' do
context 'when include_noteable is set to true' do

View File

@ -6069,6 +6069,20 @@ RSpec.describe User, feature_category: :user_profile do
end
end
describe '#can_access_admin_area?' do
it 'returns false for regular user' do
user = build_stubbed(:user)
expect(user.can_access_admin_area?).to be_falsy
end
it 'returns true for admin user' do
user = build_stubbed(:user, :admin)
expect(user.can_access_admin_area?).to be_truthy
end
end
shared_examples 'organization owner' do
let!(:org_user) { create(:organization_user, organization: organization, user: user, access_level: access_level) }

View File

@ -85,6 +85,16 @@ RSpec.describe BasePolicy do
.to change { policy.allowed?(ability) }.from(false).to(true)
end
end
context 'with a limited admin user', :enable_admin_mode do
let(:current_user) { build_stubbed(:user) }
before do
allow(current_user).to receive(:can_access_admin_area?).and_return(true)
end
it { is_expected.not_to be_allowed(ability) }
end
end
describe 'read_dedicated_hosted_runner_usage' do

View File

@ -68,7 +68,7 @@ RSpec.describe 'Update of an existing issue', feature_category: :team_planning d
context 'setting labels' do
before do
allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(102)
allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(103)
end
let(:mutation) do

View File

@ -70,7 +70,7 @@ RSpec.describe 'Setting assignees of a merge request', :assume_throttled, featur
context 'when the current user does not have permission to add assignees' do
let(:current_user) { create(:user) }
let(:db_query_limit) { 31 }
let(:db_query_limit) { 32 }
it 'does not change the assignees' do
project.add_guest(current_user)

View File

@ -64,7 +64,7 @@ RSpec.describe API::ProjectImport, :aggregate_failures, feature_category: :impor
it 'executes a limited number of queries', :use_clean_rails_redis_caching do
control = ActiveRecord::QueryRecorder.new { perform_archive_upload }
expect(control.count).to be <= 127
expect(control.count).to be <= 128
end
it 'schedules an import using a namespace' do

View File

@ -21,7 +21,7 @@ RSpec.describe 'Loading a user avatar', feature_category: :user_profile do
get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(:ok)
expect { get user.avatar_url }.not_to exceed_query_limit(4)
expect { get user.avatar_url }.not_to exceed_query_limit(5)
end
end

View File

@ -1,4 +1,5 @@
# frozen_string_literal: true
# rubocop:disable RSpec/VerifiedDoubles
require 'fast_spec_helper'
@ -21,7 +22,8 @@ RSpec.describe Trigger, feature_category: :tooling do
'GITLAB_USER_NAME' => 'gitlab_user_name',
'GITLAB_USER_LOGIN' => 'gitlab_user_login',
'QA_IMAGE' => 'qa_image',
'DOCS_PROJECT_API_TOKEN' => nil
'DOCS_PROJECT_API_TOKEN' => nil,
'CNG_SKIP_REDUNDANT_JOBS' => "false"
}
end
@ -458,6 +460,25 @@ RSpec.describe Trigger, feature_category: :tooling do
end
end
end
describe "#extra_variables" do
before do
stub_env('CI_PROJECT_PATH_SLUG', 'project-path')
stub_env('ARCH_LIST', 'amd64,arm64')
end
it 'includes extra variables' do
expect(subject.variables).to include({
"FULL_RUBY_VERSION" => RUBY_VERSION,
"SKIP_JOB_REGEX" => "/final-images-listing/",
"DEBIAN_IMAGE" => "debian:bookworm-slim",
"ALPINE_IMAGE" => "alpine:3.20",
"CONTAINER_VERSION_SUFFIX" => "project-path",
"CACHE_BUSTER" => "false",
"ARCH_LIST" => 'amd64,arm64'
})
end
end
end
end

View File

@ -18,7 +18,9 @@ RSpec.describe Issuable::Callbacks::Description, feature_category: :portfolio_ma
project: project,
description: 'old description',
last_edited_at: Date.yesterday,
last_edited_by: random_user
last_edited_by: random_user,
created_at: 3.days.ago,
updated_at: 3.days.ago
)
end

View File

@ -382,7 +382,7 @@ RSpec.configure do |config|
# See also spec/support/helpers/admin_mode_helpers.rb
if example.metadata[:enable_admin_mode] && !example.metadata[:do_not_mock_admin_mode]
allow_any_instance_of(Gitlab::Auth::CurrentUserMode).to receive(:admin_mode?) do |current_user_mode|
current_user_mode.send(:user)&.admin?
current_user_mode.send(:user)&.can_access_admin_area?
end
end

View File

@ -34,7 +34,7 @@ module AdminModeHelper
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).and_call_original
allow(Gitlab::Auth::CurrentUserMode).to receive(:new).with(user).and_return(fake_user_mode)
allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.admin?)
allow(fake_user_mode).to receive(:admin_mode?).and_return(user&.can_access_admin_area?)
end
end
end

View File

@ -0,0 +1,161 @@
# frozen_string_literal: true
RSpec.shared_examples 'admin_mode? check if admin_mode can be enabled' do
context 'when admin mode not requested' do
it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'raises exception if we try to enable it' do
expect do
subject.enable_admin_mode!(password: user.password)
end.to raise_error(::Gitlab::Auth::CurrentUserMode::NotRequestedError)
expect(subject.admin_mode?).to be(false)
end
end
context 'when admin mode requested first' do
before do
subject.request_admin_mode!
end
it 'is false by default' do
expect(subject.admin_mode?).to be(false)
end
it 'cannot be enabled with an invalid password' do
subject.enable_admin_mode!(password: nil)
expect(subject.admin_mode?).to be(false)
end
it 'can be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true)
end
it 'can be disabled' do
subject.enable_admin_mode!(password: user.password)
subject.disable_admin_mode!
expect(subject.admin_mode?).to be(false)
end
it 'expires in the future' do
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true), 'admin mode is not active in the present'
travel_to(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
# in the future this will be a new request, simulate by clearing the RequestStore
Gitlab::SafeRequestStore.clear!
expect(subject.admin_mode?).to be(false), 'admin mode did not expire in the future'
end
end
context 'when skipping password validation' do
it 'can be enabled with a valid password' do
subject.enable_admin_mode!(password: user.password, skip_password_validation: true)
expect(subject.admin_mode?).to be(true)
end
it 'can be enabled with an invalid password' do
subject.enable_admin_mode!(skip_password_validation: true)
expect(subject.admin_mode?).to be(true)
end
end
context 'with two independent sessions' do
let(:another_session) { {} }
let(:another_subject) { described_class.new(user) }
before do
allow(ActiveSession).to receive(:list_sessions).with(user).and_return([session, another_session])
end
it 'cannot be enabled in one and seen in the other' do
Gitlab::Session.with_session(another_session) do
another_subject.request_admin_mode!
another_subject.enable_admin_mode!(password: user.password)
end
expect(subject.admin_mode?).to be(false)
end
end
end
context 'when bypassing session' do
it 'is active by default' do
described_class.bypass_session!(user.id) do
expect(subject.admin_mode?).to be(true)
end
end
it 'enable has no effect' do
described_class.bypass_session!(user.id) do
subject.request_admin_mode!
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true)
end
end
it 'disable has no effect' do
described_class.bypass_session!(user.id) do
subject.disable_admin_mode!
expect(subject.admin_mode?).to be(true)
end
end
end
end
RSpec.shared_examples 'enabling admin_mode when it can be enabled' do
it 'creates a timestamp in the session' do
subject.request_admin_mode!
subject.enable_admin_mode!(password: user.password)
expect(session).to include(expected_session_entry(be_within(1.second).of(Time.now)))
end
it 'returns true after successful enable' do
subject.request_admin_mode!
expect(subject.enable_admin_mode!(password: user.password)).to be(true)
end
it 'returns false after unsuccessful enable' do
subject.request_admin_mode!
expect(subject.enable_admin_mode!(password: 'wrong password')).to be(false)
end
context 'when admin mode is not requested' do
it 'raises error' do
expect do
subject.enable_admin_mode!(password: user.password)
end.to raise_error(Gitlab::Auth::CurrentUserMode::NotRequestedError)
end
end
end
RSpec.shared_examples 'disabling admin_mode' do
it 'sets the session timestamp to nil' do
subject.request_admin_mode!
subject.disable_admin_mode!
expect(session).to include(expected_session_entry(be_nil))
end
end
def expected_session_entry(value_matcher)
{
Gitlab::Auth::CurrentUserMode::SESSION_STORE_KEY => a_hash_including(
Gitlab::Auth::CurrentUserMode::ADMIN_MODE_START_TIME_KEY => value_matcher)
}
end

View File

@ -15372,10 +15372,10 @@ vite-plugin-ruby@^5.1.1:
debug "^4.3.4"
fast-glob "^3.3.2"
vite@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.1.tgz#ae865d4bb93a11844be1bc647c8b2dd1856ea180"
integrity sha512-n2GnqDb6XPhlt9B8olZPrgMD/es/Nd1RdChF6CBD/fHW6pUyUTt2sQW2fPRX5GiD9XEa6+8A6A4f2vT6pSsE7Q==
vite@^6.2.2:
version "6.2.2"
resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.2.tgz#8098b12a6bfd95abe39399aa7d5faa56545d7a1a"
integrity sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==
dependencies:
esbuild "^0.25.0"
postcss "^8.5.3"