Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
983f6954d1
commit
03cd2a56f3
58 changed files with 897 additions and 344 deletions
|
@ -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:
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
"CiManualVariable",
|
||||
"CiProjectVariable"
|
||||
],
|
||||
"CommitSignature": [
|
||||
"GpgSignature",
|
||||
"X509Signature"
|
||||
],
|
||||
"CurrentUserTodos": [
|
||||
"BoardEpic",
|
||||
"Design",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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') }}
|
||||
|
|
|
@ -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>
|
||||
|
|
37
app/graphql/types/commit_signature_interface.rb
Normal file
37
app/graphql/types/commit_signature_interface.rb
Normal 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
|
29
app/graphql/types/commit_signatures/gpg_signature_type.rb
Normal file
29
app/graphql/types/commit_signatures/gpg_signature_type.rb
Normal 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
|
|
@ -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
|
22
app/graphql/types/commit_signatures/x509_signature_type.rb
Normal file
22
app/graphql/types/commit_signatures/x509_signature_type.rb
Normal 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
|
|
@ -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.'
|
||||
|
||||
|
|
39
app/graphql/types/x509_certificate_type.rb
Normal file
39
app/graphql/types/x509_certificate_type.rb
Normal 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
|
29
app/graphql/types/x509_issuer_type.rb
Normal file
29
app/graphql/types/x509_issuer_type.rb
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -49,5 +49,9 @@ module CommitSignatures
|
|||
|
||||
Gitlab::Gpg::Commit.new(commit)
|
||||
end
|
||||
|
||||
def user
|
||||
gpg_key&.user
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
7
app/policies/commit_signatures/gpg_signature_policy.rb
Normal file
7
app/policies/commit_signatures/gpg_signature_policy.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module CommitSignatures
|
||||
class GpgSignaturePolicy < BasePolicy
|
||||
delegate { @subject.project }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module CommitSignatures
|
||||
class X509CommitSignaturePolicy < BasePolicy
|
||||
delegate { @subject.project }
|
||||
end
|
||||
end
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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).
|
||||
|
|
262
doc/user/group/compliance_frameworks.md
Normal file
262
doc/user/group/compliance_frameworks.md
Normal 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.
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -352,7 +352,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def cookie_key
|
||||
"#{idempotency_key}:cookie"
|
||||
"#{idempotency_key}:cookie:v2"
|
||||
end
|
||||
|
||||
def get_cookie
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
25
spec/graphql/types/commit_signature_interface_spec.rb
Normal file
25
spec/graphql/types/commit_signature_interface_spec.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
14
spec/graphql/types/x509_certificate_type_spec.rb
Normal file
14
spec/graphql/types/x509_certificate_type_spec.rb
Normal 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
|
13
spec/graphql/types/x509_issuer_type_spec.rb
Normal file
13
spec/graphql/types/x509_issuer_type_spec.rb
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue