Commit 74ab5b3c authored by Sashi's avatar Sashi

Add default scan execution policies stage to pipeline

This change adds 'scan-policies' stage to pipeline if
'test' stage is not present. The new stage will be added
after the 'build' stage if it exists. This change also adds
'dast' stage for policy with dast scan type.

EE: true
Changelog: fixed
parent 0433e99a
......@@ -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,11 +56,47 @@ RSpec.describe Gitlab::Ci::Config::SecurityOrchestrationPolicies::Processor do
end
shared_examples 'with different scan type' do
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
shared_examples 'when policy is invalid' do
let_it_be(:policy_yaml) do
build(:orchestration_policy_yaml, scan_execution_policy:
......@@ -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