Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-02-07 15:11:09 +00:00
parent 7b7daa5813
commit 111d6e2690
51 changed files with 468 additions and 163 deletions

View File

@ -1,6 +1,7 @@
.as-if-jh-sandbox-variables:
variables:
AS_IF_JH_BRANCH: "as-if-jh/${CI_COMMIT_REF_NAME}"
JH_MIRROR_REPOSITORY: "https://dummy:${ADD_JH_FILES_TOKEN}@gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab.git"
SANDBOX_REPOSITORY: "https://dummy:${AS_IF_JH_TOKEN}@gitlab.com/gitlab-org-sandbox/gitlab-jh-validation.git"
.shared-as-if-jh:
@ -13,20 +14,12 @@
add-jh-files:
extends:
- .shared-as-if-jh
- .with_secret
- .as-if-jh:rules:prepare-as-if-jh
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}
stage: prepare
needs: []
secrets:
ADD_JH_FILES_TOKEN:
gcp_secret_manager:
name: ADD_JH_FILES_TOKEN
token: $GCP_ID_TOKEN
before_script:
- source ./scripts/utils.sh
- export ADD_JH_FILES_TOKEN="$(cat ${ADD_JH_FILES_TOKEN})"
- export JH_MIRROR_REPOSITORY="https://dummy:${ADD_JH_FILES_TOKEN}@gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab.git"
- source ./scripts/setup/as-if-jh.sh
- install_gitlab_gem
script:

View File

@ -514,8 +514,3 @@
curl -f --header "Private-Token: ${PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE}" "${url}" --create-dirs --output scripts/utils.sh
- source scripts/utils.sh
- run_timed_command "download_files ${FILES_TO_DOWNLOAD}"
.with_secret:
id_tokens:
GCP_ID_TOKEN:
aud: https://iam.googleapis.com/projects/${GCP_PROJECT_NUMBER}/locations/global/workloadIdentityPools/${GCP_WORKLOAD_IDENTITY_FEDERATION_POOL_ID}/providers/${GCP_WORKLOAD_IDENTITY_FEDERATION_PROVIDER_ID}

View File

@ -1,5 +1,4 @@
<--
<!--
This issue template is sourced from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/SAST%20Ruleset%20Enhancement.md and is maintained by the Secure: Vulnerability Research team (https://handbook.gitlab.com/handbook/engineering/development/sec/secure/vulnerability-research/), most of its content is based on the documentation found in the GitLab SAST Rules Project under https://gitlab.com/gitlab-org/security-products/sast-rules/-/blob/main/docs.
@ -7,13 +6,13 @@ This issue template is sourced from https://gitlab.com/gitlab-org/gitlab/-/blob/
## Background and Rationale behind this Work
<--
<!--
REPLACE: As per https://gitlab.com/gitlab-org/gitlab/-/issues/425704 and https://gitlab.com/gitlab-org/gitlab/-/issues/425704 we are continuously working towards improving the coverage and efficacy of our SAST rules.
-->
### Desired Change
<--
<!--
REPLACE: This issue is aimed at creating, embedding, or enhancing a GitLab SAST rule that detects the issue seen in https://foo.example.com and https://bar.example.com
-->
@ -21,7 +20,7 @@ REPLACE: This issue is aimed at creating, embedding, or enhancing a GitLab SAST
## Implementation Plan
### Assesment
### Assessment
#### If Creating a New Rule
@ -95,14 +94,14 @@ If the addition, inclusion or adaptation of a rule addressing the Desired Change
- [ ] Clone our [Real World Test Projects](https://gitlab.com/gitlab-org/security-products/tests/sast-rules-apps/) and extend it with your MRE demonstrating the problem. Alternatively, discuss the creation of a new folder or repository if none fits.
- [ ] Push the changes to [gitlab-org/security-products/tests/sast-rules-apps](https://gitlab.com/gitlab-org/security-products/tests/sast-rules-apps/) as a feature branch if you have access; otherwise push it to a personal fork of the project
- [ ] Create a new MR and mention this issue in it so they are linked.
- [ ] A member of the @gitlab-org/secure/vulnerability-research team will assign themselves as reviewer shortly, work with them to finalise and merge your work.
- [ ] A member of the `@gitlab-org/secure/vulnerability-research` team will assign themselves as reviewer shortly, work with them to finalise and merge your work.
#### Merge the Rule
- [ ] Push the changes to `sast-rules` as a feature branch to [gitlab-org/security-products/sast-rules](https://gitlab.com/gitlab-org/security-products/sast-rules/) if you have access; otherwise push it to a personal fork of the project.
- [ ] Create the MR and mention this issue in it so they are linked.
- [ ] A member of the @gitlab-org/secure/vulnerability-research team will assign themselves as reviewer shortly, work with them to finalise and merge your work.
- [ ] A member of the `@gitlab-org/secure/vulnerability-research` team will assign themselves as reviewer shortly, work with them to finalise and merge your work.
- [ ] Find the [latest sast-rules release MR](https://gitlab.com/gitlab-org/security-products/sast-rules/-/merge_requests?scope=all&state=opened&search=draft%3A+Release) and add a line to CHANGELOG.md detailing briefly the changes performed, their intent and the MR ID where this work was done.
```

View File

@ -560,7 +560,7 @@ gem 'spamcheck', '~> 1.3.0' # rubocop:todo Gemfile/MissingFeatureCategory
gem 'gitaly', '~> 16.9.0-rc3', feature_category: :gitaly
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.3.0', feature_category: :deployment_management
gem 'kas-grpc', '~> 0.4.0', feature_category: :deployment_management
gem 'grpc', '~> 1.60.0' # rubocop:todo Gemfile/MissingFeatureCategory

View File

@ -341,7 +341,7 @@
{"name":"kaminari-actionview","version":"1.2.2","platform":"ruby","checksum":"1330f6fc8b59a4a4ef6a549ff8a224797289ebf7a3a503e8c1652535287cc909"},
{"name":"kaminari-activerecord","version":"1.2.2","platform":"ruby","checksum":"0dd3a67bab356a356f36b3b7236bcb81cef313095365befe8e98057dd2472430"},
{"name":"kaminari-core","version":"1.2.2","platform":"ruby","checksum":"3bd26fec7370645af40ca73b9426a448d09b8a8ba7afa9ba3c3e0d39cdbb83ff"},
{"name":"kas-grpc","version":"0.3.0","platform":"ruby","checksum":"78dfc454e6725e6354e66e9e65ea87b6ad0888f52d20bf41775e5400d74dad8a"},
{"name":"kas-grpc","version":"0.4.0","platform":"ruby","checksum":"bb21845032b443289b20be8ff8ae22a35abedb3ed17e60ed10b6e5f05bc6738d"},
{"name":"knapsack","version":"1.21.1","platform":"ruby","checksum":"82f70422adebcacec1b514f6ebff65265fc85d836e3c320718a160d8ac41cf14"},
{"name":"kramdown","version":"2.3.2","platform":"ruby","checksum":"cb4530c2e9d16481591df2c9336723683c354e5416a5dd3e447fa48215a6a71c"},
{"name":"kramdown-parser-gfm","version":"1.1.0","platform":"ruby","checksum":"fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729"},

View File

@ -1009,7 +1009,7 @@ GEM
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
kas-grpc (0.3.0)
kas-grpc (0.4.0)
grpc (~> 1.0)
knapsack (1.21.1)
rake
@ -1987,7 +1987,7 @@ DEPENDENCIES
jsonb_accessor (~> 1.3.10)
jwt (~> 2.5)
kaminari (~> 1.2.2)
kas-grpc (~> 0.3.0)
kas-grpc (~> 0.4.0)
knapsack (~> 1.21.1)
kramdown (~> 2.3.1)
kubeclient (~> 4.11.0)

View File

@ -51,7 +51,7 @@ export default {
};
},
result({ data: { activeBoardItem } }) {
if (activeBoardItem) {
if (activeBoardItem && activeBoardItem.listId !== null) {
this.setActiveId('');
}
},

View File

@ -108,6 +108,7 @@ export default {
mutation: setActiveBoardItemMutation,
variables: {
boardItem: this.isActive ? null : this.item,
listId: this.list.id,
isIssue: this.isActive ? undefined : this.isIssueBoard,
},
});
@ -122,7 +123,7 @@ export default {
});
await this.$apollo.mutate({
mutation: setActiveBoardItemMutation,
variables: { boardItem: null },
variables: { boardItem: null, listId: null },
});
}
this.$apollo.mutate({

View File

@ -17,7 +17,7 @@ import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sideb
import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue';
import SidebarLabelsWidget from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { setError } from '../graphql/cache_updates';
import { setError, updateListWeightCache } from '../graphql/cache_updates';
export default {
components: {
@ -163,9 +163,14 @@ export default {
mutation: setActiveBoardItemMutation,
variables: {
boardItem: null,
listId: null,
},
});
},
updateListTotalWeight({ weight }) {
const { cache } = this.$apollo.provider.clients.defaultClient;
updateListWeightCache({ weight, listId: this.activeBoardCard.listId, cache });
},
},
};
</script>
@ -280,6 +285,7 @@ export default {
:iid="activeBoardIssuable.iid"
:full-path="projectPathForActiveIssue"
:issuable-type="issuableType"
@weightUpdated="updateListTotalWeight"
/>
<sidebar-health-status-widget
v-if="healthStatusFeatureAvailable"

View File

@ -627,6 +627,7 @@ export default {
mutation: setActiveBoardItemMutation,
variables: {
boardItem: issuable,
listId: this.list.id,
isIssue: this.isIssueBoard,
},
});

View File

@ -235,7 +235,7 @@ export default {
openSidebarSettings() {
this.$apollo.mutate({
mutation: setActiveBoardItemMutation,
variables: { boardItem: null },
variables: { boardItem: null, listId: null },
});
this.$emit('setActiveList', this.list.id);

View File

@ -139,6 +139,21 @@ export function updateEpicsCount({
);
}
export function updateListWeightCache({ weight, listId, cache }) {
cache.updateQuery(
{
query: listQuery,
variables: { id: listId },
},
({ boardList }) => ({
boardList: {
...boardList,
totalIssueWeight: toNumber(boardList.totalIssueWeight) + weight,
},
}),
);
}
export function setError({ message, error, captureError = true }) {
defaultClient.mutate({
mutation: setErrorMutation,

View File

@ -3,5 +3,6 @@
query activeBoardItem {
activeBoardItem @client {
...Issue
listId
}
}

View File

@ -1,7 +1,8 @@
#import "ee_else_ce/boards/graphql/issue.fragment.graphql"
mutation setActiveBoardItem($boardItem: Issue) {
setActiveBoardItem(boardItem: $boardItem) @client {
mutation setActiveBoardItem($boardItem: Issue, $listId: ListID!) {
setActiveBoardItem(boardItem: $boardItem, listId: $listId) @client {
...Issue
listId
}
}

View File

@ -220,12 +220,12 @@ export const resolvers = {
});
cache.writeQuery({ query: getIssueStateQuery, data });
},
setActiveBoardItem(_, { boardItem }, { cache }) {
setActiveBoardItem(_, { boardItem, listId }, { cache }) {
cache.writeQuery({
query: activeBoardItemQuery,
data: { activeBoardItem: boardItem },
data: { activeBoardItem: { ...boardItem, listId } },
});
return boardItem;
return { ...boardItem, listId };
},
setSelectedBoardItems(_, { itemId }, { cache }) {
const sourceData = cache.readQuery({ query: selectedBoardItemsQuery });

View File

@ -6,12 +6,6 @@
max-width: 960px;
}
.borderless {
.login-box {
box-shadow: none;
}
}
.g-recaptcha {
> div {
margin-left: auto;
@ -20,16 +14,11 @@
}
.new-session-tabs {
&.nav-links-unboxed {
border-color: transparent;
box-shadow: none;
display: flex;
border-color: transparent;
.nav-item {
border-left: 0;
border-right: 0;
border-bottom: 1px solid $gray-100;
background-color: transparent;
}
.nav-item {
border-bottom: 1px solid $gray-100;
.nav-link.active {
.gl-dark & {
@ -38,28 +27,9 @@
}
}
display: flex;
box-shadow: 0 0 0 1px $border-color;
border-top-right-radius: $border-radius-default;
border-top-left-radius: $border-radius-default;
li {
flex: 1;
text-align: center;
border-left: 1px solid $border-color;
&:first-of-type {
border-left: 0;
border-top-left-radius: $border-radius-default;
}
&:last-of-type {
border-top-right-radius: $border-radius-default;
}
&:not(.active) {
background-color: $gray-light;
}
a {
width: 100%;

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
module ParseCommitDate
extend ActiveSupport::Concern
def convert_date_to_epoch(date)
Date.strptime(date, "%Y-%m-%d")&.to_time&.to_i if date
rescue Date::Error, TypeError
end
end

View File

@ -5,6 +5,7 @@ require "base64"
class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath
include RendersCommits
include ParseCommitDate
COMMITS_DEFAULT_LIMIT = 40
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
@ -75,6 +76,8 @@ class Projects::CommitsController < Projects::ApplicationController
@offset = (permitted_params[:offset] || 0).to_i
search = permitted_params[:search]
author = permitted_params[:author]
committed_before = convert_date_to_epoch(permitted_params[:committed_before])
committed_after = convert_date_to_epoch(permitted_params[:committed_after])
# fully_qualified_ref is available in some situations from ExtractsRef
ref = @fully_qualified_ref || @ref
@ -89,6 +92,8 @@ class Projects::CommitsController < Projects::ApplicationController
offset: @offset
}
options[:author] = author if author.present?
options[:before] = committed_before if committed_before.present?
options[:after] = committed_after if committed_after.present?
@repository.commits(ref, **options)
end
@ -101,6 +106,6 @@ class Projects::CommitsController < Projects::ApplicationController
end
def permitted_params
params.permit(:limit, :offset, :search, :author)
params.permit(:limit, :offset, :search, :author, :committed_before, :committed_after)
end
end

View File

@ -12,6 +12,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
include DiffHelper
include Gitlab::Cache::Helpers
include MergeRequestsHelper
include ParseCommitDate
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
skip_before_action :merge_request, only: [:index, :bulk_update, :export_csv]
@ -639,11 +640,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
diff_head: true
)
end
def convert_date_to_epoch(date)
Date.strptime(date, "%Y-%m-%d")&.to_time&.to_i if date
rescue Date::Error, TypeError
end
end
Projects::MergeRequestsController.prepend_mod_with('Projects::MergeRequestsController')

View File

@ -33,40 +33,16 @@ module Repositories
def execute(new_version)
tags = {}
versions = [new_version]
begin
regex = Gitlab::UntrustedRegexp.new(@regex)
rescue RegexpError => e
# The error messages produced by default are not very helpful, so we
# raise a better one here. We raise the specific error here so its
# message is displayed in the API (where we catch this specific
# error).
raise(
Gitlab::Changelog::Error,
"The regular expression to use for finding the previous tag for a version is invalid: #{e.message}"
)
end
requested_version = extract_version(new_version)
return unless requested_version
versions = [requested_version]
@project.repository.tags.each do |tag|
matches = regex.match(tag.name)
version = extract_version(tag.name)
next unless matches
# When using this class for generating changelog data for a range of
# commits, we want to compare against the tag of the last _stable_
# release; not some random RC that came after that.
next if matches[:pre]
major = matches[:major]
minor = matches[:minor]
patch = matches[:patch]
build = matches[:meta]
next unless major && minor && patch
version = "#{major}.#{minor}.#{patch}"
version += "+#{build}" if build
next unless version
tags[version] = tag
versions << version
@ -74,9 +50,47 @@ module Repositories
VersionSorter.sort!(versions)
index = versions.index(new_version)
index = versions.index(requested_version)
tags[versions[index - 1]] if index&.positive?
end
private
def version_matcher
@version_matcher ||= Gitlab::UntrustedRegexp.new(@regex)
rescue RegexpError => e
# The error messages produced by default are not very helpful, so we
# raise a better one here. We raise the specific error here so its
# message is displayed in the API (where we catch this specific
# error).
raise(
Gitlab::Changelog::Error,
"The regular expression to use for finding the previous tag for a version is invalid: #{e.message}"
)
end
def extract_version(string)
matches = version_matcher.match(string)
return unless matches
# When using this class for generating changelog data for a range of
# commits, we want to compare against the tag of the last _stable_
# release; not some random RC that came after that.
return if matches[:pre]
major = matches[:major]
minor = matches[:minor]
patch = matches[:patch]
build = matches[:meta]
return unless major && minor && patch
version = "#{major}.#{minor}.#{patch}"
version += "+#{build}" if build
version
end
end
end

View File

@ -581,9 +581,7 @@ module Ci
end
def self.use_partition_id_filter?
::Gitlab::SafeRequestStore.fetch(:ci_builds_partition_id_query_filter) do
::Feature.enabled?(:ci_builds_partition_id_query_filter)
end
true
end
def uses_needs?

View File

@ -4,7 +4,9 @@ class CodequalityDegradationEntity < Grape::Entity
expose :description
expose :fingerprint
expose :severity do |degradation|
degradation.dig(:severity)&.downcase
severity = degradation.dig(:severity)&.downcase
::Gitlab::Ci::Reports::CodequalityReports::SEVERITY_PRIORITIES.key?(severity) ? severity : 'unknown'
end
expose :file_path do |degradation|

View File

@ -50,6 +50,10 @@ module Ci
yield(pipelines_project_merge_request_path(merge_request))
yield(merge_request_widget_path(merge_request))
end
pipeline.project.merge_requests.by_merged_or_merge_or_squash_commit_sha(pipeline.sha).each do |merge_request|
yield(merge_request_widget_path(merge_request))
end
end
def graphql_pipeline_path(pipeline)

View File

@ -38,6 +38,10 @@ module Projects
return ServiceResponse.error(message: _('Project already forked'), reason: :already_forked)
end
if fork_to_project == @project
return ServiceResponse.error(message: _('Target project cannot be equal to source project'), reason: :self_fork)
end
build_fork_network_member(fork_to_project)
if link_fork_network(fork_to_project)

View File

@ -4,16 +4,15 @@
.row.gl-mt-5.justify-content-center
.col-md-5
.login-page
.borderless
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap', admin_mode: true
- elsif allow_admin_mode_password_authentication_for_web?
= render 'devise/sessions/new_base', admin_mode: true
- if any_form_based_providers_enabled?
= render 'devise/shared/tabs_ldap', admin_mode: true
- elsif allow_admin_mode_password_authentication_for_web?
= render 'devise/sessions/new_base', admin_mode: true
-# Show a message if none of the mechanisms above are enabled
- if !allow_admin_mode_password_authentication_for_web? && !ldap_sign_in_enabled? && !omniauth_enabled?
.gl-mt-3.center
= _('No authentication methods configured.')
-# Show a message if none of the mechanisms above are enabled
- if !allow_admin_mode_password_authentication_for_web? && !ldap_sign_in_enabled? && !omniauth_enabled?
.gl-mt-3.center
= _('No authentication methods configured.')
- if omniauth_enabled? && button_based_providers_enabled?
= render 'devise/shared/omniauth_box', render_remember_me: false
- if omniauth_enabled? && button_based_providers_enabled?
= render 'devise/shared/omniauth_box', render_remember_me: false

View File

@ -4,9 +4,8 @@
.row.justify-content-center
.col-md-5
.login-page
.borderless
.login-box.gl-p-5
- if current_user.two_factor_enabled?
= render 'admin/sessions/two_factor_otp'
- if current_user.two_factor_webauthn_enabled?
= render 'authentication/authenticate', render_remember_me: false, target_path: admin_session_path
.login-box.gl-p-5
- if current_user.two_factor_enabled?
= render 'admin/sessions/two_factor_otp'
- if current_user.two_factor_webauthn_enabled?
= render 'authentication/authenticate', render_remember_me: false, target_path: admin_session_path

View File

@ -7,7 +7,7 @@
= header_message
= render "layouts/init_client_detection_flags"
= yield :sessions_broadcast
.gl-h-full.borderless.gl-display-flex.gl-flex-wrap
.gl-h-full.gl-display-flex.gl-flex-wrap
.container.gl-align-self-center
.content
= render "layouts/flash"

View File

@ -1,8 +0,0 @@
---
name: ci_builds_partition_id_query_filter
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130073
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/431361
milestone: '16.6'
type: development
group: group::pipeline execution
default_enabled: false

View File

@ -700,6 +700,59 @@ Get the external wiki settings for a project.
GET /projects/:id/integrations/external-wiki
```
## GitGuardian
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** SaaS, self-managed
**Status:** Beta
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435706) in GitLab 16.9 [with a flag](../administration/feature_flags.md) named `git_guardian_integration`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../administration/feature_flags.md) named `git_guardian_integration`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
[GitGuardian](https://www.gitguardian.com/) is a cybersecurity service that detects sensitive data such as API keys
and passwords in source code repositories.
It scans Git repositories, alerts on policy violations, and helps organizations
fix security issues before hackers can exploit them.
You can configure GitLab to reject commits based on GitGuardian policies.
This feature is in [Beta](../policy/experiment-beta-support.md#beta) and subject to change without notice.
### Set up GitGuardian
Set up the GitGuardian integration for a project.
```plaintext
PUT /projects/:id/integrations/git-guardian
```
Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- |-----------------------------------------------|
| `token` | string | true | GitGuardian API token with `scan` scope. |
### Disable GitGuardian
Disable the GitGuardian integration for a project. Integration settings are reset.
```plaintext
DELETE /projects/:id/integrations/git-guardian
```
### Get GitGuardian settings
Get the GitGuardian integration settings for a project.
```plaintext
GET /projects/:id/integrations/git-guardian
```
## GitHub
DETAILS:

View File

@ -366,6 +366,9 @@ If the `version` attribute is `2.1.0`, GitLab uses tag `v2.0.0`. And when the
version is `1.1.1`, or `1.2.0`, GitLab uses tag v1.1.0. The tag `v1.0.0-pre1` is
never used, because pre-release tags are ignored.
The `version` attribute can start with `v`. For example: `v1.0.0`.
The response is the same as for `version` value `1.0.0`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/437616) in GitLab 16.9.
If `from` is unspecified and no tag to use is found, the API produces an error.
To solve such an error, you must explicitly specify a value for the `from`
attribute.

View File

@ -0,0 +1,77 @@
---
stage: Create
group: Source Code
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# GitGuardian
DETAILS:
**Tier:** Premium, Ultimate
**Offering:** SaaS, self-managed
**Status:** Beta
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/435706) in GitLab 16.9 [with a flag](../../../administration/feature_flags.md) named `git_guardian_integration`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `git_guardian_integration`.
On GitLab.com, this feature is not available.
This feature is not ready for production use.
[GitGuardian](https://www.gitguardian.com/) is a cybersecurity service that detects sensitive data such as API keys
and passwords in source code repositories.
It scans Git repositories, alerts on policy violations, and helps organizations
fix security issues before hackers can exploit them.
You can configure GitLab to reject commits based on GitGuardian policies.
This feature is in [Beta](../../../policy/experiment-beta-support.md#beta) and subject to change without notice.
To set up the GitGuardian integration:
1. [Create a GitGuardian API token](#create-a-gitguardian-api-token).
1. [Set up the GitGuardian integration for your project](#set-up-the-gitguardian-integration-for-your-project).
## Create a GitGuardian API token
Prerequisites:
- You must have a GitGuardian account.
To create an API token:
1. Sign in to your GitGuardian account.
1. Go to the **API** section in the sidebar.
1. In the API section sidebar go to **Personal access tokens** page.
1. Select **Create token**. The token creation dialog opens.
1. Provide your token information:
- Give your API token a meaningful name to identify its purpose.
For example, `GitLab integration token`.
- Select an appropriate expiration.
- Select the **scan scope** checkbox.
It is the only one needed for the integration.
1. Select **Create token**.
1. After you've generated a token, copy it to your clipboard.
This token is sensitive information, so keep it secure.
Now you have successfully created a GitGuardian API token that you can use to for our integration.
## Set up the GitGuardian integration for your project
Prerequisites:
- You must have at least the Maintainer role for the project.
After you have created and copied your API token, configure GitLab to reject commits:
To enable the integration for your project:
1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Settings > Integrations**.
1. Select **GitGuardian**.
1. In **Enable integration**, select the **Active** checkbox.
1. In **API token**, [paste the token value from GitGuardian](#create-a-gitguardian-api-token).
1. Optional. Select **Test settings**.
1. Select **Save changes**.
GitLab is now ready to reject commits based on GitGuardian policies.

View File

@ -132,6 +132,7 @@ To use custom settings for a project or group integration:
| [Emails on push](emails_on_push.md) | Send commits and diffs on push by email. | **{dotted-circle}** No |
| [Engineering Workflow Management (EWM)](ewm.md) | Use EWM as an issue tracker. | **{dotted-circle}** No |
| [External wiki](../wiki/index.md#link-an-external-wiki) | Link an external wiki. | **{dotted-circle}** No |
| [GitGuardian](git_guardian.md) | Reject commits based on GitGuardian policies. | **{dotted-circle}** No |
| [GitHub](github.md) | Receive statuses for commits and pull requests. | **{dotted-circle}** No |
| [GitLab for Slack app](gitlab_slack_application.md) | Use the native Slack app to receive notifications and run commands. | **{dotted-circle}** No |
| [Google Chat](hangouts_chat.md) | Send notifications from your GitLab project to a room in Google Chat. | **{dotted-circle}** No |

View File

@ -126,6 +126,12 @@ rewrite the URL.
## Domain-level redirects
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-pages/-/merge_requests/936) in GitLab 16.8 [with a flag](../../../administration/feature_flags.md) named `FF_ENABLE_DOMAIN_REDIRECT`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-com/gl-infra/k8s-workloads/gitlab-com/-/merge_requests/3395) in GitLab 16.9.
NOTE:
On self-managed GitLab, by default this feature is not available.
To make it available, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `FF_ENABLE_DOMAIN_REDIRECT`.
On GitLab.com, this feature is available.
To create a domain-level redirect, add a domain-level path (beginning with `http://`
or `https://`) to either:

View File

@ -28,6 +28,22 @@ The name and email information provided are retrieved from the
[Git configuration](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration)
of the contributor when a commit is made.
## Limit history range
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/423108) in GitLab 16.9.
In these cases you can constrain the search period by adding `committed_before` and `committed_after` dates as parameters.
To do this, add `&` and `committed_before=YYYY-MM-DD` or `committed_after=YYYY-MM-DD` parameters to the URL.
For example:
```plaintext
https://gitlab.com/gitlab-org/gitlab/-/commits/master/README.md?ref_type=heads&committed_before=2010-11-22&committed_after=2008-05-15
```
Doing this might be necessary to fix [commit history requests timeouts](https://gitlab.com/gitlab-org/gitaly/-/issues/5426)
in very large repositories.
## Associated `git` command
If you're running `git` from the command line, the equivalent command

View File

@ -20,7 +20,7 @@ module Gitlab
end
def get_connected_agents_by_agent_ids(agent_ids:)
request = Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIdsRequest.new(agent_ids: agent_ids)
request = Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIDsRequest.new(agent_ids: agent_ids)
stub_for(:agent_tracker)
.get_connected_agents_by_agent_ids(request, metadata: metadata)

View File

@ -49029,6 +49029,9 @@ msgstr ""
msgid "Target branch: %{target_branch}"
msgstr ""
msgid "Target project cannot be equal to source project"
msgstr ""
msgid "Target roles"
msgstr ""

View File

@ -40,6 +40,8 @@ module Gitlab
# https://ruby.social/@getajobmike/109326475545816363
@max_concurrency = 20
@min_concurrency = 0
# TODO: to be set to 20 once max_concurrency and min_concurrency is removed https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/2760
@concurrency = 0
@environment = ENV['RAILS_ENV'] || 'development'
@metrics_dir = ENV["prometheus_multiproc_dir"] || File.absolute_path("tmp/prometheus_multiproc_dir/sidekiq")
@pid = nil
@ -143,6 +145,7 @@ module Gitlab
directory: @rails_path,
max_concurrency: @max_concurrency,
min_concurrency: @min_concurrency,
concurrency: @concurrency,
dryrun: @dryrun,
timeout: @soft_timeout_seconds
)
@ -220,6 +223,10 @@ module Gitlab
abort opt.to_s
end
opt.on('-c', '--concurrency INT', 'Number of threads to use with Sidekiq (default: 0)') do |int|
@concurrency = int.to_i
end
opt.on('-m', '--max-concurrency INT', 'Maximum threads to use with Sidekiq (default: 20, 0 to disable)') do |int|
@max_concurrency = int.to_i
end

View File

@ -36,12 +36,13 @@ module Gitlab
#
# Returns an Array containing the waiter threads (from Process.detach) of
# the started processes.
def self.start(queues, env: :development, directory: Dir.pwd, max_concurrency: 20, min_concurrency: 0, timeout: DEFAULT_SOFT_TIMEOUT_SECONDS, dryrun: false)
def self.start(queues, env: :development, directory: Dir.pwd, max_concurrency: 20, min_concurrency: 0, concurrency: 0, timeout: DEFAULT_SOFT_TIMEOUT_SECONDS, dryrun: false)
queues.map.with_index do |pair, index|
start_sidekiq(pair, env: env,
directory: directory,
max_concurrency: max_concurrency,
min_concurrency: min_concurrency,
concurrency: concurrency,
worker_id: index,
timeout: timeout,
dryrun: dryrun)
@ -51,11 +52,13 @@ module Gitlab
# Starts a Sidekiq process that processes _only_ the given queues.
#
# Returns the PID of the started process.
def self.start_sidekiq(queues, env:, directory:, max_concurrency:, min_concurrency:, worker_id:, timeout:, dryrun:)
# rubocop: disable Metrics/ParameterLists -- max_concurrency and min_concurrency will be removed in 17.0
def self.start_sidekiq(queues, env:, directory:, max_concurrency:, min_concurrency:, concurrency:, worker_id:, timeout:, dryrun:)
# rubocop: enable Metrics/ParameterLists
counts = count_by_queue(queues)
cmd = %w[bundle exec sidekiq]
cmd << "-c#{self.concurrency(queues, min_concurrency, max_concurrency)}"
cmd << "-c#{self.concurrency(queues, min_concurrency, max_concurrency, concurrency)}"
cmd << "-e#{env}"
cmd << "-t#{timeout}"
cmd << "-gqueues:#{proc_details(counts)}"
@ -101,7 +104,9 @@ module Gitlab
end.join(',')
end
def self.concurrency(queues, min_concurrency, max_concurrency)
def self.concurrency(queues, min_concurrency, max_concurrency, concurrency)
return concurrency if concurrency > 0
concurrency_from_queues = queues.length + 1
max = max_concurrency > 0 ? max_concurrency : concurrency_from_queues
min = [min_concurrency, max].min

View File

@ -12,7 +12,7 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, feature_category: :gitlab_cli, stub_
let(:cli) { described_class.new('/dev/null') }
let(:timeout) { Gitlab::SidekiqCluster::DEFAULT_SOFT_TIMEOUT_SECONDS }
let(:default_options) do
{ env: 'test', directory: Dir.pwd, max_concurrency: 20, min_concurrency: 0, dryrun: false, timeout: timeout }
{ env: 'test', directory: Dir.pwd, max_concurrency: 20, min_concurrency: 0, dryrun: false, timeout: timeout, concurrency: 0 }
end
let(:sidekiq_exporter_enabled) { false }
@ -125,6 +125,18 @@ RSpec.describe Gitlab::SidekiqCluster::CLI, feature_category: :gitlab_cli, stub_
end
end
context 'with --concurrency flag' do
it 'starts Sidekiq workers for specified queues with the fixed concurrency' do
expected_queues = [%w[foo bar baz], %w[solo]].each { |queues| queues.concat(described_class::DEFAULT_QUEUES) }
expect(Gitlab::SidekiqConfig::CliMethods).to receive(:worker_queues).and_return(%w[foo bar baz])
expect(Gitlab::SidekiqCluster).to receive(:start)
.with(expected_queues, default_options.merge(concurrency: 2))
.and_return([])
cli.run(%w[foo,bar,baz solo -c 2])
end
end
context 'with --timeout flag' do
it 'when given', 'starts Sidekiq workers with given timeout' do
expect(Gitlab::SidekiqCluster).to receive(:start)

View File

@ -102,6 +102,77 @@ RSpec.describe Projects::CommitsController, feature_category: :source_code_manag
end
end
context 'date range' do
let(:id) { "master/README.md" }
let(:base_repository_params) do
{
path: "README.md",
limit: described_class::COMMITS_DEFAULT_LIMIT,
offset: 0
}
end
let(:base_request_params) do
{
namespace_id: project.namespace,
project_id: project,
id: id
}
end
shared_examples 'repository commits call' do
it 'passes the correct params' do
expect_any_instance_of(Repository).to receive(:commits).with(
"master",
repository_params
).and_call_original
get :show, params: request_params
expect(response).to be_successful
end
end
context 'when committed_before param' do
context 'is valid' do
let(:request_params) { base_request_params.merge(committed_before: '2020-01-01') }
let(:repository_params) { base_repository_params.merge(before: 1577836800) }
it_behaves_like 'repository commits call'
end
context 'is invalid' do
let(:request_params) { base_request_params.merge(committed_before: 'xxx') }
let(:repository_params) { base_repository_params }
it_behaves_like 'repository commits call'
end
context 'is not provided' do
let(:request_params) { base_request_params }
let(:repository_params) { base_repository_params }
it_behaves_like 'repository commits call'
end
end
context 'with committed_after param' do
context 'is valid' do
let(:request_params) { base_request_params.merge(committed_after: '2020-01-01') }
let(:repository_params) { base_repository_params.merge(after: 1577836800) }
it_behaves_like 'repository commits call'
end
context 'is invalid' do
let(:request_params) { base_request_params.merge(committed_after: 'xxx') }
let(:repository_params) { base_repository_params }
it_behaves_like 'repository commits call'
end
end
end
it 'loads tags for commits' do
expect_next_instance_of(CommitCollection) do |collection|
expect(collection).to receive(:load_tags)

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Repositories::ChangelogTagFinder do
RSpec.describe Repositories::ChangelogTagFinder, feature_category: :source_code_management do
let(:project) { build_stubbed(:project) }
let(:finder) { described_class.new(project) }
@ -35,6 +35,10 @@ RSpec.describe Repositories::ChangelogTagFinder do
expect(finder.execute('1.0.0')).to eq(tag4)
expect(finder.execute('0.9.0')).to eq(tag6)
expect(finder.execute('0.6.0')).to eq(tag7)
# with v at the beginning
expect(finder.execute('v2.1.0')).to eq(tag3)
expect(finder.execute('wrong_version')).to eq(nil)
end
end

View File

@ -28,7 +28,7 @@ describe('BoardApp', () => {
mockApollo.clients.defaultClient.cache.writeQuery({
query: activeBoardItemQuery,
data: {
activeBoardItem: issue,
activeBoardItem: { ...issue, listId: 'gid://gitlab/List/1' },
},
});

View File

@ -50,7 +50,7 @@ describe('Board card', () => {
mockApollo.clients.defaultClient.cache.writeQuery({
query: activeBoardItemQuery,
data: {
activeBoardItem,
activeBoardItem: { ...activeBoardItem, listId: 'gid://gitlab/List/1' },
},
});
@ -113,7 +113,7 @@ describe('Board card', () => {
});
it('should highlight the card with a correct style when selected', async () => {
mountComponent({ activeBoardItem: mockIssue });
mountComponent({ activeBoardItem: { ...mockIssue, listId: 'gid://gitlab/List/1' } });
await waitForPromises();
expect(wrapper.classes()).toContain('is-active');
@ -141,6 +141,7 @@ describe('Board card', () => {
{},
{
boardItem: mockIssue,
listId: 'gid://gitlab/List/2',
},
expect.anything(),
expect.anything(),

View File

@ -34,7 +34,7 @@ describe('BoardContentSidebar', () => {
mockApollo.clients.defaultClient.cache.writeQuery({
query: activeBoardItemQuery,
data: {
activeBoardItem: issuable,
activeBoardItem: { ...issuable, listId: 'gid://gitlab/List/1' },
},
});
@ -142,6 +142,7 @@ describe('BoardContentSidebar', () => {
{},
{
boardItem: null,
listId: null,
},
expect.anything(),
expect.anything(),

View File

@ -47,8 +47,8 @@ RSpec.describe Gitlab::Kas::Client do
describe '#get_connected_agents_by_agent_ids' do
let(:stub) { instance_double(Gitlab::Agent::AgentTracker::Rpc::AgentTracker::Stub) }
let(:request) { instance_double(Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIdsRequest) }
let(:response) { double(Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIdsResponse, agents: connected_agents) }
let(:request) { instance_double(Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIDsRequest) }
let(:response) { double(Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIDsResponse, agents: connected_agents) }
let(:connected_agents) { [double] }
@ -59,7 +59,7 @@ RSpec.describe Gitlab::Kas::Client do
.with('example.kas.internal', :this_channel_is_insecure, timeout: described_class::TIMEOUT)
.and_return(stub)
expect(Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIdsRequest).to receive(:new)
expect(Gitlab::Agent::AgentTracker::Rpc::GetConnectedAgentsByAgentIDsRequest).to receive(:new)
.with(agent_ids: [agent.id])
.and_return(request)

View File

@ -3533,6 +3533,15 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
expect(project_fork_target).not_to be_forked
end
end
context 'when fork target and source are the same' do
it 'returns an error' do
post api("/projects/#{project_fork_target.id}/fork/#{project_fork_target.id}", admin, admin_mode: true)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq 'Target project cannot be equal to source project'
end
end
end
end

View File

@ -54,6 +54,17 @@ RSpec.describe CodequalityDegradationEntity, feature_category: :code_quality do
expect(subject[:engine_name]).to eq('rubocop')
end
end
context 'when severity is a non-codeclimate-standard severity' do
# See standard severities: https://docs.codeclimate.com/docs/issues#issue-severity
let(:codequality_degradation) { build(:codequality_degradation_3) }
it 'returns severity as unknown', :aggregate_failures do
codequality_degradation[:severity] = 'warning'
expect(subject[:severity]).to eq('unknown')
end
end
end
end
end

View File

@ -6,6 +6,7 @@ RSpec.describe Ci::ExpirePipelineCacheService, feature_category: :continuous_int
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:merge_pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline, project: project) }
subject { described_class.new }
@ -45,6 +46,17 @@ RSpec.describe Ci::ExpirePipelineCacheService, feature_category: :continuous_int
subject.execute(merge_request.all_pipelines.last)
end
it 'invalidates Etag caching for merge request that pipeline runs on its merged commit' do
merge_request = create(:merge_request, merge_commit_sha: pipeline.sha, source_project: pipeline.project)
project = merge_request.target_project
merge_request_widget_path = "/#{project.full_path}/-/merge_requests/#{merge_request.iid}/cached_widget.json"
expect_touched_etag_caching_paths(merge_request_widget_path)
subject.execute(pipeline)
end
it 'updates the cached status for a project' do
expect(Gitlab::Cache::Ci::ProjectPipelineStatus).to receive(:update_for_pipeline).with(pipeline)

View File

@ -42,7 +42,8 @@ RSpec.describe Gitlab::SidekiqCluster do # rubocop:disable RSpec/FilePath
min_concurrency: 0,
worker_id: an_instance_of(Integer),
timeout: 25,
dryrun: false
dryrun: false,
concurrency: 0
}
expect(described_class).to receive(:start_sidekiq).ordered.with(%w[foo bar baz], expected_options)
@ -55,7 +56,7 @@ RSpec.describe Gitlab::SidekiqCluster do # rubocop:disable RSpec/FilePath
describe '.start_sidekiq' do
let(:first_worker_id) { 0 }
let(:options) do
{ env: :production, directory: 'foo/bar', max_concurrency: 20, min_concurrency: 0, worker_id: first_worker_id, timeout: 10, dryrun: false }
{ env: :production, directory: 'foo/bar', max_concurrency: 20, min_concurrency: 0, worker_id: first_worker_id, timeout: 10, dryrun: false, concurrency: 0 }
end
let(:env) { { "ENABLE_SIDEKIQ_CLUSTER" => "1", "SIDEKIQ_WORKER_ID" => first_worker_id.to_s } }
@ -102,21 +103,28 @@ RSpec.describe Gitlab::SidekiqCluster do # rubocop:disable RSpec/FilePath
describe '.concurrency' do
using RSpec::Parameterized::TableSyntax
where(:queue_count, :min, :max, :expected) do
2 | 0 | 0 | 3 # No min or max specified
2 | 0 | 9 | 3 # No min specified, value < max
2 | 1 | 4 | 3 # Value between min and max
2 | 4 | 5 | 4 # Value below range
5 | 2 | 3 | 3 # Value above range
2 | 1 | 1 | 1 # Value above explicit setting (min == max)
0 | 3 | 3 | 3 # Value below explicit setting (min == max)
1 | 4 | 3 | 3 # Min greater than max
where(:queue_count, :min, :max, :fixed_concurrency, :expected) do
# without fixed concurrency
2 | 0 | 0 | 0 | 3 # No min or max specified
2 | 0 | 9 | 0 | 3 # No min specified, value < max
2 | 1 | 4 | 0 | 3 # Value between min and max
2 | 4 | 5 | 0 | 4 # Value below range
5 | 2 | 3 | 0 | 3 # Value above range
2 | 1 | 1 | 0 | 1 # Value above explicit setting (min == max)
0 | 3 | 3 | 0 | 3 # Value below explicit setting (min == max)
1 | 4 | 3 | 0 | 3 # Min greater than max
# with fixed concurrency, expected always equal to fixed_concurrency
1 | 0 | 20 | 20 | 20
1 | 0 | 20 | 10 | 10
1 | 20 | 20 | 10 | 10
5 | 0 | 0 | 10 | 10
end
with_them do
let(:queues) { Array.new(queue_count) }
it { expect(described_class.concurrency(queues, min, max)).to eq(expected) }
it { expect(described_class.concurrency(queues, min, max, fixed_concurrency)).to eq(expected) }
end
end
end

View File

@ -6,7 +6,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1
github.com/BurntSushi/toml v1.3.2
github.com/alecthomas/chroma/v2 v2.12.0
github.com/aws/aws-sdk-go v1.49.3
github.com/aws/aws-sdk-go v1.50.7
github.com/disintegration/imaging v1.6.2
github.com/getsentry/raven-go v0.2.0
github.com/golang-jwt/jwt/v5 v5.2.0

View File

@ -94,8 +94,8 @@ github.com/alecthomas/chroma/v2 v2.12.0/go.mod h1:4TQu7gdfuPjSh76j78ietmqh9LiurG
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.49.3 h1:+UGwhC3kChk0pRCxSsbaQSNIc8MfFURQL44Ig6RRR3I=
github.com/aws/aws-sdk-go v1.49.3/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.50.7 h1:odKb+uneeGgF2jgAerKjFzpljiyZxleV4SHB7oBK+YA=
github.com/aws/aws-sdk-go v1.50.7/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o=