Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d632a8e913
commit
1ec3642bdf
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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 } }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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']`. |
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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([
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue