Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-03-31 21:07:09 +00:00
parent 85209dc3e4
commit 4df10dee37
64 changed files with 968 additions and 615 deletions

View File

@ -99,10 +99,15 @@ workflow:
# Example of project bot usernames (the format changed over time):
# - project_278964_bot2
# - project_278964_bot_7fb4d1cca8242cb399a0b8f483783120
#
# We set the DOCKER_AUTH_CONFIG variable to authenticate to Docker Hub to not be impacted by rate limitations
# We don't set DOCKER_AUTH_CONFIG as a CI/CD group/project variable, because it would then have higher precedence than .gitlab-ci.yml,
# and we would always reconfigure the docker deamon for any CI/CD pipeline.
- if: '$CI_MERGE_REQUEST_IID && $GITLAB_USER_LOGIN =~ /project_\d+_bot/'
variables:
<<: [*next-ruby-variables, *default-merge-request-variables]
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
DOCKER_AUTH_CONFIG: "${DOCKER_AUTH_CONFIG_OVERRIDE}"
PIPELINE_NAME: 'Ruby $RUBY_VERSION MR (triggered by a project token)'
- <<: *if-merge-request-security-canonical-sync
variables:
@ -145,10 +150,15 @@ workflow:
# Example of project bot usernames (the format changed over time):
# - project_278964_bot2
# - project_278964_bot_7fb4d1cca8242cb399a0b8f483783120
#
# We set the DOCKER_AUTH_CONFIG variable to authenticate to Docker Hub to not be impacted by rate limitations
# We don't set DOCKER_AUTH_CONFIG as a CI/CD group/project variable, because it would then have higher precedence than .gitlab-ci.yml,
# and we would always reconfigure the docker deamon for any CI/CD pipeline.
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot/'
variables:
<<: [*default-ruby-variables, *default-branch-pipeline-failure-variables]
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
DOCKER_AUTH_CONFIG: "${DOCKER_AUTH_CONFIG_OVERRIDE}"
PIPELINE_NAME: 'Ruby $RUBY_VERSION $CI_COMMIT_BRANCH branch (triggered by a project token)'
# For `$CI_DEFAULT_BRANCH` from wider community contributors, we don't want to run any pipelines on pushes,
# because normally we want to run merge request pipelines and scheduled pipelines, not for repository synchronization.

View File

@ -11,4 +11,3 @@ InternalAffairs/NumblockHandler:
- 'rubocop/cop/migration/with_lock_retries_disallowed_method.rb'
- 'rubocop/cop/qa/ambiguous_page_object_name.rb'
- 'rubocop/cop/rspec/feature_category.rb'
- 'rubocop/cop/rspec/shared_groups_metadata.rb'

View File

@ -15,6 +15,5 @@ InternalAffairs/RedundantMessageArgument:
- 'rubocop/cop/migration/prevent_single_statement_with_disable_ddl_transaction.rb'
- 'rubocop/cop/migration/schema_addition_methods_no_post.rb'
- 'rubocop/cop/redis_queue_usage.rb'
- 'rubocop/cop/rspec/shared_groups_metadata.rb'
- 'rubocop/cop/sidekiq_api_usage.rb'
- 'rubocop/cop/sidekiq_redis_call.rb'

View File

@ -1,5 +0,0 @@
---
RSpec/SharedGroupsMetadata:
Exclude:
- 'spec/lib/gitlab/ci/config/entry/retry_spec.rb'
- 'spec/lib/gitlab/git/merge_base_spec.rb'

View File

@ -11,6 +11,81 @@ export const FEED_TOKEN = 'feedToken';
export const INCOMING_EMAIL_TOKEN = 'incomingEmailToken';
export const STATIC_OBJECT_TOKEN = 'staticObjectToken';
export const FILTER_OPTIONS = [
{
icon: 'status',
title: s__('AccessTokens|State'),
type: 'state',
token: GlFilteredSearchToken,
operators: OPERATORS_IS,
unique: true,
options: [
{ value: 'active', title: s__('AccessTokens|Active') },
{ value: 'inactive', title: s__('AccessTokens|Inactive') },
],
},
{
icon: 'remove',
title: s__('AccessTokens|Revoked'),
type: 'revoked',
token: GlFilteredSearchToken,
operators: OPERATORS_IS,
unique: true,
options: [
{ value: 'true', title: __('Yes') },
{ value: 'false', title: __('No') },
],
},
{
icon: 'history',
title: __('Created date'),
type: 'created',
token: DateToken,
operators: OPERATORS_AFTER_BEFORE,
unique: true,
},
{
icon: 'history',
title: __('Expiration date'),
type: 'expires',
token: DateToken,
operators: OPERATORS_AFTER_BEFORE,
unique: true,
},
{
icon: 'history',
title: __('Last used date'),
type: 'last_used',
token: DateToken,
operators: OPERATORS_AFTER_BEFORE,
unique: true,
},
];
export const FILTER_OPTIONS_CREDENTIALS_INVENTORY = [
{
icon: 'key',
title: s__('CredentialsInventory|Type'),
type: 'filter',
token: GlFilteredSearchToken,
operators: OPERATORS_IS,
unique: true,
options: [
{
value: 'personal_access_tokens',
title: s__('CredentialsInventory|Personal access tokens'),
},
{ value: 'ssh_keys', title: s__('CredentialsInventory|SSH keys') },
{
value: 'resource_access_tokens',
title: s__('CredentialsInventory|Project and group access tokens'),
},
{ value: 'gpg_keys', title: s__('CredentialsInventory|GPG keys') },
],
},
...FILTER_OPTIONS,
];
export const DEFAULT_SORT = { value: 'expires', isAsc: true };
export const SORT_OPTIONS = [
@ -48,77 +123,6 @@ export const SORT_OPTIONS = [
},
];
export const TOKENS = [
{
icon: 'key',
title: s__('CredentialsInventory|Type'),
type: 'filter',
token: GlFilteredSearchToken,
operators: OPERATORS_IS,
unique: true,
options: [
{
value: 'personal_access_tokens',
title: s__('CredentialsInventory|Personal access tokens'),
},
{ value: 'ssh_keys', title: s__('CredentialsInventory|SSH keys') },
{
value: 'resource_access_tokens',
title: s__('CredentialsInventory|Project and group access tokens'),
},
{ value: 'gpg_keys', title: s__('CredentialsInventory|GPG keys') },
],
},
{
icon: 'status',
title: s__('CredentialsInventory|State'),
type: 'state',
token: GlFilteredSearchToken,
operators: OPERATORS_IS,
unique: true,
options: [
{ value: 'active', title: s__('CredentialsInventory|Active') },
{ value: 'inactive', title: s__('CredentialsInventory|Inactive') },
],
},
{
icon: 'remove',
title: s__('CredentialsInventory|Revoked'),
type: 'revoked',
token: GlFilteredSearchToken,
operators: OPERATORS_IS,
unique: true,
options: [
{ value: 'true', title: __('Yes') },
{ value: 'false', title: __('No') },
],
},
{
icon: 'history',
title: s__('CredentialsInventory|Created date'),
type: 'created',
token: DateToken,
operators: OPERATORS_AFTER_BEFORE,
unique: true,
},
{
icon: 'history',
title: s__('CredentialsInventory|Expiration date'),
type: 'expires',
token: DateToken,
operators: OPERATORS_AFTER_BEFORE,
unique: true,
},
{
icon: 'history',
title: s__('CredentialsInventory|Last used date'),
type: 'last_used',
token: DateToken,
operators: OPERATORS_AFTER_BEFORE,
unique: true,
},
];
export const STATISTICS_CONFIG = [
{
title: s__('AccessTokens|Active tokens'),

View File

@ -1,6 +1,6 @@
<script>
import { GlFilteredSearch, GlSorting } from '@gitlab/ui';
import { SORT_OPTIONS, TOKENS } from '~/access_tokens/constants';
import { SORT_OPTIONS, FILTER_OPTIONS_CREDENTIALS_INVENTORY } from '~/access_tokens/constants';
import { initializeValuesFromQuery, goTo } from '../utils';
export default {
@ -19,10 +19,10 @@ export default {
availableTokens() {
// Once SSH or GPG key is selected, discard the rest of the tokens
if (this.hasKey) {
return TOKENS.filter(({ type }) => type === 'filter');
return FILTER_OPTIONS_CREDENTIALS_INVENTORY.filter(({ type }) => type === 'filter');
}
return TOKENS;
return FILTER_OPTIONS_CREDENTIALS_INVENTORY;
},
hasKey() {
return this.tokens.some(

View File

@ -3,7 +3,11 @@ import {
OPERATORS_BEFORE,
OPERATORS_AFTER,
} from '~/vue_shared/components/filtered_search_bar/constants';
import { DEFAULT_SORT, SORT_OPTIONS, TOKENS } from '~/access_tokens/constants';
import {
DEFAULT_SORT,
SORT_OPTIONS,
FILTER_OPTIONS_CREDENTIALS_INVENTORY,
} from '~/access_tokens/constants';
/**
* @param {Object<string, string>} filters
@ -26,7 +30,7 @@ function initializeFilters(filters, search) {
});
} else {
try {
const { operators } = TOKENS.find(({ options }) =>
const { operators } = FILTER_OPTIONS_CREDENTIALS_INVENTORY.find(({ options }) =>
options.some((option) => option.value === value),
);
tokens.push({

View File

@ -2,16 +2,12 @@
module Ci
class BuildNameFinder
MAX_PER_PAGE = 100
def initialize(relation:, name:, project:, params: {})
def initialize(relation:, name:, project:)
raise ArgumentError, 'Only Ci::Builds are name searchable' unless relation.klass == Ci::Build
raise ArgumentError, "Offset Pagination is not supported" if relation.offset_value.present?
@relation = relation
@name = name
@project = project
@params = params
end
def execute
@ -22,51 +18,19 @@ module Ci
private
attr_reader :relation, :name, :project, :params
attr_reader :relation, :name, :project
def limited_name_search_terms
name.truncate_words(5, omission: '')
end
# rubocop: disable CodeReuse/ActiveRecord -- Need specialized queries for database optimizations
def filter_by_name(build_relation)
build_name_relation = generate_build_name_relation(apply_pagination_cursor(build_relation))
main_build_relation =
Ci::Build.where("(id, partition_id) IN (?)", build_name_relation.select(:build_id, :partition_id))
# Some callers (graphQL) will invert the ordering based on the relation and the params (asc)
if params[:invert_ordering]
main_build_relation.reorder(id: :desc)
else
apply_pagination_order(main_build_relation, :id)
end
end
def generate_build_name_relation(build_subrelation)
build_name_relation = Ci::BuildName
.where(project_id: project.id)
.pg_full_text_search_in_model(name)
.pg_full_text_search_in_model(limited_name_search_terms)
build_name_relation = apply_pagination_order(build_name_relation, :build_id)
build_name_relation
.where("(build_id, partition_id) IN (?)", build_subrelation.select(:id, :partition_id))
.limit(MAX_PER_PAGE + 1)
end
# Ci::Builds main ordering is ID DESC which makes ordering reversed
def apply_pagination_cursor(relation)
return relation if params[:after].blank? && params[:before].blank?
if params[:after]
relation.id_before(Integer(params[:after]))
else
relation.id_after(Integer(params[:before]))
end
end
def apply_pagination_order(relation, column)
if params[:asc].present?
relation.reorder(column => :asc)
else
relation.reorder(column => :desc)
end
build_relation.where("(id, partition_id) IN (?)", build_name_relation.select(:build_id, :partition_id))
end
# rubocop: enable CodeReuse/ActiveRecord
end

View File

@ -20,7 +20,7 @@ module Resolvers
argument :name, GraphQL::Types::String,
required: false,
experiment: { milestone: '17.1' },
experiment: { milestone: '17.11' },
description: 'Filter jobs by name.'
argument :sources, [::Types::Ci::JobSourceEnum],
@ -47,11 +47,7 @@ module Resolvers
jobs = ::Ci::BuildNameFinder.new(
relation: jobs,
name: args[:name],
project: project,
params: {
before: decode_cursor(args[:before]), after: decode_cursor(args[:after]),
asc: args[:last].present?, invert_ordering: true
}
project: project
).execute
elsif filter_by_sources
jobs = ::Ci::BuildSourceFinder.new(
@ -68,14 +64,6 @@ module Resolvers
private
def decode_cursor(encoded)
return unless encoded.present?
Gitlab::Json.parse(context.schema.cursor_encoder.decode(encoded, nonce: true))&.fetch('id')
rescue JSON::ParserError
raise Gitlab::Graphql::Errors::ArgumentError, "Please provide a valid cursor"
end
def preloads
{
previous_stage_jobs_or_needs: [:needs, :pipeline],

View File

@ -23,6 +23,13 @@ module Types
'Minimum GitLab access level required to push container image tags to the container repository. ' \
'Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. ' \
'If the value is `nil`, no access level can push tags. '
field :immutable,
GraphQL::Types::Boolean,
null: false,
method: :immutable?,
experiment: { milestone: '17.11' },
description: 'Returns true when tag rule is for tag immutability. Otherwise, false.'
end
end
end

View File

@ -0,0 +1,35 @@
# frozen_string_literal: true
module Namespaces
module AdjournedDeletable
extend ActiveSupport::Concern
def adjourned_deletion?
adjourned_deletion_configured?
end
def adjourned_deletion_configured?
return false unless Feature.enabled?(:downtier_delayed_deletion, :instance, type: :wip)
return false if try(:personal?)
::Gitlab::CurrentSettings.deletion_adjourned_period > 0
end
def marked_for_deletion?
return false unless Feature.enabled?(:downtier_delayed_deletion, :instance, type: :wip)
marked_for_deletion_on.present?
end
def self_or_ancestor_marked_for_deletion
return unless Feature.enabled?(:downtier_delayed_deletion, :instance, type: :wip)
return self if marked_for_deletion?
ancestors(hierarchy_order: :asc).joins(:deletion_schedule).first
end
def permanent_deletion_date(date)
date + ::Gitlab::CurrentSettings.deletion_adjourned_period.days
end
end
end

View File

@ -22,6 +22,7 @@ class Group < Namespace
include Importable
include IdInOrdered
include Members::Enumerable
include Namespaces::AdjournedDeletable
extend ::Gitlab::Utils::Override
@ -935,10 +936,6 @@ class Group < Namespace
import_export_upload_by_user(user)&.export_archive_exists?
end
def adjourned_deletion?
false
end
def execute_hooks(data, hooks_scope)
# NOOP
# TODO: group hooks https://gitlab.com/gitlab-org/gitlab/-/issues/216904

View File

@ -49,6 +49,7 @@ class Project < ApplicationRecord
include Importable
include SafelyChangeColumnDefault
include Todoable
include Namespaces::AdjournedDeletable
columns_changing_default :organization_id

View File

@ -135,7 +135,7 @@ class WorkItem < Issue
end
def non_widgets
[:related_vulnerabilities, :pending_escalations]
[:pending_escalations]
end
end

View File

@ -0,0 +1,9 @@
---
name: downtier_delayed_deletion
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/526403
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/185850
rollout_issue_url:
milestone: '17.11'
group: group::authorization
type: wip
default_enabled: false

View File

@ -0,0 +1,19 @@
---
data_category: optional
key_path: product_usage_data_enabled
description: Whether product usage data is enabled
product_group: analytics_instrumentation
value_type: boolean
status: active
time_frame: none
data_source: system
instrumentation_class: GitlabSettingsMetric
options:
setting_method: product_usage_data_enabled?
tiers:
- free
- premium
- ultimate
performance_indicator_type: []
milestone: "17.11"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/184899

View File

@ -1,41 +0,0 @@
- title: "Pipelines API cancel endpoint returns error for non-cancelable pipelines"
# The milestones for the deprecation announcement, and the removal.
removal_milestone: "18.0"
announcement_milestone: "17.6"
# Change breaking_change to false if needed.
breaking_change: true
window: 1 # Can be [1, 2, or 3] - The window when the breaking change will be deployed on GitLab.com
# The stage and GitLab username of the person reporting the change,
# and a link to the deprecation issue
reporter: rutshah
stage: verify
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414963
# Use the impact calculator https://gitlab-com.gitlab.io/gl-infra/breaking-change-impact-calculator/?
impact: high # Can be one of: [critical, high, medium, low]
scope: instance, group, project # Can be one or a combination of: [instance, group, project]
resolution_role: Owner # Can be one of: [Admin, Owner, Maintainer, Developer]
manual_task: true # Can be true or false. Use this to denote whether a resolution action must be performed manually (true), or if it can be automated by using the API or other automation (false).
body: | # (required) Don't change this line.
The Pipelines API cancel endpoint [`POST /projects/:id/pipelines/:pipeline_id/cancel`](https://docs.gitlab.com/api/pipelines/#cancel-a-pipelines-jobs)
returns a `200` success response regardless of whether a pipeline can be canceled.
Starting in GitLab 18.0, the endpoint will return a `422 Unprocessable Entity` error when a pipeline cannot be canceled.
Update your API integration to handle the `422` status code when making pipeline cancellation requests.
# ==============================
# OPTIONAL END-OF-SUPPORT FIELDS
# ==============================
#
# If an End of Support period applies:
# 1) Share this announcement in the `#spt_managers` Support channel in Slack
# 2) Mention `@gitlab-com/support` in this merge request.
#
# When support for this feature ends, in XX.YY milestone format.
end_of_support_milestone:
# Array of tiers the feature is currently available to,
# like [Free, Silver, Gold, Core, Premium, Ultimate]
tiers:
# Links to documentation and thumbnail image
documentation_url:
image_url:
# Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
video_url:

View File

@ -17,8 +17,8 @@
To migrate:
1. Check your S3 storage backend configuration in the GitLab container registry settings.
1. Remove the `v4auth: false` option if it's set.
1. Check your [S3 storage backend configuration in the GitLab container registry settings](https://docs.gitlab.com/administration/packages/container_registry/#use-object-storage).
1. If `v4auth` is set to `false`, remove the option.
1. Verify your existing credentials work with v4 authentication.
If you encounter any issues after making these changes, try regenerating your AWS credentials.

View File

@ -2,15 +2,15 @@
announcement_milestone: "17.9"
removal_milestone: "18.0"
breaking_change: true
impact: # Can be one of: [critical, high, medium, low]
scope: # Can be one or a combination of: [instance, group, project]
impact: low
scope: project
reporter: jayswain
stage: Software Supply Chain Security
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/509578
body: | # (required) Do not modify this line, instead modify the lines below.
In GitLab 18.0, CI/CD job tokens are moving to the JWT standard by default. All new projects will use this standard, but existing projects will continue to use the legacy format. Existing projects can switch to the JWT standard before the GitLab 18.0 release. If you experience issues, you can still [use the legacy format for your CI/CD tokens](https://docs.gitlab.com/ci/jobs/ci_job_token#use-legacy-format-for-cicd-tokens) until the GitLab 18.3 release.
In GitLab 18.0, CI/CD job tokens will switch from a string token format to the JWT token format. This changes impacts new and existing CI/CD job tokens in all projects. If you experience issues, you can still [use the legacy format for your CI/CD tokens](https://docs.gitlab.com/ci/jobs/ci_job_token#use-legacy-format-for-cicd-tokens) until the GitLab 19.0 release.
In GitLab 18.3, all CI/CD job tokens must use the JWT standard. Before this release, you can temporarily revert your tokens back to the legacy job token format.
In GitLab 19.0, all CI/CD job tokens must use the JWT standard. Before this release, you can temporarily revert your tokens back to the legacy job token format.
Known issues:

View File

@ -23597,6 +23597,7 @@ Represents the most restrictive permissions for a container image tag.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="containerprotectionaccesslevelimmutable"></a>`immutable` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.11. **Status**: Experiment. Returns true when tag rule is for tag immutability. Otherwise, false. |
| <a id="containerprotectionaccesslevelminimumaccesslevelfordelete"></a>`minimumAccessLevelForDelete` {{< icon name="warning-solid" >}} | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to delete container image tags from the container repository. Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, no access level can delete tags. |
| <a id="containerprotectionaccesslevelminimumaccesslevelforpush"></a>`minimumAccessLevelForPush` {{< icon name="warning-solid" >}} | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to push container image tags to the container repository. Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, no access level can push tags. |
@ -23622,6 +23623,7 @@ A container repository tag protection rule designed to prevent users with a cert
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="containerprotectiontagruleid"></a>`id` {{< icon name="warning-solid" >}} | [`ContainerRegistryProtectionTagRuleID!`](#containerregistryprotectiontagruleid) | **Introduced** in GitLab 17.8. **Status**: Experiment. ID of the container repository tag protection rule. |
| <a id="containerprotectiontagruleimmutable"></a>`immutable` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.11. **Status**: Experiment. Returns true when tag rule is for tag immutability. Otherwise, false. |
| <a id="containerprotectiontagruleminimumaccesslevelfordelete"></a>`minimumAccessLevelForDelete` {{< icon name="warning-solid" >}} | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to delete container image tags from the container repository. Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, no access level can delete tags. |
| <a id="containerprotectiontagruleminimumaccesslevelforpush"></a>`minimumAccessLevelForPush` {{< icon name="warning-solid" >}} | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to push container image tags to the container repository. Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, no access level can push tags. |
| <a id="containerprotectiontagruletagnamepattern"></a>`tagNamePattern` {{< icon name="warning-solid" >}} | [`String!`](#string) | **Introduced** in GitLab 17.8. **Status**: Experiment. The pattern that matches container image tags to protect. For example, `v1.*`. Wildcard character `*` allowed. |
@ -35416,7 +35418,7 @@ four standard [pagination arguments](#pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="projectjobsname"></a>`name` {{< icon name="warning-solid" >}} | [`String`](#string) | **Introduced** in GitLab 17.1. **Status**: Experiment. Filter jobs by name. |
| <a id="projectjobsname"></a>`name` {{< icon name="warning-solid" >}} | [`String`](#string) | **Introduced** in GitLab 17.11. **Status**: Experiment. Filter jobs by name. |
| <a id="projectjobssources"></a>`sources` {{< icon name="warning-solid" >}} | [`[CiJobSource!]`](#cijobsource) | **Introduced** in GitLab 17.7. **Status**: Experiment. Filter jobs by source. Ignored if 'populate_and_use_build_source_table' feature flag is disabled. |
| <a id="projectjobsstatuses"></a>`statuses` | [`[CiJobStatus!]`](#cijobstatus) | Filter jobs by status. |
| <a id="projectjobswithartifacts"></a>`withArtifacts` | [`Boolean`](#boolean) | Filter by artifacts presence. |
@ -46567,6 +46569,7 @@ Implementations:
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="accesslevelinterfaceimmutable"></a>`immutable` {{< icon name="warning-solid" >}} | [`Boolean!`](#boolean) | **Introduced** in GitLab 17.11. **Status**: Experiment. Returns true when tag rule is for tag immutability. Otherwise, false. |
| <a id="accesslevelinterfaceminimumaccesslevelfordelete"></a>`minimumAccessLevelForDelete` {{< icon name="warning-solid" >}} | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to delete container image tags from the container repository. Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, no access level can delete tags. |
| <a id="accesslevelinterfaceminimumaccesslevelforpush"></a>`minimumAccessLevelForPush` {{< icon name="warning-solid" >}} | [`ContainerProtectionTagRuleAccessLevel`](#containerprotectiontagruleaccesslevel) | **Introduced** in GitLab 17.8. **Status**: Experiment. Minimum GitLab access level required to push container image tags to the container repository. Valid values include `MAINTAINER`, `OWNER`, or `ADMIN`. If the value is `nil`, no access level can push tags. |

View File

@ -775,7 +775,7 @@ POST /projects/:id/jobs/:job_id/cancel
|-----------|----------------|----------|-------------|
| `id` | integer/string | Yes | ID or [URL-encoded path of the project](rest/_index.md#namespaced-paths). |
| `job_id` | integer | Yes | ID of a job. |
| `force` | boolean | No | [Forces cancellation](../ci/jobs/job_logs.md#force-cancel-a-job) of a job in `canceling` state when set to `true`. |
| `force` | boolean | No | [Forces cancellation](../ci/jobs/_index.md#force-cancel-a-job) of a job in `canceling` state when set to `true`. |
```shell
curl --request POST \

View File

@ -297,6 +297,152 @@ One or more `: [...]`, `X Y`, `X/Y`, or `X\Y` sequences are removed from the **e
of job names only. Matching substrings found at the beginning or in the middle of
job names are not removed.
## Retry a job
You can retry a job after it completes, regardless of its final state (failed, success, or canceled).
When you retry a job:
- A new job instance is created with a new job ID.
- The job runs with the same parameters and variables as the original job.
- If the job produces artifacts, new artifacts are created and stored.
Prerequisites:
- You must have at least the Developer role for the project.
To retry a job from a merge request:
1. On the left sidebar, select **Search or go to** and find your project.
1. From your merge request, do one of the following:
- In the pipeline widget, next to the job you want to retry, select **Run again** ({{< icon name="retry" >}}).
- Select the **Pipelines** tab, next to the job you want to retry, select **Run again** ({{< icon name="retry" >}}).
To retry a job from the job log:
1. Go to the job's log page.
1. In the upper-right corner, select **Run again** ({{< icon name="retry" >}}).
To retry a job from a pipeline:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. Find the pipeline that contains the job you want to retry.
1. From the pipeline graph, next to the job you want to retry, select **Run again** ({{< icon name="retry" >}}).
### Retry all failed or canceled jobs in a pipeline
If a pipeline has multiple failed or canceled jobs, you can retry all of them at once:
1. On the left sidebar, select **Search or go to** and find your project.
1. Do one of the following:
- Select **Build > Pipelines**.
- Go to a merge request and select the **Pipelines** tab.
1. For the pipeline with failed or canceled jobs, select **Retry all failed or canceled jobs** ({{< icon name="retry" >}}).
## Cancel a job
You can cancel a CI/CD job depending on its current state and the runner's capabilities.
When you cancel a job, what happens next depends on the job state and runner capabilities:
- For a `pending` job (not yet executing), the job is canceled immediately.
- For a `running` job:
- If the runner supports graceful cancellation, the job enters the `canceling` state.
The runner can complete its [`after_script`](../yaml/_index.md#after_script) before the job is marked as `canceled`.
- If the runner doesn't support graceful cancellation, the job moves to the `canceled` state immediately.
```mermaid
%%{init: { "fontFamily": "GitLab Sans" }}%%
stateDiagram-v2
accTitle: CI/CD job state transitions
accDescr: Shows possible state transitions for CI/CD jobs, including cancellation paths.
direction TB
state if_graceful <>
[*] --> pending: Job created
pending --> canceled: Cancel requested
canceled --> [*]
pending --> running: Runner picks up job
running --> success: Job succeeds
success --> [*]
running --> failed: Job fails
failed --> [*]
running --> if_graceful: Cancel requested
if_graceful --> canceling: Runner supports graceful cancellation
if_graceful --> canceled: Runner doesn't support graceful cancellation
canceling --> canceled: Graceful cancellation complete
note right of if_graceful: Does the runner support graceful cancellation?
```
Prerequisites:
- You must have at least the Developer role for the project,
or the [minimum role required to cancel a pipeline or job](../pipelines/settings.md#restrict-roles-that-can-cancel-pipelines-or-jobs).
To cancel a job from a merge request:
1. On the left sidebar, select **Search or go to** and find your project.
1. From your merge request, do one of the following:
- In the pipeline widget, next to the job you want to cancel, select **Cancel** ({{< icon name="cancel" >}}).
- Select the **Pipelines** tab, next to the job you want to cancel, select **Cancel** ({{< icon name="cancel" >}}).
To cancel a job from the job log:
1. Go to the job's log page.
1. In the upper-right corner, select **Cancel** ({{< icon name="cancel" >}}).
To cancel a job from a pipeline:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Build > Pipelines**.
1. Find the pipeline that contains the job you want to cancel.
1. From the pipeline graph, next to the job you want to cancel, select **Cancel** ({{< icon name="cancel" >}}).
### Cancel all running jobs in a pipeline
You can cancel all jobs in a running pipeline at once.
1. On the left sidebar, select **Search or go to** and find your project.
1. Do one of the following:
- Select **Build > Pipelines**.
- Go to a merge request and select the **Pipelines** tab.
1. For the pipeline you want to cancel, select **Cancel the running pipeline** ({{< icon name="cancel" >}}).
### Force cancel a job
{{< history >}}
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/467107) in GitLab 17.10 [with a flag](../../administration/feature_flags.md) named `force_cancel_build`. Disabled by default. This feature is an [experiment](../../policy/development_stages_support.md).
{{< /history >}}
{{< alert type="flag">}}
The availability of this feature is controlled by a feature flag.
For more information, see the history.
This feature is available for testing, but not ready for production use.
{{< /alert >}}
If a job is stuck in the `canceling` state, you can force it to the `canceled` state.
Prerequisites:
- You must have at least the Maintainer role for the project.
To force cancel a job:
- From the job log, select **Force cancel**.
{{< alert type="warning" >}}
When you force cancel a job, the [job token](ci_job_token.md) is revoked.
If the runner is still trying to execute the job, it loses access to GitLab.
The runner aborts the job without waiting for `after_script` to complete.
{{< /alert >}}
## Troubleshoot a failed job
When a pipeline fails or is allowed to fail, there are several places where you

View File

@ -164,70 +164,6 @@ job1:
- echo -e "\e[0Ksection_end:`date +%s`:my_first_section\r\e[0K"
```
## Cancel a job
You can cancel a CI/CD job depending on its current state and the runner's capabilities.
```mermaid
%%{init: { "fontFamily": "GitLab Sans" }}%%
stateDiagram-v2
accTitle: CI/CD job state transitions
accDescr: Shows possible state transitions for CI/CD jobs, including cancellation paths.
direction LR
state if_graceful <<choice>>
[*] --> pending: Job created
pending --> canceled: Cancel requested
canceled --> [*]
pending --> running: Runner picks up job
running --> success: Job succeeds
success --> [*]
running --> failed: Job fails
failed --> [*]
running --> if_graceful: Cancel requested
if_graceful --> canceling: Runner supports graceful cancellation
if_graceful --> canceled: Runner doesn't support graceful cancellation
canceling --> canceled: Graceful cancellation complete
note right of if_graceful: Runner supports graceful cancellation?
```
Prerequisites:
- You must have at least the Developer role for the project, or the [minimum role required to cancel a pipeline or job](../pipelines/settings.md#restrict-roles-that-can-cancel-pipelines-or-jobs).
To cancel a job from the job log:
1. Select **Cancel**.
1. What happens next depends on the job state and runner capabilities:
- For a `pending` job (not yet executing), the job is canceled immediately.
- For a `running` job:
- If the runner supports graceful cancellation, the job enters the `canceling` state. The runner can complete its [`after_script`](../yaml/_index.md#after_script) before the job is marked as `canceled`.
- If the runner doesn't support graceful cancellation, the job moves to the `canceled` state immediately.
### Force cancel a job
{{< history >}}
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/467107) in GitLab 17.10.
{{< /history >}}
If a job is stuck in the `canceling` state due to runner issues (for example, due to a runner hardware failure), you can force cancel it to complete its pipeline.
Prerequisites:
- You must have at least the Maintainer role for the project.
To force cancel a job:
- From the job log, select **Force cancel**.
{{< alert type="warning" >}}
When you force cancel a job, the [job token](ci_job_token.md) is revoked. If the runner is still trying to execute the job, it loses access to GitLab. The runner aborts the job without waiting for `after_script` to complete.
{{< /alert >}}
## Delete job logs
When you delete a job log you also [erase the entire job](../../api/jobs.md#erase-a-job).

View File

@ -33,7 +33,6 @@ This window takes place on April 21 - 23, 2025 from 09:00 UTC to 22:00 UTC.
| [Replace namespace `add_on_purchase` GraphQL field with `add_on_purchases`](https://gitlab.com/gitlab-org/gitlab/-/issues/489850) | Low | Fulfillment | Instance, group |
| [Public use of Secure container registries is deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/470641) | Low | Secure | Instance |
| [Limit number of scan execution policy actions allowed per policy](https://gitlab.com/gitlab-org/gitlab/-/issues/510897) | Low | Security risk management | Instance, group, project |
| [Pipelines API cancel endpoint returns error for non-cancelable pipelines](https://gitlab.com/gitlab-org/gitlab/-/issues/414963) | High | Verify | Instance, group, project |
| [Deprecate CI job implementation of Repository X-Ray](https://gitlab.com/gitlab-org/gitlab/-/issues/500146) | Low | Create | Project |
| [Pipeline job limits extended to the Commits API](https://gitlab.com/gitlab-org/gitlab/-/issues/436361) | Low | Verify | Project |
| [Deprecation of `name` field in `ProjectMonthlyUsageType` GraphQL API](https://gitlab.com/gitlab-org/gitlab/-/issues/381894) | Low | Fulfillment | Project |
@ -65,7 +64,7 @@ This window takes place on April 28 - 30, 2025 from 09:00 UTC to 22:00 UTC.
| [`mergeTrainIndex` and `mergeTrainsCount` GraphQL fields deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/473759) | Low | Verify | Project |
| [Behavior change for Upcoming and Started milestone filters](https://gitlab.com/gitlab-org/gitlab/-/issues/501294) | Low | Plan | Group, project |
| [`kpt`-based `agentk` is deprecated](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/issues/656) | Low | Deploy | Project |
| [Updating CI/CD job tokens to JWT standard](https://gitlab.com/gitlab-org/gitlab/-/issues/509578) | | Software supply chain security | |
| [Updating CI/CD job tokens to JWT standard](https://gitlab.com/gitlab-org/gitlab/-/issues/509578) | Low | Software supply chain security | Project |
## Window 3

View File

@ -785,8 +785,8 @@ To ensure continued compatibility and security, migrate to Signature Version 4.
To migrate:
1. Check your S3 storage backend configuration in the GitLab container registry settings.
1. Remove the `v4auth: false` option if it's set.
1. Check your [S3 storage backend configuration in the GitLab container registry settings](https://docs.gitlab.com/administration/packages/container_registry/#use-object-storage).
1. If `v4auth` is set to `false`, remove the option.
1. Verify your existing credentials work with v4 authentication.
If you encounter any issues after making these changes, try regenerating your AWS credentials.
@ -1610,25 +1610,6 @@ Starting in GitLab 18.0, the maximum [number of jobs in active pipelines](https:
<div class="deprecation breaking-change" data-milestone="18.0">
### Pipelines API cancel endpoint returns error for non-cancelable pipelines
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">17.6</span>
- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/update/terminology/#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/414963).
</div>
The Pipelines API cancel endpoint [`POST /projects/:id/pipelines/:pipeline_id/cancel`](https://docs.gitlab.com/api/pipelines/#cancel-a-pipelines-jobs)
returns a `200` success response regardless of whether a pipeline can be canceled.
Starting in GitLab 18.0, the endpoint will return a `422 Unprocessable Entity` error when a pipeline cannot be canceled.
Update your API integration to handle the `422` status code when making pipeline cancellation requests.
</div>
<div class="deprecation breaking-change" data-milestone="18.0">
### PostgreSQL 14 and 15 no longer supported
<div class="deprecation-notes">
@ -2234,9 +2215,9 @@ In other cases:
</div>
In GitLab 18.0, CI/CD job tokens are moving to the JWT standard by default. All new projects will use this standard, but existing projects will continue to use the legacy format. Existing projects can switch to the JWT standard before the GitLab 18.0 release. If you experience issues, you can still [use the legacy format for your CI/CD tokens](https://docs.gitlab.com/ci/jobs/ci_job_token#use-legacy-format-for-cicd-tokens) until the GitLab 18.3 release.
In GitLab 18.0, CI/CD job tokens will switch from a string token format to the JWT token format. This changes impacts new and existing CI/CD job tokens in all projects. If you experience issues, you can still [use the legacy format for your CI/CD tokens](https://docs.gitlab.com/ci/jobs/ci_job_token#use-legacy-format-for-cicd-tokens) until the GitLab 19.0 release.
In GitLab 18.3, all CI/CD job tokens must use the JWT standard. Before this release, you can temporarily revert your tokens back to the legacy job token format.
In GitLab 19.0, all CI/CD job tokens must use the JWT standard. Before this release, you can temporarily revert your tokens back to the legacy job token format.
Known issues:

View File

@ -153,6 +153,23 @@ To create test coverage for selected lines:
- If the merge request includes a test file, it is updated with the suggested tests.
- If the merge request does not include a test file, Amazon Q populates a comment with the suggested tests.
## Additional supported features
In addition, these features are available on GitLab Duo with Amazon Q.
| Feature | GitLab version |
|----------------------------------------------------------------------------------------------------------------------------------------|----------------|
| [GitLab Duo Chat](../../user/gitlab_duo_chat/_index.md) | GitLab 17.11 and later |
| [Code Suggestions](../../user/project/repository/code_suggestions/_index.md) | GitLab 17.11 and later |
| [Code Explanation](../../user/project/repository/code_explain.md) | GitLab 17.11 and later |
| [Test Generation](../../user/gitlab_duo_chat/examples.md#write-tests-in-the-ide) | GitLab 17.11 and later |
| [Refactor Code](../../user/gitlab_duo_chat/examples.md#refactor-code-in-the-ide) | GitLab 17.11 and later |
| [Fix Code](../../user/gitlab_duo_chat/examples.md#fix-code-in-the-ide) | GitLab 17.11 and later |
| [Root Cause Analysis](../../user/gitlab_duo_chat/examples.md#troubleshoot-failed-cicd-jobs-with-root-cause-analysis) | GitLab 17.11 and later |
| [Discussion Summary](../../user/discussions/_index.md#summarize-issue-discussions-with-duo-chat) | GitLab 17.11 and later |
| [Vulnerability Explanation](../../user/application_security/vulnerabilities/_index.md#explaining-a-vulnerability) | GitLab 17.11 and later |
| [Vulnerability Resolution](../../user/application_security/vulnerabilities/_index.md#vulnerability-resolution) | GitLab 17.11 and later |
## Related topics
- [Set up GitLab Duo with Amazon Q](setup.md)

View File

@ -82,6 +82,8 @@ To use CI/CD to authenticate with the container registry, you can use:
- A [CI job token](../../../ci/jobs/ci_job_token.md).
This token can only be used for read (pull) access. It has the `read_registry` scope but not the `write_registry` scope needed for push operations.
```shell
echo "$CI_JOB_TOKEN" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
```

View File

@ -590,6 +590,53 @@ npm-deploy-job:
- npm dist-tag add @scope/package@version my-tag
```
### Audit npm packages
GitLab supports `npm audit` commands, allowing you to check your packages for known vulnerabilities.
#### Use `npm audit`
Prerequisites:
- [Configure authentication](#authenticate-to-the-package-registry) to the package registry.
- [Set up the registry URL](#set-up-the-registry-url).
To run security audits, you can run the following command:
```shell
npm audit --registry=https://gitlab.example.com/api/v4/packages/npm/
```
Or, if you've already set your registry configuration:
```shell
npm audit
```
The `npm audit` command checks your dependencies for known vulnerabilities and provides a report.
#### `npm audit` workflow
When you run `npm audit` against the GitLab package registry, one of two scenarios occurs:
1. If package forwarding is enabled (default), GitLab forwards the audit request to `npmjs.com` to retrieve vulnerability information for both public and private packages.
1. If package forwarding is disabled, GitLab returns an empty result set. GitLab does not scan packages for vulnerabilities independently.
To learn more about the package forwarding setting, see [Package forwarding to npmjs.com](#package-forwarding-to-npmjscom).
#### Important security considerations
If you do not specify GitLab as your package registry (either with the `--registry` flag or by setting it as your default registry in the `.npmrc` file), the audit request goes to the public [npm registry](https://registry.npmjs.org) instead.
In this case, the request body contains information about all packages in your project, including your private GitLab packages.
To ensure your private package information stays within GitLab, always make sure to specify the GitLab registry when running `npm audit` commands.
#### Limitations
- Audit results depend on [package forwarding](#package-forwarding-to-npmjscom) being enabled. If forwarding is disabled by an administrator or group Owner, `npm audit` does not return vulnerability information.
- The audit request includes information about all packages in your project, including private packages.
### Supported CLI commands
The GitLab npm repository supports the following commands for the npm CLI (`npm`) and yarn CLI
@ -604,6 +651,7 @@ The GitLab npm repository supports the following commands for the npm CLI (`npm`
- `npm view`: Show package metadata.
- `npm pack`: Create a tarball from a package.
- `npm deprecate`: Deprecate a version of a package.
- `npm audit`: Check for vulnerabilities in your project dependencies.
## Troubleshooting

View File

@ -35,6 +35,15 @@ You can configure merge request status checks for each individual project. These
Status checks fail if they stay in the pending state for more than two minutes.
## Access permissions
External status check responses can be viewed by:
- Users with Reporter role or higher permissions in the project
- Any authenticated user who can view the merge request when the project has internal visibility
This means that if you have an internal project, any logged-in user who can access the merge request can view the external status check responses.
For more information about use cases, feature discovery, and development timelines,
see [epic 3869](https://gitlab.com/groups/gitlab-org/-/epics/3869).

View File

@ -346,6 +346,7 @@ module API
authorize! :cancel_pipeline, pipeline
# TODO: inconsistent behavior: when pipeline is not cancelable we should return an error
# Set to be fixed on V5 to avoid breaking changes: https://gitlab.com/gitlab-org/gitlab/-/issues/519143
::Ci::CancelPipelineService.new(pipeline: pipeline, current_user: current_user).execute
status 200

View File

@ -14,6 +14,15 @@ module Authn
Gitlab::CurrentSettings.current_application_settings.instance_token_prefix
end
def self.default_instance_prefix(prefix)
return prefix unless Feature.enabled?(:custom_prefix_for_all_token_types, :instance)
return prefix unless prefix.starts_with?(instance_prefix)
# remove the configured instance prefix and add the default:
"#{ApplicationSetting.defaults[:instance_token_prefix]}#{prefix.delete_prefix(instance_prefix)}"
end
end
end
end

View File

@ -4,7 +4,8 @@ module Authn
module Tokens
class FeedToken
def self.prefix?(plaintext)
plaintext.start_with?(::User.prefix_for_feed_token)
plaintext.start_with?(::User.prefix_for_feed_token,
Authn::TokenField::PrefixHelper.default_instance_prefix(::User.prefix_for_feed_token))
end
attr_reader :revocable, :source

View File

@ -13,6 +13,9 @@ module Gitlab
license = data['license']
return unless license
# A license must have either id or name
return unless license['id'].present? || license['name'].present?
::Gitlab::Ci::Reports::Sbom::License.new(
spdx_identifier: license['id'],
name: license['name'],

View File

@ -227,24 +227,11 @@ dependency-scanning:
variables:
ANALYZER_SUPPORTED_FILES: "packages.lock.json,conan.lock,conda-lock.yml,pubspec.lock,go.mod,go.graph,ivy-report.xml,maven.graph.json,dependencies.lock,package-lock.json,npm-shrinkwrap.json,pnpm-lock.yaml,yarn.lock,Podfile.lock,composer.lock,pipdeptree.json,requirements.txt,Pipfile.lock,pipenv.graph.json,poetry.lock,uv.lock,Gemfile.lock,gems.locked,Cargo.lock,dependencies-compile.dot,Package.resolved"
ADDITIONAL_SUPPORTED_FILES: "pom.xml,build.gradle,build.gradle.kts,build.sbt,requirements.pip,Pipfile,requires.txt,setup.py"
SCA_TO_SARIF_MATCHER_VERSION: "v2.0.1"
stage: test
image:
name: "$CI_TEMPLATE_REGISTRY_HOST/security-products/dependency-scanning:v0"
needs:
- job: gitlab-static-reachability
optional: true
artifacts: true
script:
- |
/analyzer run || exit $?
if [ -f "reachable_packages.json" ]; then
echo "Found reachable_packages.json"
echo "Downloading SCA-to-sarif-matcher ${SCA_TO_SARIF_MATCHER_VERSION}"
curl -L "gitlab.com/api/v4/projects/60962090/packages/generic/sca-to-sarif-matcher/${SCA_TO_SARIF_MATCHER_VERSION}/matcher" -o /home/gitlab/sbom-enricher
chmod +x /home/gitlab/sbom-enricher
/home/gitlab/sbom-enricher process --glas_report="reachable_packages.json"
fi
- /analyzer run
allow_failure: true
artifacts:
access: "developer"
@ -315,42 +302,3 @@ dependency-scanning:
- '**/{conda-lock.yml,pubspec.lock,Podfile.lock,Cargo.lock,Package.resolved}'
variables:
DS_EXCLUDED_PATHS: 'spec, test, tests, tmp, **/build.gradle, **/build.gradle.kts, **/build.sbt, **/pom.xml, **/requirements.txt, **/requirements.pip, **/Pipfile, **/Pipfile.lock, **/requires.txt, **/setup.py, **/poetry.lock, **/uv.lock, **/packages.lock.json, **/conan.lock, **/package-lock.json, **/npm-shrinkwrap.json, **/pnpm-lock.yaml, **/yarn.lock, **/composer.lock, **/Gemfile.lock, **/gems.locked, **/go.graph, **/ivy-report.xml, **/maven.graph.json, **/dependencies.lock, **/pipdeptree.json, **/pipenv.graph.json, **/dependencies-compile.dot'
gitlab-static-reachability:
stage: test
variables:
SEARCH_MAX_DEPTH: 20
STATIC_REACHABILITY_ANALYZER_IMAGE_TAG: 1
# For now we are using GLAS as our static reachability analyzer
STATIC_REACHABILITY_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/gitlab-advanced-sast:$STATIC_REACHABILITY_ANALYZER_IMAGE_TAG"
image:
name: "$STATIC_REACHABILITY_ANALYZER_IMAGE"
cache: []
script:
- |
export SAST_SCANNER_ALLOWED_CLI_OPTS="--sca-output-path reachable_packages.json"
echo keep-builtin-rules: false >> /lightz-aio_default_config.yaml
/analyzer run
chmod 644 reachable_packages.json
artifacts:
access: 'developer'
paths:
- reachable_packages.json
rules:
- if: $GITLAB_STATIC_REACHABILITY_ENABLED != 'true' || $DS_ENFORCE_NEW_ANALYZER != 'true'
when: never
# if DS is disabled then static reachability cannot execute
- if: $DEPENDENCY_SCANNING_DISABLED == 'true' || $DEPENDENCY_SCANNING_DISABLED == '1'
when: never
# Add the job to merge request pipelines if there's an open merge request.
- if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
$GITLAB_FEATURES =~ /\bsast_advanced\b/
exists:
- '**/*.py'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
when: never
# If there's no open merge request, add it to a *branch* pipeline instead.
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bsast_advanced\b/
exists:
- '**/*.py'

View File

@ -13,6 +13,7 @@ variables:
DEFAULT_SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
SAST_EXCLUDED_PATHS: "$DEFAULT_SAST_EXCLUDED_PATHS"
SCAN_KUBERNETES_MANIFESTS: "false"
GITLAB_ADVANCED_SAST_SCA_FILENAME: "GLAS_SCA.json"
sast:
stage: test
@ -87,6 +88,90 @@ gitlab-advanced-sast:
- '**/*.cs'
- '**/*.rb'
.static-reachability-rules:
rules:
- if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /gitlab-advanced-sast/
when: never
- if: $GITLAB_STATIC_REACHABILITY_ENABLED != 'true'
when: never
# Add the job to merge request pipelines if there's an open merge request.
- if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
$GITLAB_FEATURES =~ /\bsast_advanced\b/
exists:
- '**/*.py'
- '**/*.java'
- '**/*.jsp'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
when: never
# If there's no open merge request, add it to a *branch* pipeline instead.
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bsast_advanced\b/
exists:
- '**/*.py'
- '**/*.java'
- '**/*.jsp'
gitlab-static-reachability:
extends:
- gitlab-advanced-sast
variables:
SAST_SCANNER_ALLOWED_CLI_OPTS: --sca-output-path ${GITLAB_ADVANCED_SAST_SCA_FILENAME}
before_script:
- |
echo keep-builtin-rules: false >> /lightz-aio_default_config.yaml
artifacts:
paths:
- $GITLAB_ADVANCED_SAST_SCA_FILENAME
rules:
- if: $SAST_DISABLED == 'true' || $SAST_DISABLED == '1'
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /gitlab-advanced-sast/
when: never
- if: $GITLAB_STATIC_REACHABILITY_ENABLED != 'true'
when: never
# Add the job to merge request pipelines if there's an open merge request.
- if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
$GITLAB_FEATURES =~ /\bsast_advanced\b/
exists:
- '**/*.py'
- '**/*.java'
- '**/*.jsp'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
when: never
# If there's no open merge request, add it to a *branch* pipeline instead.
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bsast_advanced\b/
exists:
- '**/*.py'
- '**/*.java'
- '**/*.jsp'
gitlab-enrich-cdx-results:
stage: .post
extends: .static-reachability-rules
variables:
GLAS_STATIC_REACHABILITY_MATCHER_VERSION: "v1.0.3"
GLAS_REPORT: $GITLAB_ADVANCED_SAST_SCA_FILENAME
SCA_TO_SARIF_PROJECT_ID: 60962090
DEPENDENCY_SCANNING_PATTERN: "**/gl-sbom-*-*.cdx.json"
image:
name: "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
entrypoint: [""]
before_script:
- |
wget "gitlab.com/api/v4/projects/${SCA_TO_SARIF_PROJECT_ID}/packages/generic/sca-to-sarif-matcher/${GLAS_STATIC_REACHABILITY_MATCHER_VERSION}/matcher" \
--no-verbose -O /matcher
- chmod +x /matcher
script:
- /matcher process
artifacts:
paths:
- "**/gl-sbom-*.cdx.json"
reports:
cyclonedx: "**/gl-sbom-*.cdx.json"
kubesec-sast:
extends: .sast-analyzer
image:

View File

@ -2990,9 +2990,6 @@ msgstr ""
msgid "AccessTokens|Created"
msgstr ""
msgid "AccessTokens|Created date"
msgstr ""
msgid "AccessTokens|Description"
msgstr ""
@ -3112,9 +3109,6 @@ msgstr ""
msgid "AccessTokens|Keep this token secret. Anyone who has it can read activity and issue RSS feeds or your calendar feed as if they were you. If that happens, %{linkStart}reset this token%{linkEnd}."
msgstr ""
msgid "AccessTokens|Last used date"
msgstr ""
msgid "AccessTokens|Last used:"
msgstr ""
@ -4992,6 +4986,12 @@ msgstr ""
msgid "AdminUsers|Could not load user group counts. Please refresh the page to try again."
msgstr ""
msgid "AdminUsers|Create"
msgstr ""
msgid "AdminUsers|Create service account"
msgstr ""
msgid "AdminUsers|Deactivate"
msgstr ""
@ -5022,6 +5022,12 @@ msgstr ""
msgid "AdminUsers|Delete user and contributions"
msgstr ""
msgid "AdminUsers|Edit"
msgstr ""
msgid "AdminUsers|Edit service account"
msgstr ""
msgid "AdminUsers|Export permissions as CSV (max 100,000 users)"
msgstr ""
@ -5214,6 +5220,9 @@ msgstr ""
msgid "AdminUsers|Unblock user %{username}?"
msgstr ""
msgid "AdminUsers|Unique username that can be called for usage across GitLab"
msgstr ""
msgid "AdminUsers|Unlock user %{username}?"
msgstr ""
@ -17939,18 +17948,9 @@ msgstr ""
msgid "Credentials"
msgstr ""
msgid "CredentialsInventory|Active"
msgstr ""
msgid "CredentialsInventory|Created date"
msgstr ""
msgid "CredentialsInventory|Deleted user"
msgstr ""
msgid "CredentialsInventory|Expiration date"
msgstr ""
msgid "CredentialsInventory|Expired"
msgstr ""
@ -17960,12 +17960,6 @@ msgstr ""
msgid "CredentialsInventory|GPG keys"
msgstr ""
msgid "CredentialsInventory|Inactive"
msgstr ""
msgid "CredentialsInventory|Last used date"
msgstr ""
msgid "CredentialsInventory|No credentials found"
msgstr ""
@ -17990,9 +17984,6 @@ msgstr ""
msgid "CredentialsInventory|Search or filter credentials…"
msgstr ""
msgid "CredentialsInventory|State"
msgstr ""
msgid "CredentialsInventory|Type"
msgstr ""
@ -55238,6 +55229,12 @@ msgstr ""
msgid "ServiceAccounts|Add Service Account"
msgstr ""
msgid "ServiceAccounts|An error occurred creating the service account."
msgstr ""
msgid "ServiceAccounts|An error occurred updating the service account."
msgstr ""
msgid "ServiceAccounts|An error occurred while deleting the service account."
msgstr ""
@ -55268,6 +55265,12 @@ msgstr ""
msgid "ServiceAccounts|The service account is being deleted."
msgstr ""
msgid "ServiceAccounts|The service account was created."
msgstr ""
msgid "ServiceAccounts|The service account was updated."
msgstr ""
msgid "ServiceAccount|No more seats are available to create Service Account User"
msgstr ""

View File

@ -1,52 +0,0 @@
# frozen_string_literal: true
require 'rubocop/cop/rspec/base'
module RuboCop
module Cop
module RSpec
# Ensures that shared examples and shared context don't have any metadata.
#
# @example
#
# # bad
# RSpec.shared_examples 'an external link with rel attribute', feature_category: :team_planning do
# end
#
# RSpec.shared_examples 'an external link with rel attribute', :aggregate_failures do
# end
#
# RSpec.shared_context 'an external link with rel attribute', :aggregate_failures do
# end
#
# # good
# RSpec.shared_examples 'an external link with rel attribute' do
# end
#
# shared_examples 'an external link with rel attribute' do
# end
#
# it 'adds rel="nofollow" to external links', feature_category: :team_planning do
# end
class SharedGroupsMetadata < RuboCop::Cop::RSpec::Base
MSG = 'Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388'
# @!method metadata_value(node)
def_node_matcher :metadata_value, <<~PATTERN
(block
(send #rspec? {#SharedGroups.all} _description $_ ...)
...
)
PATTERN
def on_block(node)
value_node = metadata_value(node)
return unless value_node
add_offense(value_node, message: MSG)
end
end
end
end
end

View File

@ -170,7 +170,6 @@ spec/frontend/projects/new/components/new_project_url_select_spec.js
spec/frontend/projects/report_abuse/components/report_abuse_dropdown_item_spec.js
spec/frontend/projects/settings/components/branch_rule_modal_spec.js
spec/frontend/projects/settings/topics/components/topics_token_selector_spec.js
spec/frontend/projects/settings_service_desk/components/custom_email_form_spec.js
spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
spec/frontend/ref/init_ambiguous_ref_modal_spec.js

View File

@ -7,6 +7,7 @@ RSpec.describe Admin::ProjectsController, feature_category: :groups_and_projects
before do
sign_in(create(:admin))
stub_feature_flags(downtier_delayed_deletion: false)
end
describe 'GET /projects' do

View File

@ -24,6 +24,7 @@ RSpec.describe GroupsController, :with_current_organization, factory_default: :k
before do
enable_admin_mode!(admin_with_admin_mode)
stub_feature_flags(downtier_delayed_deletion: false)
end
shared_examples 'member with ability to create subgroups' do

View File

@ -7,6 +7,7 @@ RSpec.describe 'Group', :with_current_organization, feature_category: :groups_an
before do
sign_in(user)
stub_feature_flags(downtier_delayed_deletion: false)
end
matcher :have_namespace_error_message do

View File

@ -7,6 +7,10 @@ RSpec.describe 'Copy as GFM', :js, feature_category: :markdown do
include RepoHelpers
include ActionView::Helpers::JavaScriptHelper
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
describe 'Copying rendered GFM' do
before do
@feat = MarkdownFeature.new

View File

@ -5,42 +5,40 @@ require 'spec_helper'
RSpec.describe Ci::BuildNameFinder, feature_category: :continuous_integration do
let_it_be(:pipeline) { create(:ci_pipeline) }
let_it_be(:build_non_relevant) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "unique-name") }
let_it_be(:old_build) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build1") }
let_it_be(:old_middle_build) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build2") }
let_it_be(:middle_build) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build3") }
let_it_be(:middle_new_build) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build4") }
let_it_be(:new_build) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build5") }
let_it_be(:build_test) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build test") }
let_it_be(:build_deploy) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build deploy") }
let_it_be(:build_test_deploy) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "build test deploy") }
let_it_be(:multi_search_term) { create(:ci_build, :with_build_name, pipeline: pipeline, name: "a b c d e f") }
describe "#execute" do
let(:main_relation) { Ci::Build.all }
let(:name) { "build" }
let(:before) { nil }
let(:after) { nil }
let(:asc) { nil }
let(:invert_ordering) { false }
subject(:build_name_finder) do
described_class.new(
relation: main_relation,
name: name,
project: pipeline.project,
params: {
before: before, after: after, asc: asc,
invert_ordering: invert_ordering
}
project: pipeline.project
).execute
end
it 'filters by name in desc order' do
expect(build_name_finder)
.to eq([new_build, middle_new_build, middle_build, old_middle_build, old_build])
it 'filters by name' do
expect(build_name_finder).to match_array([build_test, build_deploy, build_test_deploy])
end
context 'when a multi-term name is passed in' do
let(:name) { "a b c d e z z z" }
it 'filters and restricts search term' do
expect(build_name_finder).to eq([multi_search_term])
end
end
context 'when no name is passed in' do
let(:name) { nil }
it 'does not filter by name' do
expect(build_name_finder.count).to eq(6)
expect(build_name_finder.count).to eq(5)
end
end
@ -52,64 +50,6 @@ RSpec.describe Ci::BuildNameFinder, feature_category: :continuous_integration do
expect { build_name_finder.execute }.to raise_error(ArgumentError, 'Only Ci::Builds are name searchable')
end
end
context 'when relation is using offset' do
it 'raises argument error for params' do
expect do
described_class.new(
relation: main_relation.offset(1),
name: name,
project: pipeline.project,
params: {}
)
.execute
end.to raise_error(ArgumentError, 'Offset Pagination is not supported')
end
end
end
context 'with before param' do
let(:before) { middle_build.id }
it 'returns builds newer than middle build' do
expect(build_name_finder)
.to eq([new_build, middle_new_build])
end
context 'with asc param' do
let(:asc) { true }
it 'returns only the builds in asc order' do
expect(build_name_finder)
.to eq([middle_new_build, new_build])
end
end
end
context 'with after param' do
let(:after) { middle_build.id }
it 'returns builds older than middle build' do
expect(build_name_finder)
.to eq([old_middle_build, old_build])
end
context 'with asc param' do
let(:asc) { true }
it 'returns build before cursor in asc order' do
expect(build_name_finder)
.to eq([old_build, old_middle_build])
end
end
end
context 'with asc param' do
let(:asc) { true }
it 'returns the records in ascending order' do
expect(build_name_finder).to eq([old_build, old_middle_build, middle_build, middle_new_build, new_build])
end
end
end
end

View File

@ -50,7 +50,7 @@ describe('Daterange component', () => {
factory({ show: true, startDate, endDate, minDate }, mountExtended);
const input = findDaterangePicker().find('input');
input.setValue('2019-01-01');
input.element.value = '2019-01-01';
await input.trigger('change');
expect(wrapper.emitted().change).toEqual([[{ startDate: minDate, endDate }]]);

View File

@ -1,8 +1,8 @@
import { GlDatepicker } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { useFakeDate } from 'helpers/fake_date';
import waitForPromises from 'helpers/wait_for_promises';
import ExpirationDatepicker from '~/members/components/table/expiration_datepicker.vue';
@ -40,7 +40,7 @@ describe('ExpirationDatepicker', () => {
};
const createComponent = (propsData = {}) => {
wrapper = mount(ExpirationDatepicker, {
wrapper = shallowMountExtended(ExpirationDatepicker, {
propsData: {
member,
permissions: { canUpdate: true },
@ -56,7 +56,6 @@ describe('ExpirationDatepicker', () => {
});
};
const findInput = () => wrapper.find('input');
const findDatepicker = () => wrapper.findComponent(GlDatepicker);
describe('datepicker input', () => {
@ -65,7 +64,7 @@ describe('ExpirationDatepicker', () => {
await nextTick();
expect(findInput().element.value).toBe('2020-03-17');
expect(findDatepicker().props('value')).toEqual(new Date('2020-03-17'));
});
});
@ -128,9 +127,8 @@ describe('ExpirationDatepicker', () => {
beforeEach(async () => {
createComponent();
findInput().setValue('2020-03-17');
await nextTick();
wrapper.find('[data-testid="clear-button"]').trigger('click');
await findDatepicker().vm.$emit('input', new Date('2020-03-17'));
await findDatepicker().vm.$emit('clear');
});
it('calls `updateMemberExpiration` Vuex action', () => {

View File

@ -132,7 +132,9 @@ describe('search box by type component', () => {
createComponent({ debounce }, mount);
findInput().setValue(newValue);
const input = findInput();
input.element.value = newValue;
input.trigger('input');
});
it(`emits a ${modelEvent} after the debounce delay`, () => {
@ -151,7 +153,9 @@ describe('search box by type component', () => {
beforeEach(() => {
createComponent({ lazy: true }, mount);
findInput().setValue(newValue);
const input = findInput();
input.element.value = newValue;
input.trigger('input');
});
it.each(['change', 'blur'])(`emits ${modelEvent} event after input's %s event`, (event) => {

View File

@ -82,7 +82,14 @@ if (global.document) {
}).mount(document.createElement('div'));
Vue.configureCompat(compatConfig);
installVTUCompat(VTU, fullCompatConfig, compatH);
installVTUCompat(
VTU,
{
...fullCompatConfig,
WRAPPER_SET_VALUE_DOES_NOT_TRIGGER_CHANGE: false,
},
compatH,
);
jest.mock('vue', () => {
const actualVue = jest.requireActual('vue');

View File

@ -399,7 +399,9 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
buildWrapper();
const newValue = 'new value';
await findTextarea().setValue(newValue);
const textArea = findTextarea();
textArea.element.value = newValue;
await findTextarea().trigger('input');
expect(wrapper.emitted('input')).toEqual([[value], [newValue]]);
});

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['ContainerProtectionAccessLevel'], feature_category: :container_registry do
specify { expect(described_class.graphql_name).to eq('ContainerProtectionAccessLevel') }
specify { expect(described_class.description).to be_present }
describe 'minimum_access_level_for_push' do
subject { described_class.fields['minimumAccessLevelForPush'] }
it { is_expected.to have_nullable_graphql_type(Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum) }
end
describe 'minimum_access_level_for_delete' do
subject { described_class.fields['minimumAccessLevelForDelete'] }
it { is_expected.to have_nullable_graphql_type(Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum) }
end
describe 'immutable' do
subject { described_class.fields['immutable'] }
it { is_expected.to have_non_null_graphql_type(GraphQL::Types::Boolean) }
end
end

View File

@ -32,4 +32,10 @@ RSpec.describe GitlabSchema.types['ContainerProtectionTagRule'], feature_categor
it { is_expected.to have_nullable_graphql_type(Types::ContainerRegistry::Protection::TagRuleAccessLevelEnum) }
end
describe 'immutable' do
subject { described_class.fields['immutable'] }
it { is_expected.to have_non_null_graphql_type(GraphQL::Types::Boolean) }
end
end

View File

@ -45,7 +45,29 @@ RSpec.describe Authn::AgnosticTokenIdentifier, feature_category: :system_access
end
with_them do
it_behaves_like 'supported token type'
context 'with default instance prefix' do
it_behaves_like 'supported token type'
end
context 'with custom instance prefix' do
let_it_be(:instance_prefix) { 'instance-prefix-' }
before do
stub_application_setting(instance_token_prefix: instance_prefix)
end
# this will make sure that we find old tokens with the default instance prefix,
# even if we have configured a custom one:
it_behaves_like 'supported token type'
end
context 'with feature flag custom_prefix_for_all_token_types disabled' do
before do
stub_feature_flags(custom_prefix_for_all_token_types: false)
end
it_behaves_like 'supported token type'
end
end
end

View File

@ -3,35 +3,89 @@
require 'spec_helper'
RSpec.describe Authn::TokenField::PrefixHelper, feature_category: :system_access do
let(:prefix) { 'prefix' }
describe '.prepend_instance_prefix' do
let(:prefix) { 'prefix' }
subject(:prepend_instance_prefix) { described_class.prepend_instance_prefix(prefix) }
subject(:prepend_instance_prefix) { described_class.prepend_instance_prefix(prefix) }
context 'with application config default value' do
it 'prepends the instance wide token prefix' do
expect(prepend_instance_prefix).to eq("gl#{prefix}")
context 'with application config default value' do
it 'prepends the instance wide token prefix' do
expect(prepend_instance_prefix).to eq("gl#{prefix}")
end
end
context 'with application config set to custom value' do
let(:instance_prefix) { 'instance-prefix-' }
before do
stub_application_setting(instance_token_prefix: instance_prefix)
end
it 'prepends the instance wide token prefix' do
expect(prepend_instance_prefix).to eq("#{instance_prefix}#{prefix}")
end
end
context 'with feature flag custom_prefix_for_all_token_types disabled' do
before do
stub_feature_flags(custom_prefix_for_all_token_types: false)
end
it 'does not prepend the instance wide token prefix' do
expect(prepend_instance_prefix).to eq(prefix)
end
end
end
context 'with application config set to custom value' do
let(:instance_prefix) { 'instance-prefix-' }
describe '.default_instance_prefix' do
let(:prefix) { 'glprefix' }
before do
stub_application_setting(instance_token_prefix: instance_prefix)
subject(:default_instance_prefix) { described_class.default_instance_prefix(prefix) }
context 'with application config default value' do
it 'returns the default prefix' do
expect(default_instance_prefix).to eq(prefix)
end
end
it 'prepends the instance wide token prefix' do
expect(prepend_instance_prefix).to eq("#{instance_prefix}#{prefix}")
end
end
context 'with application config set to custom value' do
let(:instance_prefix) { 'instance-prefix-' }
context 'with feature flag custom_prefix_for_all_token_types disabled' do
before do
stub_feature_flags(custom_prefix_for_all_token_types: false)
before do
stub_application_setting(instance_token_prefix: instance_prefix)
end
context 'for the default prefix' do
it 'still returns the default prefix' do
expect(default_instance_prefix).to eq(prefix)
end
end
context 'for the current instance prefix' do
let(:prefix) { "#{instance_prefix}token-prefix" }
it 'changes the instance prefix to the default prefix' do
expect(default_instance_prefix).to eq('gltoken-prefix')
end
end
context 'for a non-matching prefix' do
let(:prefix) { 'different-token-prefix' }
it 'keeps the prefix unchanged' do
expect(default_instance_prefix).to eq(prefix)
end
end
end
it 'does not prepend the instance wide token prefix' do
expect(prepend_instance_prefix).to eq(prefix)
context 'with feature flag custom_prefix_for_all_token_types disabled' do
before do
stub_feature_flags(custom_prefix_for_all_token_types: false)
end
it 'keeps the prefix unchanged' do
expect(default_instance_prefix).to eq(prefix)
end
end
end
end

View File

@ -5,12 +5,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Retry do
let(:entry) { described_class.new(config) }
shared_context 'when retry value is a numeric', :numeric do
shared_context 'when retry value is a numeric' do
let(:config) { max }
let(:max) {}
end
shared_context 'when retry value is a hash', :hash do
shared_context 'when retry value is a hash' do
let(:config) { { max: max, when: public_send(:when), exit_codes: exit_codes }.compact }
let(:when) {}
let(:exit_codes) {}
@ -20,7 +20,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Retry do
describe '#value' do
subject(:value) { entry.value }
context 'when retry value is a numeric', :numeric do
context 'when retry value is a numeric' do
include_context 'when retry value is a numeric'
let(:max) { 2 }
it 'is returned as a hash with max key' do
@ -28,7 +30,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Retry do
end
end
context 'when retry value is a hash', :hash do
context 'when retry value is a hash' do
include_context 'when retry value is a hash'
context 'and `when` is a string' do
let(:when) { 'unknown_failure' }
@ -65,7 +69,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Retry do
describe 'validation' do
context 'when retry value is correct' do
context 'when it is a numeric', :numeric do
context 'when it is a numeric' do
include_context 'when retry value is a numeric'
let(:max) { 2 }
it 'is valid' do
@ -73,7 +79,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Retry do
end
end
context 'when it is a hash', :hash do
context 'when it is a hash' do
include_context 'when retry value is a hash'
context 'with max' do
let(:max) { 2 }
@ -175,7 +183,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Retry do
end
end
context 'when it is a numeric', :numeric do
context 'when it is a numeric' do
include_context 'when retry value is a numeric'
context 'when it is lower than zero' do
let(:max) { -1 }
@ -205,7 +215,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Retry do
end
end
context 'when it is a hash', :hash do
context 'when it is a hash' do
include_context 'when retry value is a hash'
context 'with unknown keys' do
let(:config) { { max: 2, unknown_key: :something, one_more: :key } }

View File

@ -40,6 +40,20 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::License, feature_category: :dependency
end
end
context "when the license has neither id nor name" do
let(:data) do
{
"license" => {
"url" => "https://example.com/license.txt"
}
}
end
it "returns nil" do
is_expected.to be_nil
end
end
context "when the license is defined using an expression" do
let(:data) do
{

View File

@ -9,24 +9,26 @@ RSpec.describe Gitlab::Git::MergeBase do
subject(:merge_base) { described_class.new(repository, refs) }
shared_context 'existing refs with a merge base', :existing_refs do
shared_context 'existing refs with a merge base' do
let(:refs) do
%w[304d257dcb821665ab5110318fc58a007bd104ed 0031876facac3f2b2702a0e53a26e89939a42209]
end
end
shared_context 'when passing a missing ref', :missing_ref do
shared_context 'when passing a missing ref' do
let(:refs) do
%w[304d257dcb821665ab5110318fc58a007bd104ed aaaa]
end
end
shared_context 'when passing refs that do not have a common ancestor', :no_common_ancestor do
shared_context 'when passing refs that do not have a common ancestor' do
let(:refs) { ['304d257dcb821665ab5110318fc58a007bd104ed', TestEnv::BRANCH_SHA['orphaned-branch']] }
end
describe '#sha' do
context 'when the refs exist', :existing_refs do
context 'when the refs exist' do
include_context 'existing refs with a merge base'
it 'returns the SHA of the merge base' do
expect(merge_base.sha).not_to be_nil
end
@ -38,7 +40,9 @@ RSpec.describe Gitlab::Git::MergeBase do
end
end
context 'when passing a missing ref', :missing_ref do
context 'when passing a missing ref' do
include_context 'when passing a missing ref'
it 'does not call merge_base on the repository but raises an error' do
expect(repository).not_to receive(:merge_base)
@ -46,8 +50,12 @@ RSpec.describe Gitlab::Git::MergeBase do
end
end
it 'returns `nil` when the refs do not have a common ancestor', :no_common_ancestor do
expect(merge_base.sha).to be_nil
context 'when the refs do not have a common ancestor' do
include_context 'when passing refs that do not have a common ancestor'
it 'returns `nil`' do
expect(merge_base.sha).to be_nil
end
end
it 'returns a merge base when passing 2 branch names' do
@ -64,7 +72,9 @@ RSpec.describe Gitlab::Git::MergeBase do
end
describe '#commit' do
context 'for existing refs with a merge base', :existing_refs do
context 'for existing refs with a merge base' do
include_context 'existing refs with a merge base'
it 'finds the commit for the merge base' do
expect(merge_base.commit).to be_a(Commit)
end
@ -76,14 +86,20 @@ RSpec.describe Gitlab::Git::MergeBase do
end
end
it 'does not try to find the commit when there is no sha', :no_common_ancestor do
expect(repository).not_to receive(:commit_by)
context 'when there is no sha' do
include_context 'when passing refs that do not have a common ancestor'
merge_base.commit
it 'does not try to find the commit' do
expect(repository).not_to receive(:commit_by)
merge_base.commit
end
end
end
describe '#unknown_refs', :missing_ref do
describe '#unknown_refs' do
include_context 'when passing a missing ref'
it 'returns the refs passed that are not part of the repository' do
expect(merge_base.unknown_refs).to contain_exactly('aaaa')
end

View File

@ -0,0 +1,171 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Namespaces::AdjournedDeletable, feature_category: :groups_and_projects do
let(:project) { build(:project) }
describe '#adjourned_deletion?' do
it 'returns the result of adjourned_deletion_configured?', :aggregate_failures do
expect(project).to receive(:adjourned_deletion_configured?).and_return(true)
expect(project.adjourned_deletion?).to be true
expect(project).to receive(:adjourned_deletion_configured?).and_return(false)
expect(project.adjourned_deletion?).to be false
end
end
describe '#adjourned_deletion_configured?' do
context 'when deletion_adjourned_period is zero' do
before do
stub_application_setting(deletion_adjourned_period: 0)
end
it 'returns false' do
expect(project.adjourned_deletion_configured?).to be false
end
end
context 'when deletion_adjourned_period is positive' do
before do
stub_application_setting(deletion_adjourned_period: 7)
end
context 'for groups' do
let(:group) { build(:group) }
it 'returns true' do
expect(group.adjourned_deletion_configured?).to be true
end
end
context 'when it is a personal project' do
before do
allow(project).to receive(:personal?).and_return(true)
end
it 'returns false' do
expect(project.adjourned_deletion_configured?).to be false
end
end
context 'when it is not a personal project' do
before do
allow(project).to receive(:personal?).and_return(false)
end
it 'returns true' do
expect(project.adjourned_deletion_configured?).to be true
end
context 'when downtier_delayed_deletion feature flag is disabled' do
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
it 'returns false' do
expect(project.adjourned_deletion_configured?).to be false
end
end
end
end
end
describe '#marked_for_deletion?' do
context 'when marked_for_deletion_at is present' do
before do
project.marked_for_deletion_at = Time.current
end
it 'returns true' do
expect(project.marked_for_deletion?).to be true
end
context 'when downtier_delayed_deletion feature flag is disabled' do
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
it 'returns false' do
expect(project.marked_for_deletion?).to be false
end
end
end
context 'when marked_for_deletion_at is nil' do
before do
project.marked_for_deletion_at = nil
end
it 'returns false' do
expect(project.marked_for_deletion?).to be false
end
end
end
describe '#self_or_ancestor_marked_for_deletion' do
let_it_be(:group) { create(:group) }
let_it_be_with_reload(:project) { create(:project, group: group) }
context 'when the project is marked for deletion' do
before do
project.update!(marked_for_deletion_on: Time.current)
end
it 'returns self' do
expect(project.self_or_ancestor_marked_for_deletion).to eq(project)
end
context 'when downtier_delayed_deletion feature flag is disabled' do
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
it 'returns nil' do
expect(project.self_or_ancestor_marked_for_deletion).to be_nil
end
end
end
context 'when the project is not marked for deletion' do
context 'when an ancestor is marked for deletion' do
let_it_be(:group) { create(:group_with_deletion_schedule) }
let_it_be(:project) { create(:project, group: group) }
it 'returns the first ancestor marked for deletion' do
expect(project.self_or_ancestor_marked_for_deletion).to eq(group)
end
context 'when downtier_delayed_deletion feature flag is disabled' do
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
it 'returns nil' do
expect(project.self_or_ancestor_marked_for_deletion).to be_nil
end
end
end
context 'when no ancestor is marked for deletion' do
it 'returns nil' do
expect(project.self_or_ancestor_marked_for_deletion).to be_nil
end
end
end
end
describe '#permanent_deletion_date' do
let(:date) { Time.current }
let(:adjourned_period) { 7 }
before do
stub_application_setting(deletion_adjourned_period: adjourned_period)
end
it 'returns the date plus the configured adjourned period in days', :freeze_time do
expected_date = date + adjourned_period.days
expect(project.permanent_deletion_date(date)).to eq(expected_date)
end
end
end

View File

@ -44,7 +44,8 @@ RSpec.describe 'Deleting a container registry tag protection rule', :aggregate_f
'id' => container_protection_rule.to_global_id.to_s,
'tagNamePattern' => container_protection_rule.tag_name_pattern,
'minimumAccessLevelForDelete' => container_protection_rule.minimum_access_level_for_delete.upcase,
'minimumAccessLevelForPush' => container_protection_rule.minimum_access_level_for_push.upcase
'minimumAccessLevelForPush' => container_protection_rule.minimum_access_level_for_push.upcase,
'immutable' => container_protection_rule.immutable?
}
)
end

View File

@ -18,6 +18,10 @@ RSpec.describe API::Groups, :with_current_organization, feature_category: :group
let_it_be(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
let_it_be(:archived_project) { create(:project, namespace: group1, archived: true) }
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
def expect_log_keys(caller_id:, route:, root_namespace:)
expect(API::API::LOG_FORMATTER).to receive(:call) do |_severity, _datetime, _, data|
expect(data.stringify_keys).to include(

View File

@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Organizations::GroupsController, feature_category: :cell do
let_it_be(:organization) { create(:organization) }
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
describe 'GET #new' do
subject(:gitlab_request) { get new_groups_organization_path(organization) }

View File

@ -1,70 +0,0 @@
# frozen_string_literal: true
require 'rubocop_spec_helper'
require 'rspec-parameterized'
require_relative '../../../../rubocop/cop/rspec/shared_groups_metadata'
RSpec.describe RuboCop::Cop::RSpec::SharedGroupsMetadata, feature_category: :tooling do
context 'with hash metadata' do
it 'flags metadata in shared example' do
expect_offense(<<~RUBY)
RSpec.shared_examples 'foo', feature_category: :shared do
^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
shared_examples 'foo', feature_category: :shared do
^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
RUBY
end
it 'flags metadata in shared context' do
expect_offense(<<~RUBY)
RSpec.shared_context 'foo', feature_category: :shared do
^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
shared_context 'foo', feature_category: :shared do
^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
RUBY
end
end
context 'with symbol metadata' do
it 'flags metadata in shared example' do
expect_offense(<<~RUBY)
RSpec.shared_examples 'foo', :aggregate_failures do
^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
shared_examples 'foo', :aggregate_failures do
^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
RUBY
end
it 'flags metadata in shared context' do
expect_offense(<<~RUBY)
RSpec.shared_context 'foo', :aggregate_failures do
^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
shared_context 'foo', :aggregate_failures do
^^^^^^^^^^^^^^^^^^^ Avoid using metadata on shared examples and shared context. They might cause flaky tests. See https://gitlab.com/gitlab-org/gitlab/-/issues/404388
end
RUBY
end
end
it 'does not flag if feature category is missing' do
expect_no_offenses(<<~RUBY)
RSpec.shared_examples 'foo' do
end
shared_examples 'foo' do
end
RUBY
end
end

View File

@ -225,7 +225,9 @@ RSpec.configure do |config|
config.include ClickHouseHelpers, :click_house
config.include WorkItems::DataSync::AssociationsHelpers
config.shared_context_metadata_behavior = :apply_to_host_groups
config.include_context 'when rendered has no HTML escapes', type: :view
config.include_context 'with STI disabled', type: :model
include StubFeatureFlags
include StubSnowplow

View File

@ -2,7 +2,7 @@
# goal of this context: provide an easy process for setting and using the current organization that is set
# in the middleware for non-feature spec level specs.
RSpec.shared_context 'with current_organization setting', shared_context: :metadata do # rubocop:disable RSpec/SharedGroupsMetadata -- We are actually using this for easy metadata setting
RSpec.shared_context 'with current_organization setting' do
unless method_defined?(:current_organization)
let_it_be(:current_organization, reload: true) { create(:organization, name: 'Current Organization') }
end

View File

@ -23,7 +23,7 @@ RSpec.shared_examples 'Model disables STI' do
end
end
RSpec.shared_examples 'STI disabled', type: :model do # rubocop:disable RSpec/SharedGroupsMetadata -- Shared example is run within every spec tagged `type: :model`
RSpec.shared_context 'with STI disabled' do
include_examples 'Model disables STI' do
let(:models) { [described_class] }
end

View File

@ -3,6 +3,10 @@
require 'spec_helper'
RSpec.describe 'groups/settings/_remove.html.haml' do
before do
stub_feature_flags(downtier_delayed_deletion: false)
end
describe 'render' do
it 'enables the Remove group button for a group' do
group = build(:group)