Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
983f6954d1
commit
03cd2a56f3
|
@ -171,7 +171,7 @@ graphql-schema-dump:
|
||||||
graphql-schema-dump as-if-foss:
|
graphql-schema-dump as-if-foss:
|
||||||
extends:
|
extends:
|
||||||
- graphql-schema-dump
|
- graphql-schema-dump
|
||||||
- .frontend:rules:eslint-as-if-foss
|
- .frontend:rules:default-frontend-jobs-as-if-foss
|
||||||
- .as-if-foss
|
- .as-if-foss
|
||||||
|
|
||||||
.frontend-test-base:
|
.frontend-test-base:
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
files:
|
files:
|
||||||
- GITALY_SERVER_VERSION
|
- GITALY_SERVER_VERSION
|
||||||
- lib/gitlab/setup_helper.rb
|
- 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:
|
paths:
|
||||||
- ${TMP_TEST_FOLDER}/gitaly/_build/bin/
|
- ${TMP_TEST_FOLDER}/gitaly/_build/bin/
|
||||||
- ${TMP_TEST_FOLDER}/gitaly/_build/deps/git/install/
|
- ${TMP_TEST_FOLDER}/gitaly/_build/deps/git/install/
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
"CiManualVariable",
|
"CiManualVariable",
|
||||||
"CiProjectVariable"
|
"CiProjectVariable"
|
||||||
],
|
],
|
||||||
|
"CommitSignature": [
|
||||||
|
"GpgSignature",
|
||||||
|
"X509Signature"
|
||||||
|
],
|
||||||
"CurrentUserTodos": [
|
"CurrentUserTodos": [
|
||||||
"BoardEpic",
|
"BoardEpic",
|
||||||
"Design",
|
"Design",
|
||||||
|
|
|
@ -86,6 +86,7 @@ export default {
|
||||||
:target="openInNewTab ? '_blank' : '_self'"
|
:target="openInNewTab ? '_blank' : '_self'"
|
||||||
:href="value.url"
|
:href="value.url"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
:data-track-label="actionLabelValue('trackLabel')"
|
:data-track-label="actionLabelValue('trackLabel')"
|
||||||
>{{ actionLabelValue('title') }}</gl-link
|
>{{ actionLabelValue('title') }}</gl-link
|
||||||
|
|
|
@ -41,6 +41,8 @@ export default {
|
||||||
featureFlagsHelpText: s__(
|
featureFlagsHelpText: s__(
|
||||||
'ProjectSettings|Roll out new features without redeploying with feature flags.',
|
'ProjectSettings|Roll out new features without redeploying with feature flags.',
|
||||||
),
|
),
|
||||||
|
infrastructureLabel: s__('ProjectSettings|Infrastructure'),
|
||||||
|
infrastructureHelpText: s__('ProjectSettings|Configure your infrastructure.'),
|
||||||
monitorLabel: s__('ProjectSettings|Monitor'),
|
monitorLabel: s__('ProjectSettings|Monitor'),
|
||||||
packagesHelpText: s__(
|
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.',
|
'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,
|
required: false,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
infrastructureHelpPath: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
releasesHelpPath: {
|
releasesHelpPath: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
|
@ -245,6 +252,7 @@ export default {
|
||||||
operationsAccessLevel: featureAccessLevel.EVERYONE,
|
operationsAccessLevel: featureAccessLevel.EVERYONE,
|
||||||
environmentsAccessLevel: featureAccessLevel.EVERYONE,
|
environmentsAccessLevel: featureAccessLevel.EVERYONE,
|
||||||
featureFlagsAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
|
featureFlagsAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
|
||||||
|
infrastructureAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
|
||||||
releasesAccessLevel: featureAccessLevel.EVERYONE,
|
releasesAccessLevel: featureAccessLevel.EVERYONE,
|
||||||
monitorAccessLevel: featureAccessLevel.EVERYONE,
|
monitorAccessLevel: featureAccessLevel.EVERYONE,
|
||||||
containerRegistryAccessLevel: featureAccessLevel.EVERYONE,
|
containerRegistryAccessLevel: featureAccessLevel.EVERYONE,
|
||||||
|
@ -433,6 +441,10 @@ export default {
|
||||||
featureAccessLevel.PROJECT_MEMBERS,
|
featureAccessLevel.PROJECT_MEMBERS,
|
||||||
this.featureFlagsAccessLevel,
|
this.featureFlagsAccessLevel,
|
||||||
);
|
);
|
||||||
|
this.infrastructureAccessLevel = Math.min(
|
||||||
|
featureAccessLevel.PROJECT_MEMBERS,
|
||||||
|
this.infrastructureAccessLevel,
|
||||||
|
);
|
||||||
this.releasesAccessLevel = Math.min(
|
this.releasesAccessLevel = Math.min(
|
||||||
featureAccessLevel.PROJECT_MEMBERS,
|
featureAccessLevel.PROJECT_MEMBERS,
|
||||||
this.releasesAccessLevel,
|
this.releasesAccessLevel,
|
||||||
|
@ -981,6 +993,19 @@ export default {
|
||||||
name="project[project_feature_attributes][feature_flags_access_level]"
|
name="project[project_feature_attributes][feature_flags_access_level]"
|
||||||
/>
|
/>
|
||||||
</project-setting-row>
|
</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>
|
</template>
|
||||||
<project-setting-row
|
<project-setting-row
|
||||||
ref="releases-settings"
|
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"
|
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="#"
|
href="#"
|
||||||
data-test-id="edit-link"
|
data-test-id="edit-link"
|
||||||
|
data-qa-selector="edit_link"
|
||||||
data-track-action="click_edit_button"
|
data-track-action="click_edit_button"
|
||||||
data-track-label="right_sidebar"
|
data-track-label="right_sidebar"
|
||||||
data-track-property="assignee"
|
data-track-property="assignee"
|
||||||
|
|
|
@ -56,6 +56,7 @@ export default {
|
||||||
type="button"
|
type="button"
|
||||||
class="gl-button btn-link gl-reset-color!"
|
class="gl-button btn-link gl-reset-color!"
|
||||||
data-testid="assign-yourself"
|
data-testid="assign-yourself"
|
||||||
|
data-qa-selector="assign_yourself_button"
|
||||||
@click="assignSelf"
|
@click="assignSelf"
|
||||||
>
|
>
|
||||||
{{ __('assign yourself') }}
|
{{ __('assign yourself') }}
|
||||||
|
|
|
@ -91,6 +91,7 @@ export default {
|
||||||
<div
|
<div
|
||||||
class="gl-ml-3 gl-line-height-normal gl-display-grid gl-align-items-center"
|
class="gl-ml-3 gl-line-height-normal gl-display-grid gl-align-items-center"
|
||||||
data-testid="username"
|
data-testid="username"
|
||||||
|
data-qa-selector="username"
|
||||||
>
|
>
|
||||||
<user-name-with-status :name="user.name" :availability="userAvailability(user)" />
|
<user-name-with-status :name="user.name" :availability="userAvailability(user)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
field :web_path, type: GraphQL::Types::String, null: false,
|
||||||
description: 'Web path of the commit.'
|
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,
|
field :signature_html, type: GraphQL::Types::String, null: true, calls_gitaly: true,
|
||||||
description: 'Rendered HTML of the commit signature.'
|
description: 'Rendered HTML of the commit signature.'
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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),
|
membersPagePath: project_project_members_path(project),
|
||||||
environmentsHelpPath: help_page_path('ci/environments/index'),
|
environmentsHelpPath: help_page_path('ci/environments/index'),
|
||||||
featureFlagsHelpPath: help_page_path('operations/feature_flags'),
|
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
|
end
|
||||||
|
|
||||||
|
@ -664,7 +665,8 @@ module ProjectsHelper
|
||||||
containerRegistryAccessLevel: feature.container_registry_access_level,
|
containerRegistryAccessLevel: feature.container_registry_access_level,
|
||||||
environmentsAccessLevel: feature.environments_access_level,
|
environmentsAccessLevel: feature.environments_access_level,
|
||||||
featureFlagsAccessLevel: feature.feature_flags_access_level,
|
featureFlagsAccessLevel: feature.feature_flags_access_level,
|
||||||
releasesAccessLevel: feature.releases_access_level
|
releasesAccessLevel: feature.releases_access_level,
|
||||||
|
infrastructureAccessLevel: feature.infrastructure_access_level
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,5 +49,9 @@ module CommitSignatures
|
||||||
|
|
||||||
Gitlab::Gpg::Commit.new(commit)
|
Gitlab::Gpg::Commit.new(commit)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user
|
||||||
|
gpg_key&.user
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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)
|
UrlResult = Struct.new(:url, :used_cdn)
|
||||||
|
|
||||||
def cdn_enabled_url(project, ip_address)
|
def cdn_enabled_url(ip_address)
|
||||||
if Feature.enabled?(:ci_job_artifacts_cdn, project) && use_cdn?(ip_address)
|
if use_cdn?(ip_address)
|
||||||
UrlResult.new(cdn_signed_url, true)
|
UrlResult.new(cdn_signed_url, true)
|
||||||
else
|
else
|
||||||
UrlResult.new(url, false)
|
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
|
stays configured and working correctly. These features can help you automate
|
||||||
compliance:
|
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 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.
|
pipeline configuration to run for any projects with a given compliance framework.
|
||||||
|
|
||||||
## Audit management
|
## 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="commitmessage"></a>`message` | [`String`](#string) | Raw commit message. |
|
||||||
| <a id="commitsha"></a>`sha` | [`String!`](#string) | SHA1 ID of the commit. |
|
| <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="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="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="committitle"></a>`title` | [`String`](#string) | Title of the commit message. |
|
||||||
| <a id="committitlehtml"></a>`titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. |
|
| <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="geonodeuploadregistriesreplicationstate"></a>`replicationState` | [`ReplicationStateEnum`](#replicationstateenum) | Filters registries by their replication state. |
|
||||||
| <a id="geonodeuploadregistriesverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Filters registries by their verification 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`
|
### `GrafanaIntegration`
|
||||||
|
|
||||||
#### Fields
|
#### Fields
|
||||||
|
@ -20078,6 +20095,53 @@ Represents a weight widget.
|
||||||
| <a id="workitemwidgetweighttype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
|
| <a id="workitemwidgetweighttype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
|
||||||
| <a id="workitemwidgetweightweight"></a>`weight` | [`Int`](#int) | Weight of the work item. |
|
| <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
|
## Enumeration types
|
||||||
|
|
||||||
Also called _Enums_, enumeration types are a special kind of scalar that
|
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="verificationstateenumstarted"></a>`STARTED` | Verification process is in progress. |
|
||||||
| <a id="verificationstateenumsucceeded"></a>`SUCCEEDED` | Verification process finished successfully. |
|
| <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`
|
### `VisibilityLevelsEnum`
|
||||||
|
|
||||||
| Value | Description |
|
| Value | Description |
|
||||||
|
@ -22903,6 +22981,23 @@ Implementations:
|
||||||
| <a id="civariablevalue"></a>`value` | [`String`](#string) | Value of the variable. |
|
| <a id="civariablevalue"></a>`value` | [`String`](#string) | Value of the variable. |
|
||||||
| <a id="civariablevariabletype"></a>`variableType` | [`CiVariableType`](#civariabletype) | Type 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`
|
#### `CurrentUserTodos`
|
||||||
|
|
||||||
Implementations:
|
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 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,
|
- 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.
|
- 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.
|
- 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.
|
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/352316) from GitLab Premium to GitLab Ultimate in 15.0.
|
||||||
|
|
||||||
NOTE:
|
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,
|
is available. We recommend this alternative solution because it provides greater flexibility,
|
||||||
allowing required pipelines to be assigned to specific compliance framework labels.
|
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.
|
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),
|
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).
|
[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
|
or [Scan Execution Policies](policies/scan-execution-policies.md) to enforce required scan types
|
||||||
and ensure separation of duties between security and engineering.
|
and ensure separation of duties between security and engineering.
|
||||||
1. Consider enabling [Review Apps](../../development/testing_guide/review_apps.md) to allow for DAST
|
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.
|
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:
|
are recommended when:
|
||||||
|
|
||||||
- Scan execution enforcement is required for any scanner that uses a GitLab template, such as SAST IaC, DAST, Dependency Scanning,
|
- 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
|
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.
|
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).
|
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
|
For details on the similarities and differences between these features, see
|
||||||
[Enforce scan execution](../index.md#enforce-scan-execution).
|
[Enforce scan execution](../index.md#enforce-scan-execution).
|
||||||
|
|
|
@ -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:
|
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.
|
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
|
## Disable email notifications
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23585) in GitLab 12.2.
|
> [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)**
|
## 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:
|
compliance framework using either:
|
||||||
|
|
||||||
- The GitLab UI:
|
- The GitLab UI:
|
||||||
|
|
|
@ -188,6 +188,7 @@ module API
|
||||||
mount ::API::ProjectRepositoryStorageMoves
|
mount ::API::ProjectRepositoryStorageMoves
|
||||||
mount ::API::Release::Links
|
mount ::API::Release::Links
|
||||||
mount ::API::ResourceAccessTokens
|
mount ::API::ResourceAccessTokens
|
||||||
|
mount ::API::ProtectedTags
|
||||||
mount ::API::SnippetRepositoryStorageMoves
|
mount ::API::SnippetRepositoryStorageMoves
|
||||||
mount ::API::ProtectedBranches
|
mount ::API::ProtectedBranches
|
||||||
mount ::API::Statistics
|
mount ::API::Statistics
|
||||||
|
|
|
@ -38,7 +38,7 @@ module API
|
||||||
latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
|
latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
|
||||||
authorize_read_job_artifacts!(latest_build)
|
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
|
end
|
||||||
|
|
||||||
desc 'Download a specific file from artifacts archive from a ref' do
|
desc 'Download a specific file from artifacts archive from a ref' do
|
||||||
|
@ -80,7 +80,7 @@ module API
|
||||||
build = find_build!(params[:job_id])
|
build = find_build!(params[:job_id])
|
||||||
authorize_read_job_artifacts!(build)
|
authorize_read_job_artifacts!(build)
|
||||||
|
|
||||||
present_artifacts_file!(build.artifacts_file, project: build.project)
|
present_artifacts_file!(build.artifacts_file)
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Download a specific file from artifacts archive' do
|
desc 'Download a specific file from artifacts archive' do
|
||||||
|
|
|
@ -349,7 +349,7 @@ module API
|
||||||
authenticate_job!(require_running: false)
|
authenticate_job!(require_running: false)
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
module API
|
module API
|
||||||
module Entities
|
module Entities
|
||||||
class ProtectedTag < Grape::Entity
|
class ProtectedTag < Grape::Entity
|
||||||
expose :name
|
expose :name, documentation: { type: 'string', example: 'release-1-0' }
|
||||||
expose :create_access_levels, using: Entities::ProtectedRefAccess
|
expose :create_access_levels, using: Entities::ProtectedRefAccess
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -592,19 +592,19 @@ module API
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def present_artifacts_file!(file, project:, **args)
|
def present_artifacts_file!(file, **args)
|
||||||
log_artifacts_filesize(file&.model)
|
log_artifacts_filesize(file&.model)
|
||||||
|
|
||||||
present_carrierwave_file!(file, project: project, **args)
|
present_carrierwave_file!(file, **args)
|
||||||
end
|
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?
|
return not_found! unless file&.exists?
|
||||||
|
|
||||||
if file.file_storage?
|
if file.file_storage?
|
||||||
present_disk_file!(file.path, file.filename)
|
present_disk_file!(file.path, file.filename)
|
||||||
elsif supports_direct_download && file.class.direct_download_enabled?
|
elsif supports_direct_download && file.class.direct_download_enabled?
|
||||||
redirect(cdn_fronted_url(file, project))
|
redirect(cdn_fronted_url(file))
|
||||||
else
|
else
|
||||||
header(*Gitlab::Workhorse.send_url(file.url))
|
header(*Gitlab::Workhorse.send_url(file.url))
|
||||||
status :ok
|
status :ok
|
||||||
|
@ -612,9 +612,9 @@ module API
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def cdn_fronted_url(file, project)
|
def cdn_fronted_url(file)
|
||||||
if file.respond_to?(:cdn_enabled_url)
|
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)
|
Gitlab::ApplicationContext.push(artifact_used_cdn: result.used_cdn)
|
||||||
result.url
|
result.url
|
||||||
else
|
else
|
||||||
|
|
|
@ -18,7 +18,13 @@ module API
|
||||||
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
|
||||||
desc "Get a project's protected tags" do
|
desc "Get a project's protected tags" do
|
||||||
detail 'This feature was introduced in GitLab 11.3.'
|
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
|
end
|
||||||
params do
|
params do
|
||||||
use :pagination
|
use :pagination
|
||||||
|
@ -33,10 +39,15 @@ module API
|
||||||
|
|
||||||
desc 'Get a single protected tag' do
|
desc 'Get a single protected tag' do
|
||||||
detail 'This feature was introduced in GitLab 11.3.'
|
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
|
end
|
||||||
params do
|
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
|
end
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
get ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
|
get ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
|
||||||
|
@ -48,13 +59,21 @@ module API
|
||||||
|
|
||||||
desc 'Protect a single tag or wildcard' do
|
desc 'Protect a single tag or wildcard' do
|
||||||
detail 'This feature was introduced in GitLab 11.3.'
|
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
|
end
|
||||||
params do
|
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' }
|
||||||
optional :create_access_level, type: Integer,
|
optional :create_access_level,
|
||||||
values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
|
type: Integer,
|
||||||
desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)'
|
values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
|
||||||
|
desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)',
|
||||||
|
documentation: { example: 30 }
|
||||||
use :optional_params_ee
|
use :optional_params_ee
|
||||||
end
|
end
|
||||||
post ':id/protected_tags' do
|
post ':id/protected_tags' do
|
||||||
|
@ -76,9 +95,16 @@ module API
|
||||||
|
|
||||||
desc 'Unprotect a single tag' do
|
desc 'Unprotect a single tag' do
|
||||||
detail 'This feature was introduced in GitLab 11.3.'
|
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
|
end
|
||||||
params do
|
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
|
end
|
||||||
# rubocop: disable CodeReuse/ActiveRecord
|
# rubocop: disable CodeReuse/ActiveRecord
|
||||||
delete ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
|
delete ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
|
||||||
|
|
|
@ -352,7 +352,7 @@ module Gitlab
|
||||||
end
|
end
|
||||||
|
|
||||||
def cookie_key
|
def cookie_key
|
||||||
"#{idempotency_key}:cookie"
|
"#{idempotency_key}:cookie:v2"
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_cookie
|
def get_cookie
|
||||||
|
|
|
@ -31814,6 +31814,9 @@ msgstr ""
|
||||||
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
|
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ProjectSettings|Configure your infrastructure."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ProjectSettings|Configure your project resources and monitor their health."
|
msgid "ProjectSettings|Configure your project resources and monitor their health."
|
||||||
msgstr ""
|
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."
|
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "ProjectSettings|Infrastructure"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "ProjectSettings|Internal"
|
msgid "ProjectSettings|Internal"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,9 @@ RSpec.describe 'User changes public project visibility', :js do
|
||||||
sign_in(project.first_owner)
|
sign_in(project.first_owner)
|
||||||
|
|
||||||
visit edit_project_path(project)
|
visit edit_project_path(project)
|
||||||
|
|
||||||
|
# https://gitlab.com/gitlab-org/gitlab/-/issues/381259
|
||||||
|
allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(110)
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'does not require confirmation'
|
it_behaves_like 'does not require confirmation'
|
||||||
|
|
|
@ -147,6 +147,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="set_up_your_first_project_s_ci_cd"
|
data-track-label="set_up_your_first_project_s_ci_cd"
|
||||||
|
@ -171,6 +172,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="start_a_free_trial_of_gitlab_ultimate"
|
data-track-label="start_a_free_trial_of_gitlab_ultimate"
|
||||||
|
@ -196,6 +198,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="add_code_owners"
|
data-track-label="add_code_owners"
|
||||||
|
@ -228,6 +231,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="enable_require_merge_approvals"
|
data-track-label="enable_require_merge_approvals"
|
||||||
|
@ -294,6 +298,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="create_an_issue"
|
data-track-label="create_an_issue"
|
||||||
|
@ -318,6 +323,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="submit_a_merge_request_mr"
|
data-track-label="submit_a_merge_request_mr"
|
||||||
|
@ -376,6 +382,7 @@ exports[`Learn GitLab renders correctly 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
class="gl-link"
|
class="gl-link"
|
||||||
|
data-qa-selector="uncompleted_learn_gitlab_link"
|
||||||
data-testid="uncompleted-learn-gitlab-link"
|
data-testid="uncompleted-learn-gitlab-link"
|
||||||
data-track-action="click_link"
|
data-track-action="click_link"
|
||||||
data-track-label="run_a_security_scan_using_ci_cd"
|
data-track-label="run_a_security_scan_using_ci_cd"
|
||||||
|
|
|
@ -137,6 +137,8 @@ describe('Settings Panel', () => {
|
||||||
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
|
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
|
||||||
const findEnvironmentsSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
|
const findEnvironmentsSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
|
||||||
const findFeatureFlagsSettings = () => wrapper.findComponent({ ref: 'feature-flags-settings' });
|
const findFeatureFlagsSettings = () => wrapper.findComponent({ ref: 'feature-flags-settings' });
|
||||||
|
const findInfrastructureSettings = () =>
|
||||||
|
wrapper.findComponent({ ref: 'infrastructure-settings' });
|
||||||
const findReleasesSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
|
const findReleasesSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
|
||||||
const findMonitorSettings = () => wrapper.findComponent({ ref: 'monitor-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('Releases', () => {
|
||||||
describe('with feature flag', () => {
|
describe('with feature flag', () => {
|
||||||
it('should show the releases toggle', () => {
|
it('should show the releases toggle', () => {
|
||||||
|
|
|
@ -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(
|
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,
|
: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,
|
:author_name, :author_email, :author_gravatar, :author, :web_url, :web_path,
|
||||||
:pipelines, :signature_html
|
:pipelines, :signature_html, :signature
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
@ -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,
|
containerRegistryAccessLevel: project.project_feature.container_registry_access_level,
|
||||||
environmentsAccessLevel: project.project_feature.environments_access_level,
|
environmentsAccessLevel: project.project_feature.environments_access_level,
|
||||||
featureFlagsAccessLevel: project.project_feature.feature_flags_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
|
end
|
||||||
|
|
||||||
|
|
|
@ -798,7 +798,7 @@ RSpec.describe API::Helpers do
|
||||||
context 'with object storage' do
|
context 'with object storage' do
|
||||||
let(:artifact) { create(:ci_job_artifact, :zip, :remote_store) }
|
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
|
before do
|
||||||
allow(helper).to receive(:env).and_return({})
|
allow(helper).to receive(:env).and_return({})
|
||||||
|
@ -830,7 +830,7 @@ RSpec.describe API::Helpers do
|
||||||
it 'retrieves a CDN-fronted URL' do
|
it 'retrieves a CDN-fronted URL' do
|
||||||
expect(artifact.file).to receive(:cdn_enabled_url).and_call_original
|
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(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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -841,7 +841,7 @@ RSpec.describe API::Helpers do
|
||||||
file = double(url: url)
|
file = double(url: url)
|
||||||
|
|
||||||
expect(Gitlab::ApplicationContext).not_to receive(:push)
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -527,7 +527,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with Redis cookies' do
|
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) }
|
let(:cookie) { get_redis_msgpack(cookie_key) }
|
||||||
|
|
||||||
def with_redis(&block)
|
def with_redis(&block)
|
||||||
|
|
|
@ -85,4 +85,10 @@ RSpec.describe CommitSignatures::GpgSignature do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#user' do
|
||||||
|
it 'retrieves the gpg_key user' do
|
||||||
|
expect(signature.user).to eq(gpg_key.user)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -389,8 +389,7 @@ RSpec.describe API::Ci::JobArtifacts do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when Google CDN is enabled' do
|
context 'when Google CDN is configured' do
|
||||||
let(:cdn_enabled) { true }
|
|
||||||
let(:cdn_config) do
|
let(:cdn_config) do
|
||||||
{
|
{
|
||||||
'provider' => 'Google',
|
'provider' => 'Google',
|
||||||
|
@ -401,7 +400,6 @@ RSpec.describe API::Ci::JobArtifacts do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_feature_flags(ci_job_artifacts_cdn: cdn_enabled)
|
|
||||||
stub_object_storage_uploader(config: Gitlab.config.artifacts.object_store,
|
stub_object_storage_uploader(config: Gitlab.config.artifacts.object_store,
|
||||||
uploader: JobArtifactUploader,
|
uploader: JobArtifactUploader,
|
||||||
proxy_download: proxy_download,
|
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}")
|
expect(response.redirect_url).to start_with("https://cdn.example.org/#{artifact.file.path}")
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
context 'authorized user' do
|
context 'authorized user' do
|
||||||
|
|
|
@ -4,7 +4,8 @@ require 'spec_helper'
|
||||||
RSpec.describe 'getting a tree in a project' do
|
RSpec.describe 'getting a tree in a project' do
|
||||||
include GraphqlHelpers
|
include GraphqlHelpers
|
||||||
|
|
||||||
let(:project) { create(:project, :repository) }
|
let_it_be(:project) { create(:project, :repository) }
|
||||||
|
|
||||||
let(:current_user) { project.first_owner }
|
let(:current_user) { project.first_owner }
|
||||||
let(:path) { "" }
|
let(:path) { "" }
|
||||||
let(:ref) { "master" }
|
let(:ref) { "master" }
|
||||||
|
@ -82,6 +83,89 @@ RSpec.describe 'getting a tree in a project' do
|
||||||
end
|
end
|
||||||
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
|
context 'when current user is nil' do
|
||||||
it 'returns empty project' do
|
it 'returns empty project' do
|
||||||
post_graphql(query, current_user: nil)
|
post_graphql(query, current_user: nil)
|
||||||
|
|
|
@ -11,6 +11,8 @@ module TestEnv
|
||||||
# When developing the seed repository, comment out the branch you will modify.
|
# When developing the seed repository, comment out the branch you will modify.
|
||||||
BRANCH_SHA = {
|
BRANCH_SHA = {
|
||||||
'signed-commits' => 'c7794c1',
|
'signed-commits' => 'c7794c1',
|
||||||
|
'gpg-signed' => '8a852d5',
|
||||||
|
'x509-signed' => 'a4df3c8',
|
||||||
'not-merged-branch' => 'b83d6e3',
|
'not-merged-branch' => 'b83d6e3',
|
||||||
'branch-merged' => '498214d',
|
'branch-merged' => '498214d',
|
||||||
'empty-branch' => '7efb185',
|
'empty-branch' => '7efb185',
|
||||||
|
|
|
@ -26,7 +26,7 @@ RSpec.describe JobArtifactUploader do
|
||||||
|
|
||||||
describe '#cdn_enabled_url' do
|
describe '#cdn_enabled_url' do
|
||||||
it 'returns URL and false' 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
|
expect(result.used_cdn).to be false
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,30 +44,13 @@ RSpec.describe ObjectStorage::CDN do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#cdn_enabled_url' do
|
describe '#cdn_enabled_url' do
|
||||||
context 'with ci_job_artifacts_cdn feature flag disabled' do
|
it 'calls #cdn_signed_url' do
|
||||||
before do
|
expect(subject).not_to receive(:url)
|
||||||
stub_feature_flags(ci_job_artifacts_cdn: false)
|
expect(subject).to receive(:cdn_signed_url).and_call_original
|
||||||
end
|
|
||||||
|
|
||||||
it 'calls #url' do
|
result = subject.cdn_enabled_url(public_ip)
|
||||||
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 true
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
expect(result.used_cdn).to be true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue