Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a1e798edcd
commit
de560337ef
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ module PolicyActor
|
|||
false
|
||||
end
|
||||
|
||||
def can_access_admin_area?
|
||||
false
|
||||
end
|
||||
|
||||
def external?
|
||||
false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ title: Broadcast messages
|
|||
{{< details >}}
|
||||
|
||||
- Tier: Free, Premium, Ultimate
|
||||
- Offering: GitLab Self-Managed
|
||||
- Offering: GitLab Self-Managed, GitLab Dedicated
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)..
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue