Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-04-17 21:11:31 +00:00
parent d632a8e913
commit 1ec3642bdf
35 changed files with 6632 additions and 193 deletions

View File

@ -1248,6 +1248,10 @@ lib/gitlab/checks/**
/doc/user/workspace/ @brendan777
# End rake-managed-docs-block
# i18n Docs
[Localization Team] @gitlab-com/localization/maintainers
/doc-locale/**
[Authorization] @gitlab-org/software-supply-chain-security/authorization/approvers
/config/initializers/declarative_policy.rb
/config/initializers/declarative_policy_cached_attributes.rb

View File

@ -137,3 +137,22 @@ docs-lint redirects:
- source scripts/utils.sh
script:
- run_with_custom_exit_code ./scripts/lint-docs-redirects.rb
docs-i18n-lint markdown:
extends:
- .default-retry
- .docs:rules:docs-i18n-lint
- .docs-markdown-lint-image
- .yarn-cache
stage: lint
needs: []
script:
- source ./scripts/utils.sh
- |
function docs_lint_markdown() {
yarn_install_script
install_gitlab_gem
scripts/lint-i18n-doc.sh
}
run_with_custom_exit_code docs_lint_markdown

View File

@ -18,7 +18,7 @@ variables:
# Helm chart ref used by test-on-cng pipeline
GITLAB_HELM_CHART_REF: "074bb942c9c65613c2576ce418f59b8577fff37c"
# Specific ref for cng-mirror project to trigger builds for
GITLAB_CNG_MIRROR_REF: "56b6a062b05d549e0b69f79b759107e4956151eb"
GITLAB_CNG_MIRROR_REF: "a200886cbfb7e1f5a7642838f8f8fac9f26c6a97"
# Makes sure some of the common scripts from pipeline-common use bundler to execute commands
RUN_WITH_BUNDLE: "true"
# Makes sure reporting script defined in .gitlab-qa-report from pipeline-common is executed from correct folder

View File

@ -321,6 +321,15 @@
- "scripts/frontend/lint_docs_links.mjs"
- "tooling/eslint-config/eslint-local-rules/**/*"
.docs-i18n-patterns: &docs-i18n-patterns
- "doc-locale/**/*"
- "scripts/lint-i18n-doc.sh"
.if-tech-docs-localization: &if-tech-docs-localization
if: '($CI_PROJECT_PATH == "gitlab-com/localization" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH) ||
($CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_EVENT_TYPE != "merge_train") ||
($CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^docs-i18n-/ || $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /-docs-i18n$/)'
.docs-deprecations-and-removals-patterns: &docs-deprecations-and-removals-patterns
- "doc/update/breaking_windows.md"
- "doc/update/deprecations.md"
@ -1266,6 +1275,11 @@
- <<: *if-default-refs
changes: *docs-patterns
.docs:rules:docs-i18n-lint:
rules:
- <<: *if-tech-docs-localization
changes: *docs-i18n-patterns
.docs:rules:deprecations-and-removals:
rules:
- <<: *if-default-refs

View File

@ -1,4 +1,5 @@
import { issuableInitialDataById, isLegacyIssueType } from '~/issues/show/utils/issuable_data';
import { WORK_ITEM_TYPE_NAME_ISSUE } from '~/work_items/constants';
const initLegacyIssuePage = async () => {
const [{ initShow }] = await Promise.all([import('~/issues')]);
@ -8,7 +9,7 @@ const initLegacyIssuePage = async () => {
const initWorkItemPage = async () => {
const [{ initWorkItemsRoot }] = await Promise.all([import('~/work_items')]);
initWorkItemsRoot({ workItemType: 'issue' });
initWorkItemsRoot({ workItemType: WORK_ITEM_TYPE_NAME_ISSUE });
};
const issuableData = issuableInitialDataById('js-issuable-app');

View File

@ -2,7 +2,7 @@
import { GlBreadcrumb } from '@gitlab/ui';
import { s__, __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ROUTES, WORK_ITEM_TYPE_ENUM_EPIC } from '../constants';
import { ROUTES, WORK_ITEM_TYPE_NAME_EPIC } from '../constants';
const BREADCRUMB_LABELS = {
workItemList: s__('WorkItem|Work items'),
@ -30,7 +30,7 @@ export default {
return this.glFeatures.workItemPlanningView;
},
isEpicsList() {
return this.workItemType === WORK_ITEM_TYPE_ENUM_EPIC;
return this.workItemType === WORK_ITEM_TYPE_NAME_EPIC;
},
listName() {
if (this.isWorkItemOnly) {

View File

@ -8,7 +8,7 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import { parseBoolean } from '~/lib/utils/common_utils';
import { injectVueAppBreadcrumbs } from '~/lib/utils/breadcrumbs';
import { apolloProvider } from '~/graphql_shared/issuable_client';
import { ISSUE_WIT_FEEDBACK_BADGE } from '~/work_items/constants';
import { ISSUE_WIT_FEEDBACK_BADGE, WORK_ITEM_TYPE_NAME_ISSUE } from '~/work_items/constants';
import App from './components/app.vue';
import WorkItemBreadcrumb from './components/work_item_breadcrumb.vue';
import activeDiscussionQuery from './components/design_management/graphql/client/active_design_discussion.query.graphql';
@ -63,7 +63,7 @@ export const initWorkItemsRoot = ({ workItemType, workspaceType, withTabs } = {}
} = el.dataset;
const isGroup = workspaceType === WORKSPACE_GROUP;
const router = createRouter({ fullPath, workItemType, workspaceType, defaultBranch, isGroup });
const router = createRouter({ fullPath, workspaceType, defaultBranch, isGroup });
let listPath = issuesListPath;
const breadcrumbParams = { workItemType: listWorkItemType, isGroup };
@ -97,7 +97,7 @@ export const initWorkItemsRoot = ({ workItemType, workspaceType, withTabs } = {}
}
if (
workItemType === 'issue' &&
workItemType === WORK_ITEM_TYPE_NAME_ISSUE &&
gon.features.workItemsViewPreference &&
!isGroup &&
!gon.features.useWiViewForIssues

View File

@ -86,10 +86,12 @@ import DateToken from '~/vue_shared/components/filtered_search_bar/tokens/date_t
import { getParameterByName, removeParams, updateHistory } from '~/lib/utils/url_utility';
import {
DETAIL_VIEW_QUERY_PARAM_NAME,
NAME_TO_ENUM_MAP,
STATE_CLOSED,
STATE_OPEN,
WORK_ITEM_TYPE_ENUM_EPIC,
WORK_ITEM_TYPE_ENUM_ISSUE,
WORK_ITEM_TYPE_NAME_EPIC,
} from '../constants';
import getWorkItemsQuery from '../graphql/list/get_work_items.query.graphql';
import getWorkItemStateCountsQuery from '../graphql/list/get_work_item_state_counts.query.graphql';
@ -264,7 +266,7 @@ export default {
return this.isEpicsList ? this.glFeatures.epicsListDrawer : this.glFeatures.issuesListDrawer;
},
isEpicsList() {
return this.workItemType === WORK_ITEM_TYPE_ENUM_EPIC;
return this.workItemType === WORK_ITEM_TYPE_NAME_EPIC;
},
hasSearch() {
return Boolean(this.searchQuery);
@ -280,6 +282,7 @@ export default {
},
queryVariables() {
const hasGroupFilter = Boolean(this.urlFilterParams.group_path);
const singleWorkItemType = this.workItemType ? NAME_TO_ENUM_MAP[this.workItemType] : null;
return {
fullPath: this.fullPath,
sort: this.sortKey,
@ -289,7 +292,7 @@ export default {
...this.pageParams,
excludeProjects: hasGroupFilter || this.isEpicsList,
includeDescendants: !hasGroupFilter,
types: this.apiFilterParams.types || this.workItemType || this.defaultWorkItemTypes,
types: this.apiFilterParams.types || singleWorkItemType || this.defaultWorkItemTypes,
isGroup: this.isGroup,
};
},
@ -550,10 +553,8 @@ export default {
enableClientSideBoardsExperiment() {
return this.glFeatures.workItemsClientSideBoards;
},
workItemTypeName() {
return this.workItemType === WORK_ITEM_TYPE_ENUM_EPIC
? WORK_ITEM_TYPE_ENUM_EPIC
: WORK_ITEM_TYPE_ENUM_ISSUE;
preselectedWorkItemType() {
return this.isEpicsList ? WORK_ITEM_TYPE_ENUM_EPIC : WORK_ITEM_TYPE_ENUM_ISSUE;
},
},
watch: {
@ -919,7 +920,7 @@ export default {
<template #new-issue-button>
<create-work-item-modal
:is-group="isGroup"
:preselected-work-item-type="workItemTypeName"
:preselected-work-item-type="preselectedWorkItemType"
@workItemCreated="handleWorkItemCreated"
/>
</template>

View File

@ -7,12 +7,10 @@ module Projects
include Avatarable
include CacheMarkdownField
include Gitlab::SQL::Pattern
include SafelyChangeColumnDefault
SLUG_ALLOWED_REGEX = %r{\A[a-zA-Z0-9_\-.]+\z}
cache_markdown_field :description
columns_changing_default :organization_id
validates :name, presence: true, length: { maximum: 255 }
validates :description, length: { maximum: 1024 }

View File

@ -8,11 +8,10 @@
id: 'branch-rules',
testid: 'branch-rules-content',
expanded: expanded) do |c|
- c.with_callout do
- if Feature.enabled?(:edit_branch_rules, @project)
= render 'projects/settings/branch_rules_callout'
- c.with_description do
= _('Define rules for who can push, merge, and the required approvals for each branch.')
= link_to(_('Leave feedback.'), 'https://gitlab.com/gitlab-org/gitlab/-/issues/388149', target: '_blank', rel: 'noopener noreferrer')
- c.with_body do
- if Feature.enabled?(:edit_branch_rules, @project)
.gl-mb-5= render 'projects/settings/branch_rules_callout'
#js-branch-rules{ data: { project_path: @project.full_path, branch_rules_path: project_settings_repository_branch_rules_path(@project), show_code_owners: show_code_owners.to_s, show_status_checks: show_status_checks.to_s, show_approvers: show_approvers.to_s, show_enterprise_access_levels: show_enterprise_access_levels.to_s } }

View File

@ -0,0 +1,9 @@
---
name: allow_ldap_users_to_authenticate_with_gitlab_username
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/215357
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186848
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/536008
milestone: '18.0'
group: group::authentication
type: beta
default_enabled: true

View File

@ -1,5 +1,5 @@
- title: "GitLab Advanced SAST will be enabled by default"
removal_milestone: "18.0"
removal_milestone: "19.0"
announcement_milestone: "17.9"
breaking_change: true
window: 1
@ -12,7 +12,7 @@
resolution_role: Developer
manual_task: true
body: | # (required) Don't change this line.
In GitLab 18.0, we will update the [SAST CI/CD templates](https://docs.gitlab.com/user/application_security/sast#stable-vs-latest-sast-templates) to enable [GitLab Advanced SAST](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast) by default in projects with GitLab Ultimate.
In GitLab 19.0, we will update the [SAST CI/CD templates](https://docs.gitlab.com/user/application_security/sast#stable-vs-latest-sast-templates) to enable [GitLab Advanced SAST](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast) by default in projects with GitLab Ultimate.
Before this change, the GitLab Advanced SAST analyzer was enabled only if you set the CI/CD variable `GITLAB_ADVANCED_SAST_ENABLED` to `true`.
Advanced SAST delivers more accurate results by using cross-file, cross-function scanning and a new ruleset.

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@ Example response:
{
"id": 3,
"title": "Another Public key",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDIJFwIL6YNcCgVBLTHgM6hzmoL5vf0ThDKQMWT3HrwCjUCGPwR63vBwn6+/Gx+kx+VTo9FuojzR0O4XfwD3LrYA+oT3ETbn9U4e/VS4AH/G4SDMzgSLwu0YuPe517FfGWhWGQhjiXphkaQ+6bXPmcASWb0RCO5+pYlGIfxv4eFGQ=="
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDIJFwIL6YNcCgVBLTHgM6hzmoL5vf0ThDKQMWT3HrwCjUCGPwR63vBwn6+/Gx+kx+VTo9FuojzR0O4XfwD3LrYA+oT3ETbn9U4e/VS4AH/G4SDMzgSLwu0YuPe517FfGWhWGQhjiXphkaQ+6bXPmcASWb0RCO5+pYlGIfxv4eFGQ==",
"fingerprint": "0b:cf:58:40:b9:23:96:c7:ba:44:df:0e:9e:87:5e:75",
"fingerprint_sha256": "SHA256:lGI/Ys/Wx7PfMhUO1iuBH92JQKYN+3mhJZvWO4Q5ims",
"created_at": "2013-10-02T11:12:29Z",
@ -151,8 +151,8 @@ Example response:
```json
{
"id" : 5,
"title" : "My deploy key",
"id": 5,
"title": "My deploy key",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNJAkI3Wdf0r13c8a5pEExB2YowPWCSVzfZV22pNBc1CuEbyYLHpUyaD0GwpGvFdx2aP7lMEk35k6Rz3ccBF6jRaVJyhsn5VNnW92PMpBJ/P1UebhXwsFHdQf5rTt082cSxWuk61kGWRQtk4ozt/J2DF/dIUVaLvc+z4HomT41fQ==",
"fingerprint": "4a:9d:64:15:ed:3a:e6:07:6e:89:36:b3:3b:03:05:d9",
"fingerprint_sha256": "SHA256:Jrs3LD1Ji30xNLtTVf9NDCj7kkBgPBb2pjvTZ3HfIgU",
@ -195,7 +195,7 @@ Example response:
{
"id": 3,
"title": "Another Public key",
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDIJFwIL6YNcCgVBLTHgM6hzmoL5vf0ThDKQMWT3HrwCjUCGPwR63vBwn6+/Gx+kx+VTo9FuojzR0O4XfwD3LrYA+oT3ETbn9U4e/VS4AH/G4SDMzgSLwu0YuPe517FfGWhWGQhjiXphkaQ+6bXPmcASWb0RCO5+pYlGIfxv4eFGQ=="
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDIJFwIL6YNcCgVBLTHgM6hzmoL5vf0ThDKQMWT3HrwCjUCGPwR63vBwn6+/Gx+kx+VTo9FuojzR0O4XfwD3LrYA+oT3ETbn9U4e/VS4AH/G4SDMzgSLwu0YuPe517FfGWhWGQhjiXphkaQ+6bXPmcASWb0RCO5+pYlGIfxv4eFGQ==",
"fingerprint": "0b:cf:58:40:b9:23:96:c7:ba:44:df:0e:9e:87:5e:75",
"fingerprint_sha256": "SHA256:lGI/Ys/Wx7PfMhUO1iuBH92JQKYN+3mhJZvWO4Q5ims",
"created_at": "2013-10-02T11:12:29Z",
@ -227,24 +227,24 @@ Parameters:
```json
[
{
"id": 1,
"title": "Key A",
"created_at": "2022-05-30T12:28:27.855Z",
"expires_at": null,
"key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILkYXU2fVeO4/0rDCSsswP5iIX2+B6tv15YT3KObgyDl Key",
"fingerprint": "40:8e:fa:df:70:f7:a7:06:1e:0d:6f:ae:f2:27:92:01",
"fingerprint_sha256": "SHA256:Ojq2LZW43BFK/AMP81jBkDGn9YpPWYRNcViKBB44LPU"
},
{
"id": 2,
"title": "Key B",
"created_at": "2022-05-30T13:34:56.219Z",
"expires_at": null,
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNJAkI3Wdf0r13c8a5pEExB2YowPWCSVzfZV22pNBc1CuEbyYLHpUyaD0GwpGvFdx2aP7lMEk35k6Rz3ccBF6jRaVJyhsn5VNnW92PMpBJ/P1UebhXwsFHdQf5rTt082cSxWuk61kGWRQtk4ozt/J2DF/dIUVaLvc+z4HomT41fQ==",
"fingerprint": "4a:9d:64:15:ed:3a:e6:07:6e:89:36:b3:3b:03:05:d9",
"fingerprint_sha256": "SHA256:Jrs3LD1Ji30xNLtTVf9NDCj7kkBgPBb2pjvTZ3HfIgU",
}
{
"id": 1,
"title": "Key A",
"created_at": "2022-05-30T12:28:27.855Z",
"expires_at": null,
"key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILkYXU2fVeO4/0rDCSsswP5iIX2+B6tv15YT3KObgyDl Key",
"fingerprint": "40:8e:fa:df:70:f7:a7:06:1e:0d:6f:ae:f2:27:92:01",
"fingerprint_sha256": "SHA256:Ojq2LZW43BFK/AMP81jBkDGn9YpPWYRNcViKBB44LPU"
},
{
"id": 2,
"title": "Key B",
"created_at": "2022-05-30T13:34:56.219Z",
"expires_at": null,
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNJAkI3Wdf0r13c8a5pEExB2YowPWCSVzfZV22pNBc1CuEbyYLHpUyaD0GwpGvFdx2aP7lMEk35k6Rz3ccBF6jRaVJyhsn5VNnW92PMpBJ/P1UebhXwsFHdQf5rTt082cSxWuk61kGWRQtk4ozt/J2DF/dIUVaLvc+z4HomT41fQ==",
"fingerprint": "4a:9d:64:15:ed:3a:e6:07:6e:89:36:b3:3b:03:05:d9",
"fingerprint_sha256": "SHA256:Jrs3LD1Ji30xNLtTVf9NDCj7kkBgPBb2pjvTZ3HfIgU"
}
]
```
@ -331,12 +331,12 @@ Example response:
```json
{
"key" : "ssh-rsa AAAA...",
"id" : 12,
"title" : "My deploy key",
"can_push": true,
"created_at" : "2015-08-29T12:44:31.550Z",
"expires_at": null
"key": "ssh-rsa AAAA...",
"id": 12,
"title": "My deploy key",
"can_push": true,
"created_at": "2015-08-29T12:44:31.550Z",
"expires_at": null
}
```
@ -363,12 +363,12 @@ Example response:
```json
{
"id": 11,
"title": "New deploy key",
"key": "ssh-rsa AAAA...",
"created_at": "2015-08-29T12:44:31.550Z",
"expires_at": null,
"can_push": true
"id": 11,
"title": "New deploy key",
"key": "ssh-rsa AAAA...",
"created_at": "2015-08-29T12:44:31.550Z",
"expires_at": null,
"can_push": true
}
```
@ -410,11 +410,11 @@ Example response:
```json
{
"key" : "ssh-rsa AAAA...",
"id" : 12,
"title" : "My deploy key",
"created_at" : "2015-08-29T12:44:31.550Z",
"expires_at": null
"key": "ssh-rsa AAAA...",
"id": 12,
"title": "My deploy key",
"created_at": "2015-08-29T12:44:31.550Z",
"expires_at": null
}
```

View File

@ -1001,8 +1001,8 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `workload_identity_federation_project_id` | string | yes | Google Cloud project ID for the Workload Identity Federation. |
| `workload_identity_federation_project_number` | integer | yes | Google Cloud project number for the Workload Identity Federation. |
| `workload_identity_pool_id` | string | yes | ID of the Workload Identity Pool. |
| `workload_identity_pool_provider_id` | string | yes | ID of the Workload Identity Pool provider. |
| `workload_identity_pool_id` | string | yes | ID of the workload identity pool. |
| `workload_identity_pool_provider_id` | string | yes | ID of the workload identity pool provider. |
| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. |
### Disable Google Cloud Identity and Access Management

View File

@ -43607,8 +43607,10 @@ definitions:
type: string
repository_storage:
type: string
duo_nano_features_enabled:
type: string
duo_base_features_enabled:
type: boolean
description: "[Experimental] Indicates whether GitLab Duo features are enabled
for the group"
duo_features_enabled:
type: string
lock_duo_features_enabled:
@ -44135,10 +44137,10 @@ definitions:
service_access_tokens_expiration_enforced:
type: boolean
description: To enforce token expiration for Service accounts users for group
duo_nano_features_enabled:
duo_base_features_enabled:
type: boolean
description: Indicates whether GitLab Duo Nano features are enabled for the
group
description: "[Experimental] Indicates whether GitLab Duo features are enabled
for the group"
duo_features_enabled:
type: boolean
description: Indicates whether GitLab Duo features are enabled for the group
@ -44254,8 +44256,10 @@ definitions:
type: string
repository_storage:
type: string
duo_nano_features_enabled:
type: string
duo_base_features_enabled:
type: boolean
description: "[Experimental] Indicates whether GitLab Duo features are enabled
for the group"
duo_features_enabled:
type: string
lock_duo_features_enabled:

View File

@ -1206,8 +1206,8 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `workload_identity_federation_project_id` | string | yes | Google Cloud project ID for the Workload Identity Federation. |
| `workload_identity_federation_project_number` | integer | yes | Google Cloud project number for the Workload Identity Federation. |
| `workload_identity_pool_id` | string | yes | ID of the Workload Identity Pool. |
| `workload_identity_pool_provider_id` | string | yes | ID of the Workload Identity Pool provider. |
| `workload_identity_pool_id` | string | yes | ID of the workload identity pool. |
| `workload_identity_pool_provider_id` | string | yes | ID of the workload identity pool provider. |
| `use_inherited_settings` | boolean | no | Indicates whether to inherit the default settings. Defaults to `false`. |
### Disable Google Cloud Identity and Access Management

View File

@ -28,7 +28,7 @@ and Google Cloud. For more information on using OIDC with GitLab, read
[Connect to cloud services](../_index.md).
This tutorial assumes you have a Google Cloud account and a Google Cloud project.
Your account must have at least the **Workload Identity Pool Admin** permission
Your account must have at least the **workload identity pool Admin** permission
on the Google Cloud project.
{{< alert type="note" >}}
@ -40,32 +40,32 @@ see [How OIDC can simplify authentication of GitLab CI/CD pipelines with Google
To complete this tutorial:
1. [Create the Google Cloud Workload Identity Pool](#create-the-google-cloud-workload-identity-pool).
1. [Create a Workload Identity Provider](#create-a-workload-identity-provider).
1. [Create the Google Cloud workload identity pool](#create-the-google-cloud-workload-identity-pool).
1. [Create a workload identity provider](#create-a-workload-identity-provider).
1. [Grant permissions for service account impersonation](#grant-permissions-for-service-account-impersonation).
1. [Retrieve a temporary credential](#retrieve-a-temporary-credential).
## Create the Google Cloud Workload Identity Pool
## Create the Google Cloud workload identity pool
[Create a new Google Cloud Workload Identity Pool](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#create_the_workload_identity_pool_and_provider) with the following options:
[Create a new Google Cloud workload identity pool](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#create_the_workload_identity_pool_and_provider) with the following options:
- **Name**: Human-friendly name for the Workload Identity Pool, such as `GitLab`.
- **Pool ID**: Unique ID in the Google Cloud project for the Workload Identity Pool,
- **Name**: Human-friendly name for the workload identity pool, such as `GitLab`.
- **Pool ID**: Unique ID in the Google Cloud project for the workload identity pool,
such as `gitlab`. This value is used to refer to the pool and appears in URLs.
- **Description**: Optional. A description of the pool.
- **Enabled Pool**: Ensure this option is `true`.
We recommend creating a single _pool_ per GitLab installation per Google Cloud project. If you have multiple GitLab repositories and CI/CD jobs on the same GitLab instance, they can authenticate using different _providers_ against the same _pool_.
## Create a Workload Identity Provider
## Create a workload identity provider
[Create a new Google Cloud Workload Identity Provider](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#create_the_workload_identity_pool_and_provider)
inside the Workload Identity Pool created in the previous step, using the following options:
[Create a new Google Cloud workload identity provider](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#create_the_workload_identity_pool_and_provider)
inside the workload identity pool created in the previous step, using the following options:
- **Provider type**: OpenID Connect (OIDC).
- **Provider name**: Human-friendly name for the Workload Identity Provider,
- **Provider name**: Human-friendly name for the workload identity provider,
such as `gitlab/gitlab`.
- **Provider ID**: Unique ID in the pool for the Workload Identity Provider,
- **Provider ID**: Unique ID in the pool for the workload identity provider,
such as `gitlab-gitlab`. This value is used to refer to the provider, and appears in URLs.
- **Issuer (URL)**: The address of your GitLab instance, such as `https://gitlab.com/` or
`https://gitlab.example.com/`.
@ -98,7 +98,7 @@ For projects hosted on GitLab.com, GCP requires you to
## Grant permissions for Service Account impersonation
Creating the Workload Identity Pool and Workload Identity Provider defines the _authentication_
Creating the workload identity pool and workload identity provider defines the _authentication_
into Google Cloud. At this point, you can authenticate from GitLab CI/CD job into Google Cloud.
However, you have no permissions on Google Cloud (_authorization_).
@ -127,7 +127,7 @@ principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workl
```
where `PROJECT_NUMBER` is your Google Cloud project number, and `POOL_ID` is the
ID (not name) of the Workload Identity Pool created in the first section.
ID (not name) of the workload identity pool created in the first section.
This configuration also assumes you added `user_login` as an attribute mapped from
the assertion in the previous section.
@ -174,8 +174,8 @@ FEDERATED_TOKEN="$(curl --fail "https://sts.googleapis.com/v1/token" \
Where:
- `PROJECT_NUMBER` is your Google Cloud project number (not name).
- `POOL_ID` is the ID of the Workload Identity Pool created in the first section.
- `PROVIDER_ID` is the ID of the Workload Identity Provider created in the second section.
- `POOL_ID` is the ID of the workload identity pool created in the first section.
- `PROVIDER_ID` is the ID of the workload identity provider created in the second section.
- `GITLAB_OIDC_TOKEN` is an OIDC [ID token](../../yaml/_index.md#id_tokens).
You can then use the resulting federated token to impersonate the service account created

View File

@ -75,7 +75,7 @@ After setting up WIF, you must grant the WIF principal access to the secrets in
- `PROJECT_NUMBER`: Your Google Cloud project number (not ID) which can be found in the
[Project's dashboard](https://console.cloud.google.com/home/dashboard).
- `POOL_ID`: The ID (not name) of the Workload Identity Pool created in the first section,
- `POOL_ID`: The ID (not name) of the workload identity pool created in the first section,
for example `gitlab-pool`.
- `GITLAB_PROJECT_ID`: The GitLab project ID found on the [project overview page](../../user/project/working_with_projects.md#access-a-project-by-using-the-project-id).

View File

@ -87,6 +87,13 @@ pipelines:
These jobs check links, including anchor links, and report any problems. Any link that requires a network
connection is skipped.
## Translation documentation tests
We also run tests on documentation translations documentation. Merge requests containing changes to
Markdown (`.md`) files in the `/doc-locale/` directory run these CI/CD jobs:
- `docs-i18n-lint markdown`: Runs `scripts/lint-i18n-doc.sh` which runs Vale and markdownlint.
## Install documentation linters
To help adhere to the [documentation style guidelines](../styleguide/_index.md), and

View File

@ -32,7 +32,6 @@ This window takes place on April 21 - 23, 2025 from 09:00 UTC to 22:00 UTC.
| [Deprecation of `STORAGE` enum in `NamespaceProjectSortEnum` GraphQL API](deprecations.md#deprecation-of-storage-enum-in-namespaceprojectsortenum-graphql-api) | Low | Fulfillment | Group | |
| [DAST `dast_devtools_api_timeout` will have a lower default value](deprecations.md#dast-dast_devtools_api_timeout-will-have-a-lower-default-value) | Low | Application security testing | Project | |
| [API Discovery will use branch pipelines by default](deprecations.md#api-discovery-will-use-branch-pipelines-by-default) | Low | Application_security_testing | Project | |
| [GitLab Advanced SAST will be enabled by default](deprecations.md#gitlab-advanced-sast-will-be-enabled-by-default) | Medium | Application security testing | Instance | Refer to the [Understanding this change](https://gitlab.com/gitlab-org/gitlab/-/issues/513685#understanding-this-change) section for details. |
| [Application Security Testing analyzers major version update](deprecations.md#application-security-testing-analyzers-major-version-update) | Low | Application security testing | Project | |
## Window 2

View File

@ -513,6 +513,31 @@ we will enforce keyset pagination on these APIs.
<div class="deprecation breaking-change" data-milestone="19.0">
### GitLab Advanced SAST will be enabled by default
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">17.9</span>
- Removal in GitLab <span class="milestone">19.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/513685).
</div>
In GitLab 19.0, we will update the [SAST CI/CD templates](https://docs.gitlab.com/user/application_security/sast#stable-vs-latest-sast-templates) to enable [GitLab Advanced SAST](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast) by default in projects with GitLab Ultimate.
Before this change, the GitLab Advanced SAST analyzer was enabled only if you set the CI/CD variable `GITLAB_ADVANCED_SAST_ENABLED` to `true`.
Advanced SAST delivers more accurate results by using cross-file, cross-function scanning and a new ruleset.
Advanced SAST takes over coverage for [supported languages](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast#supported-languages) and disables scanning for that language in the previous scanner.
An automated process migrates results from previous scanners after the first scan on each project's default branch, if they're still detected.
Because it scans your project in more detail, Advanced SAST may take more time to scan your project.
If needed, you can [disable GitLab Advanced SAST](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast#disable-gitlab-advanced-sast-scanning) by setting the CI/CD variable `GITLAB_ADVANCED_SAST_ENABLED` to `false`.
You can set this variable in your project, group, or policy now to prevent Advanced SAST from being enabled by default in GitLab 18.0.
</div>
<div class="deprecation breaking-change" data-milestone="19.0">
### GitLab Self-Managed certificate-based integration with Kubernetes
<div class="deprecation-notes">
@ -1544,31 +1569,6 @@ For more information, see the [charts release page](https://docs.gitlab.com/char
</div>
<div class="deprecation breaking-change" data-milestone="18.0">
### GitLab Advanced SAST will be enabled by default
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">17.9</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/513685).
</div>
In GitLab 18.0, we will update the [SAST CI/CD templates](https://docs.gitlab.com/user/application_security/sast#stable-vs-latest-sast-templates) to enable [GitLab Advanced SAST](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast) by default in projects with GitLab Ultimate.
Before this change, the GitLab Advanced SAST analyzer was enabled only if you set the CI/CD variable `GITLAB_ADVANCED_SAST_ENABLED` to `true`.
Advanced SAST delivers more accurate results by using cross-file, cross-function scanning and a new ruleset.
Advanced SAST takes over coverage for [supported languages](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast#supported-languages) and disables scanning for that language in the previous scanner.
An automated process migrates results from previous scanners after the first scan on each project's default branch, if they're still detected.
Because it scans your project in more detail, Advanced SAST may take more time to scan your project.
If needed, you can [disable GitLab Advanced SAST](https://docs.gitlab.com/user/application_security/sast/gitlab_advanced_sast#disable-gitlab-advanced-sast-scanning) by setting the CI/CD variable `GITLAB_ADVANCED_SAST_ENABLED` to `false`.
You can set this variable in your project, group, or policy now to prevent Advanced SAST from being enabled by default in GitLab 18.0.
</div>
<div class="deprecation " data-milestone="18.0">
### Gitaly rate limiting

View File

@ -238,7 +238,7 @@ This rule enforces the defined actions based on security scan findings.
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` or the branch's name | Applicable only to protected target branches. An empty array, `[]`, applies the rule to all protected target branches. Cannot be used with the `branch_type` field. |
| `branch_type` | `string` | true if `branches` field does not exist | `default` or `protected` | The types of protected branches the given policy applies to. Cannot be used with the `branches` field. Default branches must also be `protected`. |
| `branch_exceptions` | `array` of `string` | false | Names of branches | Branches to exclude from this rule. |
| `scanners` | `array` of `string` | true | `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. `sast` includes results from both SAST and SAST IaC scanners. |
| `scanners` | `array` of `string` | true | `[]` or `sast`, `secret_detection`, `dependency_scanning`, `container_scanning`, `dast`, `coverage_fuzzing`, `api_fuzzing` | The security scanners for this rule to consider. `sast` includes results from both SAST and SAST IaC scanners. An empty array, `[]`, applies the rule to all security scanners.|
| `vulnerabilities_allowed` | `integer` | true | Greater than or equal to zero | Number of vulnerabilities allowed before this rule is considered. |
| `severity_levels` | `array` of `string` | true | `info`, `unknown`, `low`, `medium`, `high`, `critical` | The severity levels for this rule to consider. |
| `vulnerability_states` | `array` of `string` | true | `[]` or `detected`, `confirmed`, `resolved`, `dismissed`, `new_needs_triage`, `new_dismissed` | All vulnerabilities fall into two categories:<br><br>**Newly Detected Vulnerabilities** - Vulnerabilities identified in the merge request branch itself but that do not currently exist on the MR's target branch. This policy option requires a pipeline to complete before the rule is evaluated so that it knows whether vulnerabilities are newly detected or not. Merge requests are blocked until the pipeline and necessary security scans are complete. The `new_needs_triage` option considers the status<br><br> • Detected<br><br> The `new_dismissed` option considers the status<br><br> • Dismissed<br><br>**Pre-Existing Vulnerabilities** - these policy options are evaluated immediately and do not require a pipeline complete as they consider only vulnerabilities previously detected in the default branch.<br><br>`Detected` - the policy looks for vulnerabilities in the detected state.<br>`Confirmed` - the policy looks for vulnerabilities in the confirmed state.<br>`Dismissed` - the policy looks for vulnerabilities in the dismissed state.<br>`Resolved` - the policy looks for vulnerabilities in the resolved state. <br><br>An empty array, `[]`, covers the same statuses as `['new_needs_triage', 'new_dismissed']`. |

View File

@ -42,9 +42,8 @@ License approval policies rely on the output of a dependency scanning job to ver
To ensure enforcement of your policies, you should enable dependency scanning on your target development projects. You can achieve this a few different ways:
- Create a global [scan execution policy](../application_security/policies/scan_execution_policies.md) that enforces Dependency Scanning to run in all target development projects.
- Use a [Compliance Pipeline](compliance_frameworks.md) to define a Dependency Scanning job that is enforced on projects enforced by a given Compliance Framework.
- Work with development teams to configure [Dependency Scanning](../application_security/dependency_scanning/_index.md) in each of their project's `.gitlab-ci.yml` files or enable by using the [Security Configuration panel](../application_security/configuration/_index.md).
- Create a [scan execution policy](../application_security/policies/scan_execution_policies.md) that enforces Dependency Scanning to run in all target development projects.
- Work with your development teams to configure [dependency scanning](../application_security/dependency_scanning/_index.md) in each of their projects' `.gitlab-ci.yml` files or enable it by using the [Security Configuration panel](../application_security/configuration/_index.md).
License approval policies require license information from [GitLab-supported packages](license_scanning_of_cyclonedx_files/_index.md#supported-languages-and-package-managers).

View File

@ -40,9 +40,9 @@ To set up GitLab Duo with Amazon Q, you must:
- [Create a profile in the Amazon Q Developer console](#create-a-profile-in-the-amazon-q-developer-console)
- [Create an identity provider](#create-an-iam-identity-provider)
- [Create an IAM role](#create-an-iam-role)
- [Add the policy](#add-the-policy)
- [Allow administrators to use customer managed keys](#allow-administrators-to-use-customer-managed-keys)
- [Edit the role](#edit-the-role)
- [Enter the ARN in GitLab and enable Amazon Q](#enter-the-arn-in-gitlab-and-enable-amazon-q)
- [Allow administrators to use customer managed keys](#allow-administrators-to-use-customer-managed-keys)
### Prerequisites
@ -110,7 +110,14 @@ After you set up the IAM role, you cannot change the AWS account that's associat
1. Select **Web identity**.
1. For **Web identity**, select the provider URL you entered earlier.
1. For **Audience**, select the audience value you entered earlier.
1. Skip **Permissions policies** by selecting **Next**. You will create an inline policy later.
1. Select **Next**.
1. On the **Add permissions** page:
- To use a managed policy, for **Permissions policies**, search for and
select `GitLabDuoWithAmazonQPermissionsPolicy`.
- To create an inline policy, skip **Permissions policies** by selecting **Next**.
You will create a policy later.
1. Select **Next**.
1. Name the role, for example `QDeveloperAccess`.
1. Ensure the trust policy is correct. It should look like this:
```json
@ -134,20 +141,11 @@ After you set up the IAM role, you cannot change the AWS account that's associat
}
```
1. Name the role, for example `QDeveloperAccess`, and select **Create role**.
1. Select **Create role**.
### Add the policy
### Create an inline policy (optional)
Now edit the role and add the policy:
1. Find the role that you just created and select it.
1. Change the session time to 12 hours. The `AssumeRoleWithWebIdentity` will fail
in the AI Gateway if the session is not set to 12 hours or more.
1. In the **Roles search** field, enter the name of your IAM role and then choose the role name.
1. In **Summary**, choose **Edit** to edit the session duration.
1. Choose the **Maximum session duration** dropdown menu, and then choose **12 hours**.
1. Choose **Save changes**.
To create an inline policy, rather than using a managed policy:
1. Select **Permissions > Add permissions > Create inline policy**.
1. Select **JSON** and paste the following in the editor:
@ -196,13 +194,60 @@ Now edit the role and add the policy:
1. Select **Actions > Optimize for readability** to make AWS format and parse the JSON.
1. Select **Next**.
1. Name the policy `gitlab-duo-amazon-q-policy` and select **Create policy**.
### Edit the role
Now edit the role:
1. Find the role that you just created and select it.
1. Change the session time to 12 hours. The `AssumeRoleWithWebIdentity` will fail
in the AI Gateway if the session is not set to 12 hours or more.
1. In the **Roles search** field, enter the name of your IAM role and then choose the role name.
1. In **Summary**, choose **Edit** to edit the session duration.
1. Choose the **Maximum session duration** dropdown list, and then choose **12 hours**.
1. Choose **Save changes**.
1. Copy the ARN listed on the page. It will look similar to this:
```plaintext
arn:aws:iam::123456789:role/QDeveloperAccess
```
#### Allow administrators to use customer managed keys
### Enter the ARN in GitLab and enable Amazon Q
Now, enter the ARN into GitLab and determine which groups and projects can access the feature.
Prerequisites:
- You must be a GitLab administrator.
To finish setting up GitLab Duo with Amazon Q:
1. Sign in to GitLab.
1. On the left sidebar, at the bottom, select **Admin**.
1. Select **Settings > General**.
1. Expand **GitLab Duo with Amazon Q**.
1. Select **View configuration setup**.
1. Under **IAM role's ARN**, paste the ARN.
1. To determine which groups and projects can use GitLab Duo with Amazon Q, choose an option:
- To turn it on for the instance, but let groups and projects turn it off, select **On by default**.
- Optional. To configure Amazon Q to automatically review code in merge requests, select **Have Amazon Q review code in merge requests automatically**.
- To turn it off for the instance, but let groups and projects turn it on, select **Off by default**.
- To turn it off for the instance, and to prevent groups or projects from ever turning it on, select **Always off**.
1. Select **Save changes**.
When you save, an API should contact the AI Gateway to create an OAuth application on Amazon Q.
To confirm that it was successful:
- In the Amazon CloudWatch console log, check for a `204` status code. For more information, see
[What is Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)?
- In GitLab, a notification that says `Amazon Q settings have been saved` is displayed.
- In GitLab, on the left sidebar, select **Applications**. The Amazon Q OAuth application is displayed.
## Allow administrators to use customer managed keys
If you are an administrator, you can use AWS Key Management Service (AWS KMS)
customer managed keys (CMKs) to encrypt customer data.
@ -245,37 +290,6 @@ With the condition key, you can limit who can use CMK for encrypting or decrypti
For more information, see
[`kms:ViaService` in the AWS KMS Developer Guide](https://docs.aws.amazon.com/kms/latest/developerguide/conditions-kms.html#conditions-kms-via-service).
### Enter the ARN in GitLab and enable Amazon Q
Now, enter the ARN into GitLab and determine which groups and projects can access the feature.
Prerequisites:
- You must be a GitLab administrator.
1. Sign in to GitLab.
1. On the left sidebar, at the bottom, select **Admin**.
1. Select **Settings > General**.
1. Expand **GitLab Duo with Amazon Q**.
1. Select **View configuration setup**.
1. Under **IAM role's ARN**, paste the ARN.
1. To determine which groups and projects can use GitLab Duo with Amazon Q, choose an option:
- To turn it on for the instance, but let groups and projects turn it off, select **On by default**.
- Optional. To configure Amazon Q to automatically review code in merge requests, select **Have Amazon Q review code in merge requests automatically**.
- To turn it off for the instance, but let groups and projects turn it on, select **Off by default**.
- To turn it off for the instance, and to prevent groups or projects from ever turning it on, select **Always off**.
1. Select **Save changes**.
When you save, an API should contact the AI Gateway to create an OAuth application on Amazon Q.
To confirm that it was successful:
- In the Amazon CloudWatch console log, check for a `204` status code. For more information, see
[What is Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)?
- In GitLab, a notification that says `Amazon Q settings have been saved` is displayed.
- In GitLab, on the left sidebar, select **Applications**. The Amazon Q OAuth application is displayed.
## Turn off GitLab Duo with Amazon Q
You can turn off GitLab Duo with Amazon Q for the instance, group, or project.

View File

@ -45,7 +45,20 @@ module Gitlab
end
def user_filter(login)
filter = Net::LDAP::Filter.equals(config.uid, login)
# Allow LDAP users to authenticate by using their GitLab username in case
# their LDAP username does not match GitLab username or
# their LDAP username collide with another user's GitLab username.
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/186848
uid = if ldap_user_is_allowed_to_authenticate_with_gitlab_username?
::Gitlab::Auth::Ldap::Person.find_by_dn(
user.ldap_identity.extern_uid,
Gitlab::Auth::Ldap::Adapter.new(provider)
)&.uid
end
uid ||= login
filter = Net::LDAP::Filter.equals(config.uid, uid)
# Apply LDAP user filter if present
if config.user_filter.present?
@ -54,6 +67,12 @@ module Gitlab
filter
end
private
def ldap_user_is_allowed_to_authenticate_with_gitlab_username?
user && user.ldap_user? && Feature.enabled?(:allow_ldap_users_to_authenticate_with_gitlab_username, user)
end
end
end
end

48
lib/idempotency_cache.rb Normal file
View File

@ -0,0 +1,48 @@
# frozen_string_literal: true
# rubocop:disable Gitlab/NamespacedClass -- generic code
# rubocop:disable Gitlab/BoundedContexts -- generic code
class IdempotencyCache
# When code is wrapped with ensure_idempotency it won't be
# called again within the TTL(time to live) for the same key
# if the operation was successful completed
#
# Example:
# IdempotencyCache.ensure_idempotency("tracking_cache:#{build_id}", 5.hours)
# # idempotent within the TTL
# # wont run again if it ran successfully for that build within 5 hours
# track(params)
# end
def self.ensure_idempotency(key, ttl)
return if already_completed?(key)
result = yield
new(key, ttl).mark_as_completed!
result
end
def self.already_completed?(key)
Gitlab::Redis::SharedState.with do |redis|
redis.exists?(key) # rubocop:disable CodeReuse/ActiveRecord -- not active record
end
end
def initialize(key, ttl)
@key = key
@ttl = ttl
end
def mark_as_completed!
Gitlab::Redis::SharedState.with do |redis|
redis.set(
@key,
1,
ex: @ttl
)
end
end
end
# rubocop:enable Gitlab/NamespacedClass
# rubocop:enable Gitlab/BoundedContexts

49
scripts/lint-i18n-doc.sh Executable file
View File

@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -o pipefail
COLOR_RED="\e[31m"
COLOR_GREEN="\e[32m"
COLOR_YELLOW="\e[33m"
COLOR_RESET="\e[39m"
cd "$(dirname "$0")/.." || exit 1
printf "${COLOR_GREEN}INFO: Linting i18n documents at path $(pwd)...${COLOR_RESET}\n"
ERRORCODE=0
# Set defaults for documentation paths
MD_DOC_PATH='doc-locale/{*,**/*}.md'
MD_DOC_PATH_VALE='doc-locale/'
# Run options if files specified on command line
if [ -n "$1" ]; then
MD_DOC_PATH="$@"
MD_DOC_PATH_VALE="$@"
printf "${COLOR_GREEN}INFO: Checking specified files: ${MD_DOC_PATH}${COLOR_RESET}\n"
fi
# 1. Run Markdownlint
printf "${COLOR_GREEN}INFO: Running Markdownlint on i18n files...${COLOR_RESET}\n"
# PHASE 1: Check but don't fail on markdown errors
# TODO: PHASE 2, fail the build with proper error codes https://gitlab.com/gitlab-com/localization/docs-site-localization/-/issues/127#note_2450926413
yarn markdownlint ${MD_DOC_PATH} || {
printf "${COLOR_YELLOW}WARNING: Markdownlint found issues in i18n files, but continuing...${COLOR_RESET}\n"
# Error code not incremented in Phase 1
}
# 2. Run Vale
printf "${COLOR_GREEN}INFO: Running Vale on i18n files...${COLOR_RESET}\n"
# PHASE 1: Check but don't fail on vale errors
# TODO: PHASE 2, fail the build with proper error codes https://gitlab.com/gitlab-com/localization/docs-site-localization/-/issues/127#note_2450926413
vale --minAlertLevel error --filter='.Name matches "gitlab_docs"' ${MD_DOC_PATH_VALE} || {
printf "${COLOR_YELLOW}WARNING: Vale found issues in i18n files, but continuing...${COLOR_RESET}\n"
# Error code not incremented in Phase 1
}
# Report results
if [ "$ERRORCODE" -ne 0 ]; then
printf "\n${COLOR_RED}ERROR: i18n lint checks failed!${COLOR_RESET}\n"
exit 1
else
printf "\n${COLOR_GREEN}SUCCESS: All i18n lint checks passed${COLOR_RESET}\n"
exit 0
fi

View File

@ -155,5 +155,9 @@ FactoryBot.define do
trait :locked do
locked { true }
end
trait :hosted_runner do
creator { Users::Internal.admin_bot }
end
end
end

View File

@ -1,7 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import { GlBreadcrumb } from '@gitlab/ui';
import WorkItemBreadcrumb from '~/work_items/components/work_item_breadcrumb.vue';
import { WORK_ITEM_TYPE_ENUM_EPIC } from '~/work_items/constants';
import { WORK_ITEM_TYPE_NAME_EPIC } from '~/work_items/constants';
describe('WorkItemBreadcrumb', () => {
let wrapper;
@ -36,7 +36,7 @@ describe('WorkItemBreadcrumb', () => {
describe('when the workspace is a group', () => {
it('renders a href to the legacy epics page if the workItemEpicsList feature is disabled', () => {
createComponent({ workItemType: WORK_ITEM_TYPE_ENUM_EPIC, workItemEpicsList: false });
createComponent({ workItemType: WORK_ITEM_TYPE_NAME_EPIC, workItemEpicsList: false });
expect(findBreadcrumb().props('items')).toEqual([
{
@ -61,7 +61,7 @@ describe('WorkItemBreadcrumb', () => {
});
it('renders root `Epics` breadcrumb on epics list page', () => {
createComponent({ workItemType: WORK_ITEM_TYPE_ENUM_EPIC });
createComponent({ workItemType: WORK_ITEM_TYPE_NAME_EPIC });
expect(findBreadcrumb().props('items')).toEqual([
{

View File

@ -18,7 +18,7 @@ import {
} from 'jest/issues/list/mock_data';
import setWindowLocation from 'helpers/set_window_location_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { STATUS_CLOSED, STATUS_OPEN, TYPE_ISSUE } from '~/issues/constants';
import { STATUS_CLOSED, STATUS_OPEN } from '~/issues/constants';
import { CREATED_DESC, UPDATED_DESC } from '~/issues/list/constants';
import setSortPreferenceMutation from '~/issues/list/queries/set_sort_preference.mutation.graphql';
import { scrollUp } from '~/lib/utils/scroll_utils';
@ -52,6 +52,8 @@ import {
DETAIL_VIEW_QUERY_PARAM_NAME,
STATE_CLOSED,
WORK_ITEM_TYPE_ENUM_EPIC,
WORK_ITEM_TYPE_NAME_EPIC,
WORK_ITEM_TYPE_NAME_ISSUE,
} from '~/work_items/constants';
import { createRouter } from '~/work_items/router';
import {
@ -145,7 +147,7 @@ describeSkipVue3(skipReason, () => {
mountComponent({
provide: {
workItemType: TYPE_ISSUE,
workItemType: WORK_ITEM_TYPE_NAME_ISSUE,
glFeatures: {
issuesListDrawer: true,
},
@ -251,8 +253,7 @@ describeSkipVue3(skipReason, () => {
describe('when workItemType is provided', () => {
it('filters work items by workItemType', async () => {
const type = 'EPIC';
mountComponent({ provide: { workItemType: type } });
mountComponent({ provide: { workItemType: WORK_ITEM_TYPE_NAME_EPIC } });
await waitForPromises();
@ -262,16 +263,15 @@ describeSkipVue3(skipReason, () => {
includeDescendants: true,
sort: CREATED_DESC,
state: STATUS_OPEN,
types: type,
types: WORK_ITEM_TYPE_ENUM_EPIC,
}),
);
});
});
describe('when workItemType EPIC is provided', () => {
describe('when workItemType Epic is provided', () => {
it('sends excludeProjects variable in GraphQL query', async () => {
const type = 'EPIC';
mountComponent({ provide: { workItemType: type } });
mountComponent({ provide: { workItemType: WORK_ITEM_TYPE_NAME_EPIC } });
await waitForPromises();
@ -343,7 +343,7 @@ describeSkipVue3(skipReason, () => {
describe('when workItemType is defined', () => {
it('renders all tokens except "Type"', async () => {
mountComponent({ provide: { workItemType: 'EPIC' } });
mountComponent({ provide: { workItemType: WORK_ITEM_TYPE_NAME_EPIC } });
await waitForPromises();
const tokens = findIssuableList()
.props('searchTokens')
@ -659,7 +659,7 @@ describeSkipVue3(skipReason, () => {
issuesListDrawer: true,
epicsListDrawer: false,
},
workItemType: WORK_ITEM_TYPE_ENUM_EPIC,
workItemType: WORK_ITEM_TYPE_NAME_EPIC,
},
});
await waitForPromises();
@ -676,7 +676,7 @@ describeSkipVue3(skipReason, () => {
issuesListDrawer: false,
epicsListDrawer: true,
},
workItemType: WORK_ITEM_TYPE_ENUM_EPIC,
workItemType: WORK_ITEM_TYPE_NAME_EPIC,
},
});
await waitForPromises();
@ -706,7 +706,7 @@ describeSkipVue3(skipReason, () => {
getParameterByName.mockReturnValue(show);
mountComponent({
provide: {
workItemType: TYPE_ISSUE,
workItemType: WORK_ITEM_TYPE_NAME_ISSUE,
glFeatures: {
issuesListDrawer: true,
},

View File

@ -3,16 +3,20 @@
require 'spec_helper'
RSpec.describe Gitlab::Auth::Ldap::Authentication do
let(:dn) { 'uid=John Smith, ou=People, dc=example, dc=com' }
let(:user) { create(:omniauth_user, :ldap, extern_uid: Gitlab::Auth::Ldap::Person.normalize_dn(dn)) }
let(:login) { 'john' }
include LdapHelpers
let(:provider) { 'ldapmain' }
let(:uid) { 'john' }
let(:dn) { user_dn(uid) }
let(:user) { create(:omniauth_user, :ldap, extern_uid: dn) }
let(:login) { uid }
let(:password) { 'password' }
describe 'login' do
before do
allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
end
before do
stub_ldap_setting(enabled: true)
end
describe '.login' do
it "finds the user if authentication is successful" do
expect(user).not_to be_nil
@ -60,4 +64,100 @@ RSpec.describe Gitlab::Auth::Ldap::Authentication do
expect(described_class.login(login, '')).to be_falsey
end
end
describe '#login' do
let(:adapter) { instance_double(OmniAuth::LDAP::Adaptor) }
before do
allow_next_instance_of(described_class) do |instance|
allow(instance).to receive(:adapter).and_return(adapter)
end
end
context 'with GitLab username' do
subject(:authentication) { described_class.new(provider, user).login(login, password) }
let(:login) { user.username }
it "identifies the user's LDAP UID and uses it for authentication" do
stub_ldap_person_find_by_dn(ldap_user_entry(uid), provider)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, uid),
size: 1,
password: password
).and_return(ldap_user_entry(uid))
expect(authentication).to eq(user)
end
context 'when allow_ldap_users_to_authenticate_with_gitlab_username FF is disabled' do
before do
stub_feature_flags(allow_ldap_users_to_authenticate_with_gitlab_username: false)
end
it "does not try to identify the user's LDAP UID and and uses specified login for authentication" do
expect(::Gitlab::Auth::Ldap::Person).not_to receive(:find_by_dn)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
)
expect(authentication).to be_nil
end
end
context "when the user's LDAP UID cannot be identified" do
it 'uses specified login for authentication' do
stub_ldap_person_find_by_dn(nil, provider)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
)
expect(authentication).to be_nil
end
end
context 'when the user is not a LDAP user' do
let(:user) { create(:user) }
it "does not try to identify the user's LDAP UID and and uses specified login for authentication" do
expect(::Gitlab::Auth::Ldap::Person).not_to receive(:find_by_dn)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
)
expect(authentication).to be_nil
end
end
end
context 'with LDAP UID that does not match GitLab username' do
subject(:authentication) { described_class.new(provider).login(login, password) }
let(:login) { uid }
it "does not try to identify the user's LDAP UID and and uses specified login for authentication" do
expect(user).not_to be_nil
expect(::Gitlab::Auth::Ldap::Person).not_to receive(:find_by_dn)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
).and_return(ldap_user_entry(login))
expect(authentication).to eq(user)
end
end
end
end

View File

@ -1319,28 +1319,200 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching, feature_cate
end
end
context "with ldap enabled" do
context 'with LDAP enabled' do
include LdapHelpers
let(:provider) { 'ldapmain' }
before do
allow(Gitlab::Auth::Ldap::Config).to receive(:enabled?).and_return(true)
stub_ldap_setting(enabled: true)
allow(Devise).to receive(:omniauth_providers).and_return([provider.to_sym])
end
it 'does not try to authenticate with LDAP for local users' do
it 'does not try to authenticate with LDAP fallback for local users' do
expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login)
expect(gl_auth.find_with_user_password(username, user.password)).to eq(user)
end
it "does not find user by using ldap as fallback to for authentication" do
it 'does not find user by using LDAP fallback for authentication' do
expect(Gitlab::Auth::Ldap::Authentication).to receive(:login).and_return(nil)
expect(gl_auth.find_with_user_password('ldap_user', 'password')).to be_nil
end
it "finds a user by using ldap as a fallback for authentication" do
it 'finds a user by using LDAP fallback for authentication' do
expect(Gitlab::Auth::Ldap::Authentication).to receive(:login).and_return(user)
expect(gl_auth.find_with_user_password('ldap_user', 'password')).to eq(user)
end
context 'for LDAP users' do
subject(:authentication) { gl_auth.find_with_user_password(login, password) }
let(:uid) { 'john-ldap' }
let(:gitlab_username) { 'john-gitlab' }
let(:dn) { user_dn(uid) }
let(:user) { create(:omniauth_user, :ldap, username: gitlab_username, extern_uid: dn) }
let(:password) { 'password' }
let(:adapter) { instance_double(OmniAuth::LDAP::Adaptor) }
before do
allow_next_instance_of(Gitlab::Auth::Ldap::Authentication) do |instance|
allow(instance).to receive(:adapter).and_return(adapter)
end
end
context 'when LDAP UID does not match GitLab username' do
context 'with LDAP UID' do
let(:login) { uid }
it 'finds a user by using LDAP fallback for authentication' do
expect(Gitlab::Auth::Ldap::Authentication).to receive(:login).with(login, password).and_return(user)
expect(authentication).to eq(user)
end
end
context 'with GitLab username' do
let(:login) { gitlab_username }
it "uses LDAP authentication based on the user's LDAP identity" do
expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login)
ldap_authentication = instance_double(Gitlab::Auth::Ldap::Authentication)
expect(Gitlab::Auth::Ldap::Authentication).to receive(:new).with(provider, user).and_return(ldap_authentication)
expect(ldap_authentication).to receive(:login).with(login, password).and_return(user)
expect(authentication).to eq(user)
end
it "identifies the user's LDAP UID and uses it for authentication" do
stub_ldap_person_find_by_dn(ldap_user_entry(uid), provider)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, uid),
size: 1,
password: password
).and_return(ldap_user_entry(uid))
expect(authentication).to eq(user)
end
context 'when allow_ldap_users_to_authenticate_with_gitlab_username FF is disabled' do
before do
stub_feature_flags(allow_ldap_users_to_authenticate_with_gitlab_username: false)
end
it "does not try to identify the user's LDAP UID and and uses specified login for authentication" do
expect(::Gitlab::Auth::Ldap::Person).not_to receive(:find_by_dn)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
)
expect(authentication).to be_nil
end
end
end
end
context 'when LDAP UID matches GitLab username' do
let(:gitlab_username) { uid }
let(:login) { uid }
it "uses LDAP authentication based on the user's LDAP identity" do
expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login)
ldap_authentication = instance_double(Gitlab::Auth::Ldap::Authentication)
expect(Gitlab::Auth::Ldap::Authentication).to receive(:new).with(provider, user).and_return(ldap_authentication)
expect(ldap_authentication).to receive(:login).with(login, password).and_return(user)
expect(authentication).to eq(user)
end
it "identifies the user's LDAP UID and uses it for authentication" do
stub_ldap_person_find_by_dn(ldap_user_entry(uid), provider)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, uid),
size: 1,
password: password
).and_return(ldap_user_entry(uid))
expect(authentication).to eq(user)
end
context 'when allow_ldap_users_to_authenticate_with_gitlab_username FF is disabled' do
before do
stub_feature_flags(allow_ldap_users_to_authenticate_with_gitlab_username: false)
end
it "does not try to identify the user's LDAP UID and and uses specified login for authentication" do
expect(::Gitlab::Auth::Ldap::Person).not_to receive(:find_by_dn)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
).and_return(ldap_user_entry(login))
expect(authentication).to eq(user)
end
end
end
context 'when LDAP UID matches GitLab username of another user' do
let!(:another_user) { create(:user, username: uid) }
context 'with LDAP UID' do
let(:login) { uid }
it 'tries to autheticate as another user' do
expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:login)
expect(Gitlab::Auth::Ldap::Authentication).not_to receive(:new)
expect(Gitlab::Auth::Database::Authentication).to receive(:new).with('database', another_user).and_call_original
expect(authentication).to be_nil
end
end
context 'with GitLab username' do
let(:login) { gitlab_username }
it "identifies the user's LDAP UID and uses it for authentication" do
stub_ldap_person_find_by_dn(ldap_user_entry(uid), provider)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, uid),
size: 1,
password: password
).and_return(ldap_user_entry(uid))
expect(authentication).to eq(user)
end
context 'when allow_ldap_users_to_authenticate_with_gitlab_username FF is disabled' do
before do
stub_feature_flags(allow_ldap_users_to_authenticate_with_gitlab_username: false)
end
it "does not try to identify the user's LDAP UID and and uses specified login for authentication" do
expect(::Gitlab::Auth::Ldap::Person).not_to receive(:find_by_dn)
expect(adapter).to receive(:bind_as).with(
filter: Net::LDAP::Filter.equals(Gitlab::Auth::Ldap::Config.new(provider).uid, login),
size: 1,
password: password
)
expect(authentication).to be_nil
end
end
end
end
end
end
context "with password authentication disabled for Git" do

View File

@ -0,0 +1,130 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IdempotencyCache, feature_category: :hosted_runners do
let(:key) { 'test_cache:1' }
let(:ttl) { 5.hours }
describe '.already_completed?', :clean_gitlab_redis_shared_state do
subject(:already_completed?) { described_class.already_completed?(key) }
context 'when cache key does not exist' do
it 'returns false' do
expect(already_completed?).to be false
end
end
context 'when cache key exists' do
before do
Gitlab::Redis::SharedState.with do |redis|
redis.set(key, 1, ex: ttl)
end
end
it 'returns true' do
expect(already_completed?).to be true
end
end
end
describe '.ensure_idempotency', :clean_gitlab_redis_shared_state do
it 'yields the block on first call' do
block_called = false
described_class.ensure_idempotency(key, ttl) do
block_called = true
end
expect(block_called).to be true
end
it 'sets the cache key after executing the block' do
described_class.ensure_idempotency(key, ttl) { 'test result' }
expect(described_class.already_completed?(key)).to be true
end
it 'does not yield the block on second call with same key' do
call_count = 0
2.times do
described_class.ensure_idempotency(key, ttl) do
call_count += 1
end
end
expect(call_count).to eq(1)
end
it 'yields the block when called with different keys' do
call_count = 0
described_class.ensure_idempotency(key, ttl) do
call_count += 1
end
described_class.ensure_idempotency('different key', ttl) do
call_count += 1
end
expect(call_count).to eq(2)
end
it 'returns the result of the block on first call' do
result = described_class.ensure_idempotency(key, ttl) { 'test result' }
expect(result).to eq('test result')
end
it 'returns nil on subsequent calls with same params' do
described_class.ensure_idempotency(key, ttl) { 'test result' }
result = described_class.ensure_idempotency(key, ttl) { 'not called' }
expect(result).to be_nil
end
end
describe '#mark_as_completed!', :clean_gitlab_redis_shared_state do
let(:cache) { described_class.new(key, ttl) }
it 'sets the cache key with the specified TTL' do
redis_double = double
expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double)
expect(redis_double).to receive(:set).with(key, 1, ex: ttl)
cache.mark_as_completed!
end
it 'makes already_completed? return true' do
expect(described_class.already_completed?(key)).to be false
cache.mark_as_completed!
expect(described_class.already_completed?(key)).to be true
end
end
context 'with expired cache entries', :clean_gitlab_redis_shared_state do
it 'treats expired entries as not completed' do
ttl = 1.second # shortest valid redis ttl
described_class.ensure_idempotency(key, ttl) { 'test result' }
expect(described_class.already_completed?(key)).to be true
sleep ttl + 0.01.seconds
expect(described_class.already_completed?(key)).to be false
call_count = 0
described_class.ensure_idempotency(key, ttl) do
call_count += 1
end
expect(call_count).to eq(1)
end
end
end

View File

@ -168,6 +168,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
'Ci::UpdateBuildNamesWorker' => 3,
'Ci::MergeRequests::AddTodoWhenBuildFailsWorker' => 3,
'Ci::Minutes::UpdateProjectAndNamespaceUsageWorker' => 3,
'Ci::Minutes::UpdateGitlabHostedRunnerMonthlyUsageWorker' => 3,
'Ci::PipelineArtifacts::CoverageReportWorker' => 3,
'Ci::PipelineArtifacts::CreateQualityReportWorker' => 3,
'Ci::PipelineCleanupRefWorker' => 3,