Skip to content
Snippets Groups Projects
Commit f201a735 authored by Aishwarya's avatar Aishwarya Committed by Fabio Pitino
Browse files

Evaluate group level compliance pipeline configuration

If a compliance framework label has been applied
to a project, and the framework as a compliance pipeline
configuration path defined - we trigger the compliance
pipeline for the project. The compliance pipeline
configuration can in turn include the project's
.gitlab-ci.yml file to be run after the compliance runs.
parent 523db65a
No related branches found
No related tags found
No related merge requests found
Showing
with 264 additions and 12 deletions
Loading
Loading
@@ -71,7 +71,8 @@ def self.config_sources
remote_source: 4,
external_project_source: 5,
bridge_source: 6,
parameter_source: 7
parameter_source: 7,
compliance_source: 8
}
end
end
Loading
Loading
Loading
Loading
@@ -3948,7 +3948,7 @@ type ComplianceFramework {
 
"""
Full path of the compliance pipeline configuration stored in a project
repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`.
repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`.
"""
pipelineConfigurationFullPath: String
}
Loading
Loading
@@ -4006,7 +4006,7 @@ input ComplianceFrameworkInput {
 
"""
Full path of the compliance pipeline configuration stored in a project
repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`.
repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`.
"""
pipelineConfigurationFullPath: String
}
Loading
Loading
@@ -18093,7 +18093,7 @@ type Pipeline {
"""
Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE,
AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE,
BRIDGE_SOURCE, PARAMETER_SOURCE)
BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE)
"""
configSource: PipelineConfigSourceEnum
 
Loading
Loading
@@ -18364,6 +18364,7 @@ type PipelineCancelPayload {
enum PipelineConfigSourceEnum {
AUTO_DEVOPS_SOURCE
BRIDGE_SOURCE
COMPLIANCE_SOURCE
EXTERNAL_PROJECT_SOURCE
PARAMETER_SOURCE
REMOTE_SOURCE
Loading
Loading
Loading
Loading
@@ -10763,7 +10763,7 @@
},
{
"name": "pipelineConfigurationFullPath",
"description": "Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`.",
"description": "Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`.",
"args": [
 
],
Loading
Loading
@@ -10933,7 +10933,7 @@
},
{
"name": "pipelineConfigurationFullPath",
"description": "Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`.",
"description": "Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`.",
"type": {
"kind": "SCALAR",
"name": "String",
Loading
Loading
@@ -53230,7 +53230,7 @@
},
{
"name": "configSource",
"description": "Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE)",
"description": "Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE)",
"args": [
 
],
Loading
Loading
@@ -54127,6 +54127,12 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "COMPLIANCE_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"possibleTypes": null
Loading
Loading
@@ -629,7 +629,7 @@ Represents a ComplianceFramework associated with a Project.
| `description` | String! | Description of the compliance framework. |
| `id` | ID! | Compliance framework ID. |
| `name` | String! | Name of the compliance framework. |
| `pipelineConfigurationFullPath` | String | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`. |
| `pipelineConfigurationFullPath` | String | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`. |
 
### ComposerMetadata
 
Loading
Loading
@@ -2759,7 +2759,7 @@ Information about pagination in a connection..
| `beforeSha` | String | Base SHA of the source branch. |
| `cancelable` | Boolean! | Specifies if a pipeline can be canceled. |
| `committedAt` | Time | Timestamp of the pipeline's commit. |
| `configSource` | PipelineConfigSourceEnum | Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE) |
| `configSource` | PipelineConfigSourceEnum | Configuration source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE, COMPLIANCE_SOURCE) |
| `coverage` | Float | Coverage percentage. |
| `createdAt` | Time! | Timestamp of the pipeline's creation. |
| `detailedStatus` | DetailedStatus! | Detailed status of the pipeline. |
Loading
Loading
@@ -5168,6 +5168,7 @@ Rotation length unit of an on-call rotation.
| ----- | ----------- |
| `AUTO_DEVOPS_SOURCE` | |
| `BRIDGE_SOURCE` | |
| `COMPLIANCE_SOURCE` | |
| `EXTERNAL_PROJECT_SOURCE` | |
| `PARAMETER_SOURCE` | |
| `REMOTE_SOURCE` | |
Loading
Loading
Loading
Loading
@@ -24,7 +24,7 @@ class ComplianceFrameworkInputType < BaseInputObject
argument :pipeline_configuration_full_path,
GraphQL::STRING_TYPE,
required: false,
description: 'Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`.'
description: 'Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`.'
end
end
end
Loading
Loading
@@ -25,7 +25,7 @@ class ComplianceFrameworkType < Types::BaseObject
 
field :pipeline_configuration_full_path, GraphQL::STRING_TYPE,
null: true,
description: 'Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/compliance/soc2/.gitlab-ci.yml`.'
description: 'Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hippa`.'
end
end
end
Loading
Loading
@@ -173,6 +173,7 @@ class License < ApplicationRecord
subepics
threat_monitoring
vulnerability_auto_fix
evaluate_group_level_compliance_pipeline
]
EEU_FEATURES.freeze
 
Loading
Loading
---
name: ff_evaluate_group_level_compliance_pipeline
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52629
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/300324
milestone: '13.9'
type: development
group: group::compliance
default_enabled: false
# frozen_string_literal: true
module EE
module Gitlab
module Ci
module Pipeline
module Chain
module Config
module Content
extend ::Gitlab::Utils::Override
EE_SOURCES = [::Gitlab::Ci::Pipeline::Chain::Config::Content::Compliance].freeze
private
override :sources
def sources
EE_SOURCES + super
end
end
end
end
end
end
end
end
# frozen_string_literal: true
module Gitlab
module Ci
module Pipeline
module Chain
module Config
class Content
class Compliance < Source
def content
strong_memoize(:content) do
next unless available?
next unless pipeline_configuration_full_path
path_file, path_project = pipeline_configuration_full_path.split('@', 2)
YAML.dump('include' => [{ 'project' => path_project, 'file' => path_file }])
end
end
def source
:compliance_source
end
private
def pipeline_configuration_full_path
strong_memoize(:pipeline_configuration_full_path) do
next unless project
project.compliance_pipeline_configuration_full_path
end
end
def available?
project.feature_available?(:evaluate_group_level_compliance_pipeline) &&
::Feature.enabled?(:ff_evaluate_group_level_compliance_pipeline, project, default_enabled: :yaml)
end
end
end
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Config::Content do
let(:ci_config_path) { nil }
let(:pipeline) { build(:ci_pipeline, project: project) }
let(:content) { nil }
let(:source) { :push }
let(:command) { Gitlab::Ci::Pipeline::Chain::Command.new(project: project, content: content, source: source) }
subject { described_class.new(pipeline, command) }
let(:content_result) do
<<~EOY
---
include:
- project: compliance/hippa
file: ".compliance-gitlab-ci.yml"
EOY
end
shared_examples 'does not include compliance pipeline configuration content' do
it do
subject.perform!
expect(pipeline.config_source).not_to eq 'compliance_source'
expect(pipeline.pipeline_config.content).not_to eq(content_result)
expect(command.config_content).not_to eq(content_result)
end
end
context 'when project has compliance pipeline configuration defined' do
let(:project) { create(:project, ci_config_path: ci_config_path) }
let(:compliance_group) { create(:group, :private, name: "compliance") }
let(:compliance_project) { create(:project, namespace: compliance_group, name: "hippa") }
let(:framework) { create(:compliance_framework, namespace_id: compliance_group.id, pipeline_configuration_full_path: ".compliance-gitlab-ci.yml@compliance/hippa") }
let!(:framework_project_setting) { create(:compliance_framework_project_setting, project: project, framework_id: framework.id) }
context 'when feature is available' do
before do
stub_feature_flags(ff_evaluate_group_level_compliance_pipeline: true)
stub_licensed_features(evaluate_group_level_compliance_pipeline: true)
end
it 'includes compliance pipeline configuration content' do
subject.perform!
expect(pipeline.config_source).to eq 'compliance_source'
expect(pipeline.pipeline_config.content).to eq(content_result)
expect(command.config_content).to eq(content_result)
end
end
context 'when feature is not available' do
using RSpec::Parameterized::TableSyntax
where(:licensed, :feature_flag) do
true | false
false | true
false | false
end
with_them do
before do
stub_feature_flags(ff_evaluate_group_level_compliance_pipeline: licensed)
stub_licensed_features(evaluate_group_level_compliance_pipeline: feature_flag)
end
it_behaves_like 'does not include compliance pipeline configuration content'
end
end
end
context 'when project does not have compliance label defined' do
let(:project) { create(:project, ci_config_path: ci_config_path) }
context 'when feature is available' do
before do
stub_feature_flags(ff_evaluate_group_level_compliance_pipeline: true)
stub_licensed_features(evaluate_group_level_compliance_pipeline: true)
end
it_behaves_like 'does not include compliance pipeline configuration content'
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService do
include AfterNextHelpers
subject(:execute) { service.execute(:push) }
let(:project) { create(:project, :repository, name: 'website') }
let(:user) { project.owner }
let(:compliance_group) { create(:group, :private, name: "compliance") }
let(:compliance_project) { create(:project, :repository, namespace: compliance_group, name: "hippa") }
let(:framework) { create(:compliance_framework, namespace_id: compliance_group.id, pipeline_configuration_full_path: ".compliance-gitlab-ci.yml@compliance/hippa") }
let!(:framework_project_setting) { create(:compliance_framework_project_setting, project: project, framework_id: framework.id) }
let!(:ref_sha) { compliance_project.commit('HEAD').sha }
let(:compliance_config) do
<<~EOY
---
compliance_build:
stage: build
script:
- echo 'hello from compliance build'
compliance_test:
stage: test
script:
- echo 'hello from compliance test'
EOY
end
let(:service) { described_class.new(project, user, { ref: 'master' }) }
before do
stub_feature_flags(ff_evaluate_group_level_compliance_pipeline: true)
stub_licensed_features(evaluate_group_level_compliance_pipeline: true)
allow_next(Repository).to receive(:blob_data_at).with(ref_sha, '.compliance-gitlab-ci.yml').and_return(compliance_config)
end
context 'when user has access to compliance project' do
before do
compliance_project.add_maintainer(project.owner)
end
it 'persists pipeline' do
is_expected.to be_persisted
end
it 'sets the correct source' do
expect(execute.config_source).to eq("compliance_source")
end
it 'persists jobs' do
expect { execute }.to change(Ci::Build, :count).from(0).to(2)
end
it do
expect(execute.processables.map(&:name)).to eq(%w(compliance_build compliance_test))
end
end
context 'when user does not have access to compliance project' do
it 'includes access denied error' do
expect(execute.yaml_errors).to eq "Project `compliance/hippa` not found or access denied!"
end
it 'does not persist jobs' do
expect { execute }.not_to change(Ci::Build, :count).from(0)
end
end
end
Loading
Loading
@@ -34,16 +34,22 @@ def break?
private
 
def find_config
SOURCES.each do |source|
sources.each do |source|
config = source.new(@pipeline, @command)
return config if config.exists?
end
 
nil
end
def sources
SOURCES
end
end
end
end
end
end
end
Gitlab::Ci::Pipeline::Chain::Config::Content.prepend_if_ee('EE::Gitlab::Ci::Pipeline::Chain::Config::Content')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment