Commit c4b66de9 authored by Etienne Baqué's avatar Etienne Baqué

Merge branch 'sk/355891-fix-scan-policy-stage' into 'master'

Add default scan execution policies stage to pipeline

See merge request gitlab-org/gitlab!84640
parents 8807facf 74ab5b3c
......@@ -5,6 +5,13 @@ module Gitlab
class Config
module SecurityOrchestrationPolicies
class Processor
DEFAULT_ON_DEMAND_STAGE = 'dast'
DEFAULT_SECURITY_JOB_STAGE = 'test'
DEFAULT_BUILD_STAGE = 'build'
DEFAULT_SCAN_POLICY_STAGE = 'scan-policies'
DEFAULT_STAGES = Gitlab::Ci::Config::Entry::Stages.default
def initialize(config, project, ref, source)
@config = config
@project = project
......@@ -18,9 +25,7 @@ module Gitlab
return @config if valid_security_orchestration_policy_configurations.blank?
return @config unless extend_configuration?
merged_config = @config
.deep_merge(on_demand_scans_template)
.deep_merge(pipeline_scan_template)
merged_config = @config.deep_merge(merge_policies_with_stages(@config))
observe_processing_duration(Time.current - @start)
......@@ -38,31 +43,79 @@ module Gitlab
all_security_orchestration_policy_configurations&.select(&:policy_configuration_valid?)
end
def on_demand_scans_template
def prepare_on_demand_scans_template
::Security::SecurityOrchestrationPolicies::OnDemandScanPipelineConfigurationService
.new(project)
.execute(on_demand_scan_actions)
end
def pipeline_scan_template
def prepare_pipeline_scans_template
::Security::SecurityOrchestrationPolicies::ScanPipelineService
.new.execute(pipeline_scan_actions)
end
def on_demand_scan_actions
return [] if valid_security_orchestration_policy_configurations.blank?
## Add `dast` to the end of stages if `dast` is not in stages already
## For other scan types, add `scan-policies` stage after `build` stage if `test` stage is not defined
def merge_policies_with_stages(config)
merged_config = config
defined_stages = config[:stages].presence || DEFAULT_STAGES
valid_security_orchestration_policy_configurations
.flat_map { |security_orchestration_policy_configuration| security_orchestration_policy_configuration.on_demand_scan_actions(@ref) }
.compact
.uniq
merge_on_demand_scan_template(merged_config, defined_stages)
merge_pipeline_scan_template(merged_config, defined_stages)
merged_config[:stages] = defined_stages.uniq if (defined_stages - DEFAULT_STAGES).present?
merged_config
end
def merge_on_demand_scan_template(merged_config, defined_stages)
on_demand_scan_template = prepare_on_demand_scans_template
if on_demand_scan_template.present?
defined_stages << DEFAULT_ON_DEMAND_STAGE
merged_config.deep_merge!(on_demand_scan_template)
end
end
def merge_pipeline_scan_template(merged_config, defined_stages)
pipeline_scan_template = prepare_pipeline_scans_template
if pipeline_scan_template.present?
unless defined_stages.include?(DEFAULT_SECURITY_JOB_STAGE)
insert_scan_policy_stage_after_build_stage_or_first(defined_stages)
pipeline_scan_template = pipeline_scan_template.transform_values { |job_config| job_config.merge(stage: DEFAULT_SCAN_POLICY_STAGE) }
end
merged_config.deep_merge!(pipeline_scan_template)
end
end
def insert_scan_policy_stage_after_build_stage_or_first(defined_stages)
build_stage_index = defined_stages.index(DEFAULT_BUILD_STAGE)
if build_stage_index.nil?
defined_stages.unshift(DEFAULT_SCAN_POLICY_STAGE)
else
defined_stages.insert(build_stage_index + 1, DEFAULT_SCAN_POLICY_STAGE)
end
defined_stages
end
def on_demand_scan_actions
scan_actions do |security_orchestration_policy_configuration|
security_orchestration_policy_configuration.on_demand_scan_actions(@ref)
end
end
def pipeline_scan_actions
scan_actions do |security_orchestration_policy_configuration|
security_orchestration_policy_configuration.pipeline_scan_actions(@ref)
end
end
def scan_actions
return [] if valid_security_orchestration_policy_configurations.blank?
valid_security_orchestration_policy_configurations
.flat_map { |security_orchestration_policy_configuration| security_orchestration_policy_configuration.pipeline_scan_actions(@ref) }
.flat_map { |security_orchestration_policy_configuration| yield(security_orchestration_policy_configuration) }
.compact
.uniq
end
......
......@@ -11,6 +11,7 @@ RSpec.describe Gitlab::Ci::Config::SecurityOrchestrationPolicies::Processor do
let(:ref) { 'refs/heads/master' }
let(:source) { 'pipeline' }
let(:scan_policy_stage) { 'test' }
let_it_be(:namespace) { create(:group) }
let_it_be(:namespace_policies_repository) { create(:project, :repository) }
......@@ -55,8 +56,44 @@ RSpec.describe Gitlab::Ci::Config::SecurityOrchestrationPolicies::Processor do
end
shared_examples 'with different scan type' do
it 'extends config with additional jobs' do
expect(subject).to include(expected_configuration)
context 'when test stage is available' do
let(:config) { { stages: %w[build test release], image: 'image:1.0.0' } }
it 'does not include scan-policies stage' do
expect(subject[:stages]).to eq(%w[build test release dast])
end
it 'extends config with additional jobs' do
expect(subject).to include(expected_configuration)
end
end
context 'when test stage is not available' do
let(:scan_policy_stage) { 'scan-policies' }
context 'when build stage is available' do
let(:config) { { stages: %w[build not-test release], image: 'image:1.0.0' } }
it 'includes scan-policies stage after build stage' do
expect(subject[:stages]).to eq(%w[build scan-policies not-test release dast])
end
it 'extends config with additional jobs' do
expect(subject).to include(expected_configuration)
end
end
context 'when build stage is not available' do
let(:config) { { stages: %w[not-test release], image: 'image:1.0.0' } }
it 'includes scan-policies stage as a first stage' do
expect(subject[:stages]).to eq(%w[scan-policies not-test release dast])
end
it 'extends config with additional jobs' do
expect(subject).to include(expected_configuration)
end
end
end
end
......@@ -160,7 +197,7 @@ RSpec.describe Gitlab::Ci::Config::SecurityOrchestrationPolicies::Processor do
{
'secret-detection-0': hash_including(
rules: [{ if: '$SECRET_DETECTION_DISABLED', when: 'never' }, { if: '$CI_COMMIT_BRANCH' }],
stage: 'test',
stage: scan_policy_stage,
image: '$SECURE_ANALYZERS_PREFIX/secrets:$SECRETS_ANALYZER_VERSION$SECRET_DETECTION_IMAGE_SUFFIX',
services: [],
allow_failure: true,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment