Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-11-02 21:09:03 +00:00
parent 983f6954d1
commit 03cd2a56f3
58 changed files with 897 additions and 344 deletions

View file

@ -171,7 +171,7 @@ graphql-schema-dump:
graphql-schema-dump as-if-foss:
extends:
- graphql-schema-dump
- .frontend:rules:eslint-as-if-foss
- .frontend:rules:default-frontend-jobs-as-if-foss
- .as-if-foss
.frontend-test-base:

View file

@ -46,7 +46,7 @@
files:
- GITALY_SERVER_VERSION
- lib/gitlab/setup_helper.rb
prefix: "gitaly-binaries-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}"
prefix: "gitaly-binaries-${GITALY_SERVER_VERSION}-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}"
paths:
- ${TMP_TEST_FOLDER}/gitaly/_build/bin/
- ${TMP_TEST_FOLDER}/gitaly/_build/deps/git/install/

View file

@ -9,6 +9,10 @@
"CiManualVariable",
"CiProjectVariable"
],
"CommitSignature": [
"GpgSignature",
"X509Signature"
],
"CurrentUserTodos": [
"BoardEpic",
"Design",

View file

@ -86,6 +86,7 @@ export default {
:target="openInNewTab ? '_blank' : '_self'"
:href="value.url"
data-testid="uncompleted-learn-gitlab-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-track-action="click_link"
:data-track-label="actionLabelValue('trackLabel')"
>{{ actionLabelValue('title') }}</gl-link

View file

@ -41,6 +41,8 @@ export default {
featureFlagsHelpText: s__(
'ProjectSettings|Roll out new features without redeploying with feature flags.',
),
infrastructureLabel: s__('ProjectSettings|Infrastructure'),
infrastructureHelpText: s__('ProjectSettings|Configure your infrastructure.'),
monitorLabel: s__('ProjectSettings|Monitor'),
packagesHelpText: s__(
'ProjectSettings|Every project can have its own space to store its packages. Note: The Package Registry is always visible when a project is public.',
@ -157,6 +159,11 @@ export default {
required: false,
default: '',
},
infrastructureHelpPath: {
type: String,
required: false,
default: '',
},
releasesHelpPath: {
type: String,
required: false,
@ -245,6 +252,7 @@ export default {
operationsAccessLevel: featureAccessLevel.EVERYONE,
environmentsAccessLevel: featureAccessLevel.EVERYONE,
featureFlagsAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
infrastructureAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
releasesAccessLevel: featureAccessLevel.EVERYONE,
monitorAccessLevel: featureAccessLevel.EVERYONE,
containerRegistryAccessLevel: featureAccessLevel.EVERYONE,
@ -433,6 +441,10 @@ export default {
featureAccessLevel.PROJECT_MEMBERS,
this.featureFlagsAccessLevel,
);
this.infrastructureAccessLevel = Math.min(
featureAccessLevel.PROJECT_MEMBERS,
this.infrastructureAccessLevel,
);
this.releasesAccessLevel = Math.min(
featureAccessLevel.PROJECT_MEMBERS,
this.releasesAccessLevel,
@ -981,6 +993,19 @@ export default {
name="project[project_feature_attributes][feature_flags_access_level]"
/>
</project-setting-row>
<project-setting-row
ref="infrastructure-settings"
:label="$options.i18n.infrastructureLabel"
:help-text="$options.i18n.infrastructureHelpText"
:help-path="infrastructureHelpPath"
>
<project-feature-setting
v-model="infrastructureAccessLevel"
:label="$options.i18n.infrastructureLabel"
:options="featureAccessLevelOptions"
name="project[project_feature_attributes][infrastructure_access_level]"
/>
</project-setting-row>
</template>
<project-setting-row
ref="releases-settings"

View file

@ -55,6 +55,7 @@ export default {
class="js-sidebar-dropdown-toggle edit-link btn gl-text-gray-900! gl-ml-auto hide-collapsed btn-default btn-sm gl-button btn-default-tertiary float-right"
href="#"
data-test-id="edit-link"
data-qa-selector="edit_link"
data-track-action="click_edit_button"
data-track-label="right_sidebar"
data-track-property="assignee"

View file

@ -56,6 +56,7 @@ export default {
type="button"
class="gl-button btn-link gl-reset-color!"
data-testid="assign-yourself"
data-qa-selector="assign_yourself_button"
@click="assignSelf"
>
{{ __('assign yourself') }}

View file

@ -91,6 +91,7 @@ export default {
<div
class="gl-ml-3 gl-line-height-normal gl-display-grid gl-align-items-center"
data-testid="username"
data-qa-selector="username"
>
<user-name-with-status :name="user.name" :availability="userAvailability(user)" />
</div>

View file

@ -0,0 +1,37 @@
# frozen_string_literal: true
module Types
module CommitSignatureInterface
include Types::BaseInterface
graphql_name 'CommitSignature'
description 'Represents signing information for a commit'
field :verification_status, CommitSignatures::VerificationStatusEnum,
null: true,
description: 'Indicates verification status of the associated key or certificate.'
field :commit_sha, GraphQL::Types::String,
null: true,
description: 'SHA of the associated commit.'
field :project, Types::ProjectType,
null: true,
description: 'Project of the associated commit.'
orphan_types Types::CommitSignatures::GpgSignatureType,
Types::CommitSignatures::X509SignatureType
def self.resolve_type(object, context)
case object
when ::CommitSignatures::GpgSignature
Types::CommitSignatures::GpgSignatureType
when ::CommitSignatures::X509CommitSignature
Types::CommitSignatures::X509SignatureType
else
raise 'Unsupported commit signature type'
end
end
end
end

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
module Types
module CommitSignatures
class GpgSignatureType < Types::BaseObject
graphql_name 'GpgSignature'
description 'GPG signature for a signed commit'
implements Types::CommitSignatureInterface
authorize :download_code
field :user, Types::UserType, null: true,
description: 'User associated with the key.'
field :gpg_key_user_name, GraphQL::Types::String,
null: true,
description: 'User name associated with the GPG key.'
field :gpg_key_user_email, GraphQL::Types::String,
null: true,
description: 'User email associated with the GPG key.'
field :gpg_key_primary_keyid, GraphQL::Types::String,
null: true,
description: 'ID of the GPG key.'
end
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
module CommitSignatures
class VerificationStatusEnum < BaseEnum
graphql_name 'VerificationStatus'
description 'Verification status of a GPG or X.509 signature for a commit.'
::CommitSignatures::GpgSignature.verification_statuses.each do |status, _|
value status.upcase, value: status, description: "#{status} verification status."
end
end
end
end
# rubocop:enable Graphql/AuthorizeTypes

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
module Types
module CommitSignatures
class X509SignatureType < Types::BaseObject
graphql_name 'X509Signature'
description 'X.509 signature for a signed commit'
implements Types::CommitSignatureInterface
authorize :download_code
field :user, Types::UserType, null: true,
calls_gitaly: true,
description: 'User associated with the key.'
field :x509_certificate, Types::X509CertificateType,
null: true,
description: 'Certificate used for the signature.'
end
end
end

View file

@ -40,6 +40,11 @@ module Types
field :web_path, type: GraphQL::Types::String, null: false,
description: 'Web path of the commit.'
field :signature, type: Types::CommitSignatureInterface,
null: true,
calls_gitaly: true,
description: 'Signature of the commit.'
field :signature_html, type: GraphQL::Types::String, null: true, calls_gitaly: true,
description: 'Rendered HTML of the commit signature.'

View file

@ -0,0 +1,39 @@
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
class X509CertificateType < Types::BaseObject
graphql_name 'X509Certificate'
description 'Represents an X.509 certificate.'
field :certificate_status, GraphQL::Types::String,
null: false,
description: 'Indicates if the certificate is good or revoked.'
field :created_at, Types::TimeType, null: false,
description: 'Timestamp of when the certificate was saved.'
field :email, GraphQL::Types::String, null: false,
description: 'Email associated with the cerificate.'
field :id, GraphQL::Types::ID, null: false, description: 'ID of the certificate.'
field :serial_number, GraphQL::Types::String, null: false,
description: 'Serial number of the certificate.'
field :subject, GraphQL::Types::String, null: false, description: 'Subject of the certificate.'
field :subject_key_identifier, GraphQL::Types::String,
null: false,
description: 'Subject key identifier of the certificate.'
field :updated_at, Types::TimeType, null: false,
description: 'Timestamp of when the certificate was last updated.'
field :x509_issuer, Types::X509IssuerType, null: false,
description: 'Issuer of the certificate.'
end
end
# rubocop:enable Graphql/AuthorizeTypes

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
class X509IssuerType < Types::BaseObject
graphql_name 'X509Issuer'
description 'Issuer of an X.509 certificate.'
field :created_at, Types::TimeType, null: true,
description: 'Timestamp of when the issuer was created.'
field :crl_url, GraphQL::Types::String, null: true,
description: 'Certificate revokation list of the issuer.'
field :id, GraphQL::Types::ID, null: true, description: 'ID of the issuer.'
field :subject, GraphQL::Types::String, null: true, description: 'Subject of the issuer.'
field :subject_key_identifier, GraphQL::Types::String,
null: true,
description: 'Subject key identifier of the issuer.'
field :updated_at, Types::TimeType, null: true,
description: 'Timestamp of when the issuer was last updated.'
end
end
# rubocop:enable Graphql/AuthorizeTypes

View file

@ -395,7 +395,8 @@ module ProjectsHelper
membersPagePath: project_project_members_path(project),
environmentsHelpPath: help_page_path('ci/environments/index'),
featureFlagsHelpPath: help_page_path('operations/feature_flags'),
releasesHelpPath: help_page_path('user/project/releases/index')
releasesHelpPath: help_page_path('user/project/releases/index'),
infrastructureHelpPath: help_page_path('user/infrastructure/index')
}
end
@ -664,7 +665,8 @@ module ProjectsHelper
containerRegistryAccessLevel: feature.container_registry_access_level,
environmentsAccessLevel: feature.environments_access_level,
featureFlagsAccessLevel: feature.feature_flags_access_level,
releasesAccessLevel: feature.releases_access_level
releasesAccessLevel: feature.releases_access_level,
infrastructureAccessLevel: feature.infrastructure_access_level
}
end

View file

@ -49,5 +49,9 @@ module CommitSignatures
Gitlab::Gpg::Commit.new(commit)
end
def user
gpg_key&.user
end
end
end

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
module CommitSignatures
class GpgSignaturePolicy < BasePolicy
delegate { @subject.project }
end
end

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
module CommitSignatures
class X509CommitSignaturePolicy < BasePolicy
delegate { @subject.project }
end
end

View file

@ -12,8 +12,8 @@ module ObjectStorage
UrlResult = Struct.new(:url, :used_cdn)
def cdn_enabled_url(project, ip_address)
if Feature.enabled?(:ci_job_artifacts_cdn, project) && use_cdn?(ip_address)
def cdn_enabled_url(ip_address)
if use_cdn?(ip_address)
UrlResult.new(cdn_signed_url, true)
else
UrlResult.new(url, false)

View file

@ -1,8 +0,0 @@
---
name: ci_job_artifacts_cdn
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98010
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373860
milestone: '15.5'
type: development
group: group::pipeline execution
default_enabled: false

View file

@ -48,9 +48,9 @@ settings and automation to ensure that whatever a compliance team has configured
stays configured and working correctly. These features can help you automate
compliance:
- [**Compliance frameworks**](../user/group/manage.md#compliance-frameworks) (for groups): Create a custom
- [**Compliance frameworks**](../user/group/compliance_frameworks.md) (for groups): Create a custom
compliance framework at the group level to describe the type of compliance requirements any child project needs to follow.
- [**Compliance pipelines**](../user/group/manage.md#configure-a-compliance-pipeline) (for groups): Define a
- [**Compliance pipelines**](../user/group/compliance_frameworks.md#configure-a-compliance-pipeline) (for groups): Define a
pipeline configuration to run for any projects with a given compliance framework.
## Audit management

View file

@ -10939,6 +10939,7 @@ Represents a code quality degradation on the pipeline.
| <a id="commitmessage"></a>`message` | [`String`](#string) | Raw commit message. |
| <a id="commitsha"></a>`sha` | [`String!`](#string) | SHA1 ID of the commit. |
| <a id="commitshortid"></a>`shortId` | [`String!`](#string) | Short SHA1 ID of the commit. |
| <a id="commitsignature"></a>`signature` | [`CommitSignature`](#commitsignature) | Signature of the commit. |
| <a id="commitsignaturehtml"></a>`signatureHtml` | [`String`](#string) | Rendered HTML of the commit signature. |
| <a id="committitle"></a>`title` | [`String`](#string) | Title of the commit message. |
| <a id="committitlehtml"></a>`titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. |
@ -12799,6 +12800,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="geonodeuploadregistriesreplicationstate"></a>`replicationState` | [`ReplicationStateEnum`](#replicationstateenum) | Filters registries by their replication state. |
| <a id="geonodeuploadregistriesverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Filters registries by their verification state. |
### `GpgSignature`
GPG signature for a signed commit.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="gpgsignaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
| <a id="gpgsignaturegpgkeyprimarykeyid"></a>`gpgKeyPrimaryKeyid` | [`String`](#string) | ID of the GPG key. |
| <a id="gpgsignaturegpgkeyuseremail"></a>`gpgKeyUserEmail` | [`String`](#string) | User email associated with the GPG key. |
| <a id="gpgsignaturegpgkeyusername"></a>`gpgKeyUserName` | [`String`](#string) | User name associated with the GPG key. |
| <a id="gpgsignatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
| <a id="gpgsignatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. |
| <a id="gpgsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
### `GrafanaIntegration`
#### Fields
@ -20078,6 +20095,53 @@ Represents a weight widget.
| <a id="workitemwidgetweighttype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
| <a id="workitemwidgetweightweight"></a>`weight` | [`Int`](#int) | Weight of the work item. |
### `X509Certificate`
Represents an X.509 certificate.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="x509certificatecertificatestatus"></a>`certificateStatus` | [`String!`](#string) | Indicates if the certificate is good or revoked. |
| <a id="x509certificatecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the certificate was saved. |
| <a id="x509certificateemail"></a>`email` | [`String!`](#string) | Email associated with the cerificate. |
| <a id="x509certificateid"></a>`id` | [`ID!`](#id) | ID of the certificate. |
| <a id="x509certificateserialnumber"></a>`serialNumber` | [`String!`](#string) | Serial number of the certificate. |
| <a id="x509certificatesubject"></a>`subject` | [`String!`](#string) | Subject of the certificate. |
| <a id="x509certificatesubjectkeyidentifier"></a>`subjectKeyIdentifier` | [`String!`](#string) | Subject key identifier of the certificate. |
| <a id="x509certificateupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the certificate was last updated. |
| <a id="x509certificatex509issuer"></a>`x509Issuer` | [`X509Issuer!`](#x509issuer) | Issuer of the certificate. |
### `X509Issuer`
Issuer of an X.509 certificate.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="x509issuercreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of when the issuer was created. |
| <a id="x509issuercrlurl"></a>`crlUrl` | [`String`](#string) | Certificate revokation list of the issuer. |
| <a id="x509issuerid"></a>`id` | [`ID`](#id) | ID of the issuer. |
| <a id="x509issuersubject"></a>`subject` | [`String`](#string) | Subject of the issuer. |
| <a id="x509issuersubjectkeyidentifier"></a>`subjectKeyIdentifier` | [`String`](#string) | Subject key identifier of the issuer. |
| <a id="x509issuerupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp of when the issuer was last updated. |
### `X509Signature`
X.509 signature for a signed commit.
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="x509signaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
| <a id="x509signatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
| <a id="x509signatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. |
| <a id="x509signatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
| <a id="x509signaturex509certificate"></a>`x509Certificate` | [`X509Certificate`](#x509certificate) | Certificate used for the signature. |
## Enumeration types
Also called _Enums_, enumeration types are a special kind of scalar that
@ -21935,6 +21999,20 @@ Possible states of a user.
| <a id="verificationstateenumstarted"></a>`STARTED` | Verification process is in progress. |
| <a id="verificationstateenumsucceeded"></a>`SUCCEEDED` | Verification process finished successfully. |
### `VerificationStatus`
Verification status of a GPG or X.509 signature for a commit.
| Value | Description |
| ----- | ----------- |
| <a id="verificationstatusmultiple_signatures"></a>`MULTIPLE_SIGNATURES` | multiple_signatures verification status. |
| <a id="verificationstatusother_user"></a>`OTHER_USER` | other_user verification status. |
| <a id="verificationstatussame_user_different_email"></a>`SAME_USER_DIFFERENT_EMAIL` | same_user_different_email verification status. |
| <a id="verificationstatusunknown_key"></a>`UNKNOWN_KEY` | unknown_key verification status. |
| <a id="verificationstatusunverified"></a>`UNVERIFIED` | unverified verification status. |
| <a id="verificationstatusunverified_key"></a>`UNVERIFIED_KEY` | unverified_key verification status. |
| <a id="verificationstatusverified"></a>`VERIFIED` | verified verification status. |
### `VisibilityLevelsEnum`
| Value | Description |
@ -22903,6 +22981,23 @@ Implementations:
| <a id="civariablevalue"></a>`value` | [`String`](#string) | Value of the variable. |
| <a id="civariablevariabletype"></a>`variableType` | [`CiVariableType`](#civariabletype) | Type of the variable. |
#### `CommitSignature`
Represents signing information for a commit.
Implementations:
- [`GpgSignature`](#gpgsignature)
- [`X509Signature`](#x509signature)
##### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="commitsignaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
| <a id="commitsignatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
| <a id="commitsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
#### `CurrentUserTodos`
Implementations:

View file

@ -379,7 +379,7 @@ start. Jobs in the current stage are not stopped and continue to run.
- If a job does not specify a [`stage`](#stage), the job is assigned the `test` stage.
- If a stage is defined but no jobs use it, the stage is not visible in the pipeline,
which can help [compliance pipeline configurations](../../user/group/manage.md#configure-a-compliance-pipeline):
which can help [compliance pipeline configurations](../../user/group/compliance_frameworks.md#configure-a-compliance-pipeline):
- Stages can be defined in the compliance configuration but remain hidden if not used.
- The defined stages become visible when developers use them in job definitions.

View file

@ -244,7 +244,7 @@ To enable or disable the banner:
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/352316) from GitLab Premium to GitLab Ultimate in 15.0.
NOTE:
An alternative [compliance solution](../../group/manage.md#configure-a-compliance-pipeline)
An alternative [compliance solution](../../group/compliance_frameworks.md#configure-a-compliance-pipeline)
is available. We recommend this alternative solution because it provides greater flexibility,
allowing required pipelines to be assigned to specific compliance framework labels.

View file

@ -36,7 +36,7 @@ The following steps will help you get the most from GitLab application security
remediating existing vulnerabilities and preventing the introduction of new ones.
1. Enable other scan types such as [SAST](sast/index.md), [DAST](dast/index.md),
[Fuzz testing](coverage_fuzzing/index.md), or [Container Scanning](container_scanning/index.md).
1. Use [Compliance Pipelines](../group/manage.md#configure-a-compliance-pipeline)
1. Use [Compliance Pipelines](../group/compliance_frameworks.md#configure-a-compliance-pipeline)
or [Scan Execution Policies](policies/scan-execution-policies.md) to enforce required scan types
and ensure separation of duties between security and engineering.
1. Consider enabling [Review Apps](../../development/testing_guide/review_apps.md) to allow for DAST

View file

@ -487,7 +487,7 @@ Security and compliance teams must ensure that security scans:
GitLab provides two methods of accomplishing this, each with advantages and disadvantages.
- [Compliance framework pipelines](../group/manage.md#configure-a-compliance-pipeline)
- [Compliance framework pipelines](../group/compliance_frameworks.md#configure-a-compliance-pipeline)
are recommended when:
- Scan execution enforcement is required for any scanner that uses a GitLab template, such as SAST IaC, DAST, Dependency Scanning,

View file

@ -15,7 +15,7 @@ with a long, random job name. In the unlikely event of a job name collision, the
any pre-existing job in the pipeline. If a policy is created at the group-level, it will apply to every child
project or subgroup. A group-level policy cannot be edited from a child project or subgroup.
This feature has some overlap with [compliance framework pipelines](../../group/manage.md#configure-a-compliance-pipeline),
This feature has some overlap with [compliance framework pipelines](../../group/compliance_frameworks.md#configure-a-compliance-pipeline),
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
For details on the similarities and differences between these features, see
[Enforce scan execution](../index.md#enforce-scan-execution).

View file

@ -0,0 +1,262 @@
---
stage: Govern
group: Compliance
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Compliance frameworks **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
You can create a compliance framework that is a label to identify that your project has certain compliance
requirements or needs additional oversight. The label can optionally enforce
[compliance pipeline configuration](#configure-a-compliance-pipeline) to the projects on which it is
[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project).
Group owners can create, edit, and delete compliance frameworks:
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. Create, edit, or delete compliance frameworks.
## Set a default compliance framework
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375036) in GitLab 15.6.
Group owners can set a default compliance framework. The default framework is applied to all the new projects
that are created within that group. It does not affect the framework applied to the existing projects. The default
framework cannot be deleted.
### Example GraphQL mutations for setting a default compliance framework
Creating a new compliance framework and setting it as the default framework for the group.
```graphql
mutation {
createComplianceFramework(
input: {params: {name: "SOX", description: "Sarbanes-Oxley Act", color: "#87CEEB", default: true}, namespacePath: "gitlab-org"}
) {
framework {
id
name
default
description
color
pipelineConfigurationFullPath
}
errors
}
}
```
Setting an existing compliance framework as the default framework the group.
```graphql
mutation {
updateComplianceFramework(
input: {id: "gid://gitlab/ComplianceManagement::Framework/<id>", params: {default: true}}
) {
complianceFramework {
id
name
default
description
color
pipelineConfigurationFullPath
}
}
}
```
## Configure a compliance pipeline **(ULTIMATE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3156) in GitLab 13.9, disabled behind `ff_evaluate_group_level_compliance_pipeline` [feature flag](../../administration/feature_flags.md).
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Group owners can configure a compliance pipeline in a project separate to other projects. By default, the compliance
pipeline configuration (`.gitlab-ci.yml` file) is run instead of the pipeline configuration of labeled projects.
However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that:
- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of
pipeline configuration.
- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's
`.gitlab-ci.yml` file.
See [example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from
labeled project pipeline configuration.
To configure a compliance pipeline:
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. In **Compliance pipeline configuration (optional)**, add the path to the compliance framework configuration. Use the
`path/file.y[a]ml@group-name/project-name` format. For example:
- `.compliance-ci.yml@gitlab-org/gitlab`.
- `.compliance-ci.yaml@gitlab-org/gitlab`.
This configuration is inherited by projects where the compliance framework label is
[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration.
The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project.
When used to enforce scan execution, this feature has some overlap with
[scan execution policies](../application_security/policies/scan-execution-policies.md). We have not
[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on
the similarities and differences between these features, see [Enforce scan execution](../application_security/index.md#enforce-scan-execution).
### Example configuration
The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline
configuration is also executed.
```yaml
# Allows compliance team to control the ordering and interweaving of stages/jobs.
# Stages without jobs defined will remain hidden.
stages:
- pre-compliance
- build
- test
- pre-deploy-compliance
- deploy
- post-compliance
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
FOO: sast
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
variables:
FOO: sast
image: ruby:2.6
stage: pre-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
sanity check:
image: ruby:2.6
stage: pre-deploy-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
audit trail:
image: ruby:2.7
stage: post-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch
```
#### CF pipelines in Merge Requests originating in project forks
When an MR originates in a fork, the branch to be merged usually only exists in the fork.
When creating such an MR against a project with CF pipelines, the above snippet will fail with a
`Project <project-name> reference <branch-name> does not exist!` error message.
This is because in the context of the target project, `$CI_COMMIT_REF_NAME` evaluates to a non-existing branch name.
To get the correct context, use `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` instead of `$CI_PROJECT_PATH`.
This variable is only availabe in
[merge request pipelines](../../ci/pipelines/merge_request_pipelines.md).
For example, for a configuration that supports both merge request pipelines originating in project forks and branch pipelines,
you need to [combine both `include` directives with `rules:if`](../../ci/yaml/includes.md#use-rules-with-include):
```yaml
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
- project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME'
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME'
rules:
- if: $CI_PIPELINE_SOURCE != 'merge_request_event'
```
## Ensure compliance jobs are always run
Compliance pipelines [use GitLab CI/CD](../../ci/index.md) to give you an incredible amount of flexibility
for defining any sort of compliance jobs you like. Depending on your goals, these jobs
can be configured to be:
- Modified by users.
- Non-modifiable.
Generally, if a value in a compliance job:
- Is set, it cannot be changed or overridden by project-level configurations.
- Is not set, a project-level configuration may set.
Either might be wanted or not depending on your use case.
There are a few best practices for ensuring that these jobs are always run exactly
as you define them and that downstream, project-level pipeline configurations
cannot change them:
- Add [a `rules:when:always` block](../../ci/yaml/index.md#when) to each of your compliance jobs. This ensures they are
non-modifiable and are always run.
- Explicitly set any [variables](../../ci/yaml/index.md#variables) the job references. This:
- Ensures that project-level pipeline configurations do not set them and alter their
behavior.
- Includes any jobs that drive the logic of your job.
- Explicitly set the [container image](../../ci/yaml/index.md#image) to run the job in. This ensures that your script
steps execute in the correct environment.
- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/index.md#job-keywords).
This ensures that your job uses the settings you intend and that they are not overridden by
project-level pipelines.
## Avoid parent and child pipelines in GitLab 14.7 and earlier
NOTE:
This advice does not apply to GitLab 14.8 and later because [a fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78878) added
compatibility for combining compliance pipelines, and parent and child pipelines.
Compliance pipelines start on the run of _every_ pipeline in a labeled project. This means that if a pipeline in the labeled project
triggers a child pipeline, the compliance pipeline runs first. This can trigger the parent pipeline, instead of the child pipeline.
Therefore, in projects with compliance frameworks, we recommend replacing
[parent-child pipelines](../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines) with the following:
- Direct [`include`](../../ci/yaml/index.md#include) statements that provide the parent pipeline with child pipeline configuration.
- Child pipelines placed in another project that are run using the [trigger API](../../ci/triggers/index.md) rather than the parent-child
pipeline feature.
This alternative ensures the compliance pipeline does not re-start the parent pipeline.

View file

@ -397,263 +397,6 @@ To enable delayed deletion of projects in a group:
NOTE:
In GitLab 13.11 and above the group setting for delayed project deletion is inherited by subgroups. As discussed in [Cascading settings](../../development/cascading_settings.md) inheritance can be overridden, unless enforced by an ancestor.
## Compliance frameworks **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
You can create a compliance framework that is a label to identify that your project has certain compliance
requirements or needs additional oversight. The label can optionally enforce
[compliance pipeline configuration](#configure-a-compliance-pipeline) to the projects on which it is
[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project).
Group owners can create, edit, and delete compliance frameworks:
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. Create, edit, or delete compliance frameworks.
### Set a default compliance framework
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375036) in GitLab 15.6.
Group owners can set a default compliance framework. The default framework is applied to all the new projects
that are created within that group. It does not affect the framework applied to the existing projects. The default
framework cannot be deleted.
#### Example GraphQL mutations for setting a default compliance framework
Creating a new compliance framework and setting it as the default framework for the group.
```graphql
mutation {
createComplianceFramework(
input: {params: {name: "SOX", description: "Sarbanes-Oxley Act", color: "#87CEEB", default: true}, namespacePath: "gitlab-org"}
) {
framework {
id
name
default
description
color
pipelineConfigurationFullPath
}
errors
}
}
```
Setting an existing compliance framework as the default framework the group.
```graphql
mutation {
updateComplianceFramework(
input: {id: "gid://gitlab/ComplianceManagement::Framework/<id>", params: {default: true}}
) {
complianceFramework {
id
name
default
description
color
pipelineConfigurationFullPath
}
}
}
```
### Configure a compliance pipeline **(ULTIMATE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3156) in GitLab 13.9, disabled behind `ff_evaluate_group_level_compliance_pipeline` [feature flag](../../administration/feature_flags.md).
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/331231) in GitLab 14.2.
Group owners can configure a compliance pipeline in a project separate to other projects. By default, the compliance
pipeline configuration (`.gitlab-ci.yml` file) is run instead of the pipeline configuration of labeled projects.
However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that:
- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of
pipeline configuration.
- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's
`.gitlab-ci.yml` file.
See [example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from
labeled project pipeline configuration.
To configure a compliance pipeline:
1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
1. On the left sidebar, select **Settings** > **General**.
1. Expand the **Compliance frameworks** section.
1. In **Compliance pipeline configuration (optional)**, add the path to the compliance framework configuration. Use the
`path/file.y[a]ml@group-name/project-name` format. For example:
- `.compliance-ci.yml@gitlab-org/gitlab`.
- `.compliance-ci.yaml@gitlab-org/gitlab`.
This configuration is inherited by projects where the compliance framework label is
[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration.
The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project.
When used to enforce scan execution, this feature has some overlap with
[scan execution policies](../application_security/policies/scan-execution-policies.md). We have not
[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on
the similarities and differences between these features, see [Enforce scan execution](../application_security/index.md#enforce-scan-execution).
#### Example configuration
The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline
configuration is also executed.
```yaml
# Allows compliance team to control the ordering and interweaving of stages/jobs.
# Stages without jobs defined will remain hidden.
stages:
- pre-compliance
- build
- test
- pre-deploy-compliance
- deploy
- post-compliance
variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
FOO: sast
sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
variables:
FOO: sast
image: ruby:2.6
stage: pre-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
sanity check:
image: ruby:2.6
stage: pre-deploy-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
audit trail:
image: ruby:2.7
stage: post-compliance
rules:
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
when: never
- when: always # or when: on_success
allow_failure: false
before_script:
- "# No before scripts."
script:
- echo "running $FOO"
after_script:
- "# No after scripts."
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME' # Must be defined or MR pipelines always use the use default branch
```
##### CF pipelines in Merge Requests originating in project forks
When an MR originates in a fork, the branch to be merged usually only exists in the fork.
When creating such an MR against a project with CF pipelines, the above snippet will fail with a
`Project <project-name> reference <branch-name> does not exist!` error message.
This is because in the context of the target project, `$CI_COMMIT_REF_NAME` evaluates to a non-existing branch name.
To get the correct context, use `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` instead of `$CI_PROJECT_PATH`.
This variable is only availabe in
[merge request pipelines](../../ci/pipelines/merge_request_pipelines.md).
For example, for a configuration that supports both merge request pipelines originating in project forks and branch pipelines,
you need to [combine both `include` directives with `rules:if`](../../ci/yaml/includes.md#use-rules-with-include):
```yaml
include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
- project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME'
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- project: '$CI_PROJECT_PATH'
file: '$CI_CONFIG_PATH'
ref: '$CI_COMMIT_REF_NAME'
rules:
- if: $CI_PIPELINE_SOURCE != 'merge_request_event'
```
### Ensure compliance jobs are always run
Compliance pipelines [use GitLab CI/CD](../../ci/index.md) to give you an incredible amount of flexibility
for defining any sort of compliance jobs you like. Depending on your goals, these jobs
can be configured to be:
- Modified by users.
- Non-modifiable.
Generally, if a value in a compliance job:
- Is set, it cannot be changed or overridden by project-level configurations.
- Is not set, a project-level configuration may set.
Either might be wanted or not depending on your use case.
There are a few best practices for ensuring that these jobs are always run exactly
as you define them and that downstream, project-level pipeline configurations
cannot change them:
- Add [a `rules:when:always` block](../../ci/yaml/index.md#when) to each of your compliance jobs. This ensures they are
non-modifiable and are always run.
- Explicitly set any [variables](../../ci/yaml/index.md#variables) the job references. This:
- Ensures that project-level pipeline configurations do not set them and alter their
behavior.
- Includes any jobs that drive the logic of your job.
- Explicitly set the [container image](../../ci/yaml/index.md#image) to run the job in. This ensures that your script
steps execute in the correct environment.
- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/index.md#job-keywords).
This ensures that your job uses the settings you intend and that they are not overridden by
project-level pipelines.
### Avoid parent and child pipelines in GitLab 14.7 and earlier
NOTE:
This advice does not apply to GitLab 14.8 and later because [a fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78878) added
compatibility for combining compliance pipelines, and parent and child pipelines.
Compliance pipelines start on the run of _every_ pipeline in a labeled project. This means that if a pipeline in the labeled project
triggers a child pipeline, the compliance pipeline runs first. This can trigger the parent pipeline, instead of the child pipeline.
Therefore, in projects with compliance frameworks, we recommend replacing
[parent-child pipelines](../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines) with the following:
- Direct [`include`](../../ci/yaml/index.md#include) statements that provide the parent pipeline with child pipeline configuration.
- Child pipelines placed in another project that are run using the [trigger API](../../ci/triggers/index.md) rather than the parent-child
pipeline feature.
This alternative ensures the compliance pipeline does not re-start the parent pipeline.
## Disable email notifications
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23585) in GitLab 12.2.

View file

@ -45,7 +45,7 @@ If you're an instance administrator, you can administer all project topics from
## Add a compliance framework to a project **(PREMIUM)**
[Compliance frameworks](../../group/manage.md#compliance-frameworks) can be assigned to projects within group that has a
[Compliance frameworks](../../group/compliance_frameworks.md) can be assigned to projects within group that has a
compliance framework using either:
- The GitLab UI:

View file

@ -188,6 +188,7 @@ module API
mount ::API::ProjectRepositoryStorageMoves
mount ::API::Release::Links
mount ::API::ResourceAccessTokens
mount ::API::ProtectedTags
mount ::API::SnippetRepositoryStorageMoves
mount ::API::ProtectedBranches
mount ::API::Statistics

View file

@ -38,7 +38,7 @@ module API
latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
authorize_read_job_artifacts!(latest_build)
present_artifacts_file!(latest_build.artifacts_file, project: latest_build.project)
present_artifacts_file!(latest_build.artifacts_file)
end
desc 'Download a specific file from artifacts archive from a ref' do
@ -80,7 +80,7 @@ module API
build = find_build!(params[:job_id])
authorize_read_job_artifacts!(build)
present_artifacts_file!(build.artifacts_file, project: build.project)
present_artifacts_file!(build.artifacts_file)
end
desc 'Download a specific file from artifacts archive' do

View file

@ -349,7 +349,7 @@ module API
authenticate_job!(require_running: false)
end
present_artifacts_file!(current_job.artifacts_file, project: current_job.project, supports_direct_download: params[:direct_download])
present_artifacts_file!(current_job.artifacts_file, supports_direct_download: params[:direct_download])
end
end
end

View file

@ -3,7 +3,7 @@
module API
module Entities
class ProtectedTag < Grape::Entity
expose :name
expose :name, documentation: { type: 'string', example: 'release-1-0' }
expose :create_access_levels, using: Entities::ProtectedRefAccess
end
end

View file

@ -592,19 +592,19 @@ module API
end
end
def present_artifacts_file!(file, project:, **args)
def present_artifacts_file!(file, **args)
log_artifacts_filesize(file&.model)
present_carrierwave_file!(file, project: project, **args)
present_carrierwave_file!(file, **args)
end
def present_carrierwave_file!(file, project: nil, supports_direct_download: true)
def present_carrierwave_file!(file, supports_direct_download: true)
return not_found! unless file&.exists?
if file.file_storage?
present_disk_file!(file.path, file.filename)
elsif supports_direct_download && file.class.direct_download_enabled?
redirect(cdn_fronted_url(file, project))
redirect(cdn_fronted_url(file))
else
header(*Gitlab::Workhorse.send_url(file.url))
status :ok
@ -612,9 +612,9 @@ module API
end
end
def cdn_fronted_url(file, project)
def cdn_fronted_url(file)
if file.respond_to?(:cdn_enabled_url)
result = file.cdn_enabled_url(project, ip_address)
result = file.cdn_enabled_url(ip_address)
Gitlab::ApplicationContext.push(artifact_used_cdn: result.used_cdn)
result.url
else

View file

@ -18,7 +18,13 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected tags" do
detail 'This feature was introduced in GitLab 11.3.'
success Entities::ProtectedTag
is_array true
success code: 200, model: Entities::ProtectedTag
failure [
{ code: 403, message: 'Unauthenticated' },
{ code: 404, message: 'Not found' }
]
tags %w[protected_tags]
end
params do
use :pagination
@ -33,10 +39,15 @@ module API
desc 'Get a single protected tag' do
detail 'This feature was introduced in GitLab 11.3.'
success Entities::ProtectedTag
success code: 200, model: Entities::ProtectedTag
failure [
{ code: 403, message: 'Unauthenticated' },
{ code: 404, message: 'Not found' }
]
tags %w[protected_tags]
end
params do
requires :name, type: String, desc: 'The name of the tag or wildcard'
requires :name, type: String, desc: 'The name of the tag or wildcard', documentation: { example: 'release*' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
@ -48,13 +59,21 @@ module API
desc 'Protect a single tag or wildcard' do
detail 'This feature was introduced in GitLab 11.3.'
success Entities::ProtectedTag
success code: 201, model: Entities::ProtectedTag
failure [
{ code: 403, message: 'Unauthenticated' },
{ code: 404, message: 'Not found' },
{ code: 422, message: 'Unprocessable entity' }
]
tags %w[protected_tags]
end
params do
requires :name, type: String, desc: 'The name of the protected tag'
optional :create_access_level, type: Integer,
requires :name, type: String, desc: 'The name of the protected tag', documentation: { example: 'release-1-0' }
optional :create_access_level,
type: Integer,
values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)'
desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)',
documentation: { example: 30 }
use :optional_params_ee
end
post ':id/protected_tags' do
@ -76,9 +95,16 @@ module API
desc 'Unprotect a single tag' do
detail 'This feature was introduced in GitLab 11.3.'
success code: 204
failure [
{ code: 403, message: 'Unauthenticated' },
{ code: 404, message: 'Not found' },
{ code: 412, message: 'Precondition Failed' }
]
tags %w[protected_tags]
end
params do
requires :name, type: String, desc: 'The name of the protected tag'
requires :name, type: String, desc: 'The name of the protected tag', documentation: { example: 'release-1-0' }
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do

View file

@ -352,7 +352,7 @@ module Gitlab
end
def cookie_key
"#{idempotency_key}:cookie"
"#{idempotency_key}:cookie:v2"
end
def get_cookie

View file

@ -31814,6 +31814,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
msgid "ProjectSettings|Configure your infrastructure."
msgstr ""
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@ -31913,6 +31916,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
msgid "ProjectSettings|Infrastructure"
msgstr ""
msgid "ProjectSettings|Internal"
msgstr ""

View file

@ -103,6 +103,9 @@ RSpec.describe 'User changes public project visibility', :js do
sign_in(project.first_owner)
visit edit_project_path(project)
# https://gitlab.com/gitlab-org/gitlab/-/issues/381259
allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(110)
end
it_behaves_like 'does not require confirmation'

View file

@ -147,6 +147,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="set_up_your_first_project_s_ci_cd"
@ -171,6 +172,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="start_a_free_trial_of_gitlab_ultimate"
@ -196,6 +198,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="add_code_owners"
@ -228,6 +231,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="enable_require_merge_approvals"
@ -294,6 +298,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="create_an_issue"
@ -318,6 +323,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="submit_a_merge_request_mr"
@ -376,6 +382,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="run_a_security_scan_using_ci_cd"

View file

@ -137,6 +137,8 @@ describe('Settings Panel', () => {
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
const findEnvironmentsSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
const findFeatureFlagsSettings = () => wrapper.findComponent({ ref: 'feature-flags-settings' });
const findInfrastructureSettings = () =>
wrapper.findComponent({ ref: 'infrastructure-settings' });
const findReleasesSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
const findMonitorSettings = () => wrapper.findComponent({ ref: 'monitor-settings' });
@ -841,6 +843,24 @@ describe('Settings Panel', () => {
});
});
});
describe('Infrastructure', () => {
describe('with feature flag', () => {
it('should show the infrastructure toggle', () => {
wrapper = mountComponent({
glFeatures: { splitOperationsVisibilityPermissions: true },
});
expect(findInfrastructureSettings().exists()).toBe(true);
});
});
describe('without feature flag', () => {
it('should not show the infrastructure toggle', () => {
wrapper = mountComponent({});
expect(findInfrastructureSettings().exists()).toBe(false);
});
});
});
describe('Releases', () => {
describe('with feature flag', () => {
it('should show the releases toggle', () => {

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['CommitSignature'] do
it 'exposes the expected fields' do
expect(described_class).to have_graphql_fields(:verification_status, :commit_sha, :project)
end
describe '.resolve_type' do
it 'resolves gpg signatures' do
expect(described_class.resolve_type(build(:gpg_signature), {})).to eq(
Types::CommitSignatures::GpgSignatureType)
end
it 'resolves x509 signatures' do
expect(described_class.resolve_type(build(:x509_commit_signature), {})).to eq(
Types::CommitSignatures::X509SignatureType)
end
it 'raises an error when type is not known' do
expect { described_class.resolve_type(Class, {}) }.to raise_error('Unsupported commit signature type')
end
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['GpgSignature'] do
specify { expect(described_class.graphql_name).to eq('GpgSignature') }
specify { expect(described_class).to require_graphql_authorizations(:download_code) }
specify { expect(described_class).to include(Types::CommitSignatureInterface) }
it 'contains attributes related to GPG signatures' do
expect(described_class).to have_graphql_fields(
:user, :verification_status, :commit_sha, :project,
:gpg_key_user_name, :gpg_key_user_email, :gpg_key_primary_keyid
)
end
end

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['VerificationStatus'] do
specify { expect(described_class.graphql_name).to eq('VerificationStatus') }
it 'exposes all signature verification states' do
expect(described_class.values.keys)
.to match_array(%w[
UNVERIFIED UNVERIFIED_KEY VERIFIED
SAME_USER_DIFFERENT_EMAIL OTHER_USER UNKNOWN_KEY
MULTIPLE_SIGNATURES
])
end
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['X509Signature'] do
specify { expect(described_class.graphql_name).to eq('X509Signature') }
specify { expect(described_class).to require_graphql_authorizations(:download_code) }
specify { expect(described_class).to include(Types::CommitSignatureInterface) }
it 'contains attributes related to X.509 signatures' do
expect(described_class).to have_graphql_fields(
:user, :verification_status, :commit_sha, :project,
:x509_certificate
)
end
end

View file

@ -13,7 +13,7 @@ RSpec.describe GitlabSchema.types['Commit'] do
expect(described_class).to have_graphql_fields(
:id, :sha, :short_id, :title, :full_title, :full_title_html, :description, :description_html, :message, :title_html, :authored_date,
:author_name, :author_email, :author_gravatar, :author, :web_url, :web_path,
:pipelines, :signature_html
:pipelines, :signature_html, :signature
)
end
end

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['X509Certificate'] do
specify { expect(described_class.graphql_name).to eq('X509Certificate') }
it 'contains attributes for X.509 certifcates' do
expect(described_class).to have_graphql_fields(
:certificate_status, :created_at, :email, :id, :serial_number, :subject,
:subject_key_identifier, :updated_at, :x509_issuer
)
end
end

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['X509Issuer'] do
specify { expect(described_class.graphql_name).to eq('X509Issuer') }
it 'contains attributes for X.509 issuers' do
expect(described_class).to have_graphql_fields(
:created_at, :crl_url, :id, :subject, :subject_key_identifier, :updated_at
)
end
end

View file

@ -969,7 +969,8 @@ RSpec.describe ProjectsHelper do
containerRegistryAccessLevel: project.project_feature.container_registry_access_level,
environmentsAccessLevel: project.project_feature.environments_access_level,
featureFlagsAccessLevel: project.project_feature.feature_flags_access_level,
releasesAccessLevel: project.project_feature.releases_access_level
releasesAccessLevel: project.project_feature.releases_access_level,
infrastructureAccessLevel: project.project_feature.infrastructure_access_level
)
end

View file

@ -798,7 +798,7 @@ RSpec.describe API::Helpers do
context 'with object storage' do
let(:artifact) { create(:ci_job_artifact, :zip, :remote_store) }
subject { helper.present_artifacts_file!(artifact.file, project: artifact.job.project) }
subject { helper.present_artifacts_file!(artifact.file) }
before do
allow(helper).to receive(:env).and_return({})
@ -830,7 +830,7 @@ RSpec.describe API::Helpers do
it 'retrieves a CDN-fronted URL' do
expect(artifact.file).to receive(:cdn_enabled_url).and_call_original
expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: false).and_call_original
expect(helper.cdn_fronted_url(artifact.file, artifact.job.project)).to be_a(String)
expect(helper.cdn_fronted_url(artifact.file)).to be_a(String)
end
end
@ -841,7 +841,7 @@ RSpec.describe API::Helpers do
file = double(url: url)
expect(Gitlab::ApplicationContext).not_to receive(:push)
expect(helper.cdn_fronted_url(file, nil)).to eq(url)
expect(helper.cdn_fronted_url(file)).to eq(url)
end
end
end

View file

@ -527,7 +527,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
end
context 'with Redis cookies' do
let(:cookie_key) { "#{idempotency_key}:cookie" }
let(:cookie_key) { "#{idempotency_key}:cookie:v2" }
let(:cookie) { get_redis_msgpack(cookie_key) }
def with_redis(&block)

View file

@ -85,4 +85,10 @@ RSpec.describe CommitSignatures::GpgSignature do
end
end
end
describe '#user' do
it 'retrieves the gpg_key user' do
expect(signature.user).to eq(gpg_key.user)
end
end
end

View file

@ -389,8 +389,7 @@ RSpec.describe API::Ci::JobArtifacts do
end
end
context 'when Google CDN is enabled' do
let(:cdn_enabled) { true }
context 'when Google CDN is configured' do
let(:cdn_config) do
{
'provider' => 'Google',
@ -401,7 +400,6 @@ RSpec.describe API::Ci::JobArtifacts do
end
before do
stub_feature_flags(ci_job_artifacts_cdn: cdn_enabled)
stub_object_storage_uploader(config: Gitlab.config.artifacts.object_store,
uploader: JobArtifactUploader,
proxy_download: proxy_download,
@ -418,18 +416,6 @@ RSpec.describe API::Ci::JobArtifacts do
expect(response.redirect_url).to start_with("https://cdn.example.org/#{artifact.file.path}")
end
context 'when ci_job_artifacts_cdn feature flag is disabled' do
let(:cdn_enabled) { false }
it 'returns the file remote URL' do
expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: false).and_call_original
subject
expect(response).to redirect_to(artifact.file.url)
end
end
end
context 'authorized user' do

View file

@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe 'getting a tree in a project' do
include GraphqlHelpers
let(:project) { create(:project, :repository) }
let_it_be(:project) { create(:project, :repository) }
let(:current_user) { project.first_owner }
let(:path) { "" }
let(:ref) { "master" }
@ -82,6 +83,89 @@ RSpec.describe 'getting a tree in a project' do
end
end
context 'when the ref points to a gpg-signed commit with a user' do
let_it_be(:name) { GpgHelpers::User1.names.first }
let_it_be(:email) { GpgHelpers::User1.emails.first }
let_it_be(:current_user) { create(:user, name: name, email: email).tap { |user| project.add_owner(user) } }
let_it_be(:gpg_key) { create(:gpg_key, user: current_user, key: GpgHelpers::User1.public_key) }
let(:ref) { GpgHelpers::SIGNED_AND_AUTHORED_SHA }
let(:fields) do
<<~QUERY
tree(path:"#{path}", ref:"#{ref}") {
lastCommit {
signature {
... on GpgSignature {
#{all_graphql_fields_for('GpgSignature'.classify, max_depth: 2)}
}
}
}
}
QUERY
end
before do
post_graphql(query, current_user: current_user)
end
it 'returns the expected signature data' do
signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
expect(signature['commitSha']).to eq(ref)
expect(signature['user']['id']).to eq("gid://gitlab/User/#{current_user.id}")
expect(signature['gpgKeyUserName']).to eq(name)
expect(signature['gpgKeyUserEmail']).to eq(email)
expect(signature['verificationStatus']).to eq('VERIFIED')
expect(signature['project']['id']).to eq("gid://gitlab/Project/#{project.id}")
end
end
context 'when the ref points to a X.509-signed commit' do
let_it_be(:email) { X509Helpers::User1.certificate_email }
let_it_be(:current_user) { create(:user, email: email).tap { |user| project.add_owner(user) } }
let(:ref) { X509Helpers::User1.commit }
let(:fields) do
<<~QUERY
tree(path:"#{path}", ref:"#{ref}") {
lastCommit {
signature {
... on X509Signature {
#{all_graphql_fields_for('X509Signature'.classify, max_depth: 2)}
}
}
}
}
QUERY
end
before do
store = OpenSSL::X509::Store.new
store.add_cert(OpenSSL::X509::Certificate.new(X509Helpers::User1.trust_cert))
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
post_graphql(query, current_user: current_user)
end
it 'returns the expected signature data' do
signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
expect(signature['commitSha']).to eq(ref)
expect(signature['verificationStatus']).to eq('VERIFIED')
expect(signature['project']['id']).to eq("gid://gitlab/Project/#{project.id}")
end
it 'returns expected certificate data' do
signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
certificate = signature['x509Certificate']
expect(certificate['certificateStatus']).to eq('good')
expect(certificate['email']).to eq(X509Helpers::User1.certificate_email)
expect(certificate['id']).to be_present
expect(certificate['serialNumber']).to eq(X509Helpers::User1.certificate_serial.to_s)
expect(certificate['subject']).to eq(X509Helpers::User1.certificate_subject)
expect(certificate['subjectKeyIdentifier']).to eq(X509Helpers::User1.certificate_subject_key_identifier)
expect(certificate['createdAt']).to be_present
expect(certificate['updatedAt']).to be_present
end
end
context 'when current user is nil' do
it 'returns empty project' do
post_graphql(query, current_user: nil)

View file

@ -11,6 +11,8 @@ module TestEnv
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
'signed-commits' => 'c7794c1',
'gpg-signed' => '8a852d5',
'x509-signed' => 'a4df3c8',
'not-merged-branch' => 'b83d6e3',
'branch-merged' => '498214d',
'empty-branch' => '7efb185',

View file

@ -26,7 +26,7 @@ RSpec.describe JobArtifactUploader do
describe '#cdn_enabled_url' do
it 'returns URL and false' do
result = uploader.cdn_enabled_url(nil, '127.0.0.1')
result = uploader.cdn_enabled_url('127.0.0.1')
expect(result.used_cdn).to be false
end

View file

@ -44,32 +44,15 @@ RSpec.describe ObjectStorage::CDN do
end
describe '#cdn_enabled_url' do
context 'with ci_job_artifacts_cdn feature flag disabled' do
before do
stub_feature_flags(ci_job_artifacts_cdn: false)
end
it 'calls #url' do
expect(subject).to receive(:url).and_call_original
expect(subject).not_to receive(:cdn_signed_url)
result = subject.cdn_enabled_url(project, public_ip)
expect(result.used_cdn).to be false
end
end
context 'with ci_job_artifacts_cdn feature flag enabled' do
it 'calls #cdn_signed_url' do
expect(subject).not_to receive(:url)
expect(subject).to receive(:cdn_signed_url).and_call_original
result = subject.cdn_enabled_url(project, public_ip)
result = subject.cdn_enabled_url(public_ip)
expect(result.used_cdn).to be true
end
end
end
describe '#use_cdn?' do
it 'returns true' do