Commit 3fcaabc3 authored by Zamir Martins's avatar Zamir Martins Committed by Bob Van Landuyt

Extract scan execution policy related code

parent 5fab6ac5
# frozen_string_literal: true
module Security
module ScanExecutionPolicy
extend ActiveSupport::Concern
include ::Gitlab::Utils::StrongMemoize
POLICY_LIMIT = 5
RULE_TYPES = {
pipeline: 'pipeline',
schedule: 'schedule'
}.freeze
SCAN_TYPES = %w[dast secret_detection cluster_image_scanning container_scanning].freeze
ON_DEMAND_SCANS = %w[dast].freeze
included do
has_many :rule_schedules,
class_name: 'Security::OrchestrationPolicyRuleSchedule',
foreign_key: :security_orchestration_policy_configuration_id,
inverse_of: :security_orchestration_policy_configuration
end
def self.valid_scan_type?(scan_type)
SCAN_TYPES.include?(scan_type)
end
def active_scan_execution_policies
return [] unless enabled?
scan_execution_policy.select { |config| config[:enabled] }.first(POLICY_LIMIT)
end
def on_demand_scan_actions(ref)
active_policies_scan_actions(ref).select { |action| action[:scan].in?(ON_DEMAND_SCANS) }
end
def pipeline_scan_actions(ref)
active_policies_scan_actions(ref).reject { |action| action[:scan].in?(ON_DEMAND_SCANS) }
end
def active_policy_names_with_dast_site_profile(profile_name)
active_policy_names_with_dast_profiles.dig(:site_profiles, profile_name)
end
def active_policy_names_with_dast_scanner_profile(profile_name)
active_policy_names_with_dast_profiles.dig(:scanner_profiles, profile_name)
end
def delete_all_schedules
rule_schedules.delete_all(:delete_all)
end
def scan_execution_policy
policy_by_type(:scan_execution_policy)
end
private
def active_policy_names_with_dast_profiles
strong_memoize(:active_policy_names_with_dast_profiles) do
profiles = { site_profiles: Hash.new { Set.new }, scanner_profiles: Hash.new { Set.new } }
active_scan_execution_policies.each do |policy|
policy[:actions].each do |action|
next unless action[:scan].in?(ON_DEMAND_SCANS)
profiles[:site_profiles][action[:site_profile]] += [policy[:name]]
profiles[:scanner_profiles][action[:scanner_profile]] += [policy[:name]] if action[:scanner_profile].present?
end
end
profiles
end
end
def active_policies_scan_actions(ref)
active_scan_execution_policies
.select { |policy| applicable_for_ref?(policy, ref) }
.flat_map { |policy| policy[:actions] }
end
def applicable_for_ref?(policy, ref)
return false unless Gitlab::Git.branch_ref?(ref)
branch_name = Gitlab::Git.ref_name(ref)
policy[:rules].any? do |rule|
rule[:type] == RULE_TYPES[:pipeline] && rule[:branches].any? { |branch| RefMatcher.new(branch).matches?(branch_name) }
end
end
end
end
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
module Security module Security
class OrchestrationPolicyConfiguration < ApplicationRecord class OrchestrationPolicyConfiguration < ApplicationRecord
include Security::ScanExecutionPolicy
include EachBatch include EachBatch
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
...@@ -9,25 +10,11 @@ module Security ...@@ -9,25 +10,11 @@ module Security
POLICY_PATH = '.gitlab/security-policies/policy.yml' POLICY_PATH = '.gitlab/security-policies/policy.yml'
POLICY_SCHEMA_PATH = 'ee/app/validators/json_schemas/security_orchestration_policy.json' POLICY_SCHEMA_PATH = 'ee/app/validators/json_schemas/security_orchestration_policy.json'
POLICY_LIMIT = 5
RULE_TYPES = {
pipeline: 'pipeline',
schedule: 'schedule'
}.freeze
SCAN_TYPES = %w[dast secret_detection cluster_image_scanning container_scanning].freeze
ON_DEMAND_SCANS = %w[dast].freeze
AVAILABLE_POLICY_TYPES = %i{scan_execution_policy}.freeze AVAILABLE_POLICY_TYPES = %i{scan_execution_policy}.freeze
belongs_to :project, inverse_of: :security_orchestration_policy_configuration belongs_to :project, inverse_of: :security_orchestration_policy_configuration
belongs_to :security_policy_management_project, class_name: 'Project', foreign_key: 'security_policy_management_project_id' belongs_to :security_policy_management_project, class_name: 'Project', foreign_key: 'security_policy_management_project_id'
has_many :rule_schedules,
class_name: 'Security::OrchestrationPolicyRuleSchedule',
foreign_key: :security_orchestration_policy_configuration_id,
inverse_of: :security_orchestration_policy_configuration
validates :project, presence: true, uniqueness: true validates :project, presence: true, uniqueness: true
validates :security_policy_management_project, presence: true validates :security_policy_management_project, presence: true
...@@ -41,10 +28,6 @@ module Security ...@@ -41,10 +28,6 @@ module Security
self.exists?(security_policy_management_project_id: project_id) self.exists?(security_policy_management_project_id: project_id)
end end
def self.valid_scan_type?(scan_type)
SCAN_TYPES.include?(scan_type)
end
def enabled? def enabled?
::Feature.enabled?(:security_orchestration_policies_configuration, project, default_enabled: :yaml) ::Feature.enabled?(:security_orchestration_policies_configuration, project, default_enabled: :yaml)
end end
...@@ -67,28 +50,6 @@ module Security ...@@ -67,28 +50,6 @@ module Security
.valid?(policy.to_h.deep_stringify_keys) .valid?(policy.to_h.deep_stringify_keys)
end end
def active_policies
return [] unless enabled?
scan_execution_policy.select { |config| config[:enabled] }.first(POLICY_LIMIT)
end
def on_demand_scan_actions(ref)
active_policies_scan_actions(ref).select { |action| action[:scan].in?(ON_DEMAND_SCANS) }
end
def pipeline_scan_actions(ref)
active_policies_scan_actions(ref).reject { |action| action[:scan].in?(ON_DEMAND_SCANS) }
end
def active_policy_names_with_dast_site_profile(profile_name)
active_policy_names_with_dast_profiles.dig(:site_profiles, profile_name)
end
def active_policy_names_with_dast_scanner_profile(profile_name)
active_policy_names_with_dast_profiles.dig(:scanner_profiles, profile_name)
end
def policy_last_updated_by def policy_last_updated_by
strong_memoize(:policy_last_updated_by) do strong_memoize(:policy_last_updated_by) do
policy_repo.last_commit_for_path(default_branch_or_main, POLICY_PATH)&.author policy_repo.last_commit_for_path(default_branch_or_main, POLICY_PATH)&.author
...@@ -101,20 +62,12 @@ module Security ...@@ -101,20 +62,12 @@ module Security
end end
end end
def delete_all_schedules
rule_schedules.delete_all(:delete_all)
end
def policy_by_type(type) def policy_by_type(type)
return [] if policy_hash.blank? return [] if policy_hash.blank?
policy_hash.fetch(type, []) policy_hash.fetch(type, [])
end end
def scan_execution_policy
policy_by_type(:scan_execution_policy)
end
def default_branch_or_main def default_branch_or_main
security_policy_management_project.default_branch_or_main security_policy_management_project.default_branch_or_main
end end
...@@ -125,43 +78,10 @@ module Security ...@@ -125,43 +78,10 @@ module Security
security_policy_management_project.repository security_policy_management_project.repository
end end
def active_policy_names_with_dast_profiles
strong_memoize(:active_policy_names_with_dast_profiles) do
profiles = { site_profiles: Hash.new { Set.new }, scanner_profiles: Hash.new { Set.new } }
active_policies.each do |policy|
policy[:actions].each do |action|
next unless action[:scan].in?(ON_DEMAND_SCANS)
profiles[:site_profiles][action[:site_profile]] += [policy[:name]]
profiles[:scanner_profiles][action[:scanner_profile]] += [policy[:name]] if action[:scanner_profile].present?
end
end
profiles
end
end
def active_policies_scan_actions(ref)
active_policies
.select { |policy| applicable_for_ref?(policy, ref) }
.flat_map { |policy| policy[:actions] }
end
def policy_blob def policy_blob
strong_memoize(:policy_blob) do strong_memoize(:policy_blob) do
policy_repo.blob_data_at(default_branch_or_main, POLICY_PATH) policy_repo.blob_data_at(default_branch_or_main, POLICY_PATH)
end end
end end
def applicable_for_ref?(policy, ref)
return false unless Gitlab::Git.branch_ref?(ref)
branch_name = Gitlab::Git.ref_name(ref)
policy[:rules].any? do |rule|
rule[:type] == RULE_TYPES[:pipeline] && rule[:branches].any? { |branch| RefMatcher.new(branch).matches?(branch_name) }
end
end
end end
end end
...@@ -28,7 +28,7 @@ module Security ...@@ -28,7 +28,7 @@ module Security
def policy def policy
strong_memoize(:policy) do strong_memoize(:policy) do
security_orchestration_policy_configuration.active_policies.at(policy_index) security_orchestration_policy_configuration.active_scan_execution_policies.at(policy_index)
end end
end end
......
...@@ -23,7 +23,7 @@ module Security ...@@ -23,7 +23,7 @@ module Security
return unless policy_configuration.enabled? return unless policy_configuration.enabled?
policy[:rules].each_with_index do |rule, rule_index| policy[:rules].each_with_index do |rule, rule_index|
next if rule[:type] != Security::OrchestrationPolicyConfiguration::RULE_TYPES[:schedule] next if rule[:type] != Security::ScanExecutionPolicy::RULE_TYPES[:schedule]
Security::OrchestrationPolicyRuleSchedule Security::OrchestrationPolicyRuleSchedule
.create!( .create!(
......
...@@ -22,7 +22,7 @@ module Security ...@@ -22,7 +22,7 @@ module Security
private private
def valid_scan_type?(scan_type) def valid_scan_type?(scan_type)
::Security::OrchestrationPolicyConfiguration.valid_scan_type?(scan_type) Security::ScanExecutionPolicy.valid_scan_type?(scan_type)
end end
def prepare_policy_configuration(action, index) def prepare_policy_configuration(action, index)
......
...@@ -20,7 +20,7 @@ module Security ...@@ -20,7 +20,7 @@ module Security
next next
end end
configuration.active_policies.each_with_index do |policy, policy_index| configuration.active_scan_execution_policies.each_with_index do |policy, policy_index|
Security::SecurityOrchestrationPolicies::ProcessRuleService Security::SecurityOrchestrationPolicies::ProcessRuleService
.new(policy_configuration: configuration, policy_index: policy_index, policy: policy) .new(policy_configuration: configuration, policy_index: policy_index, policy: policy)
.execute .execute
......
...@@ -73,11 +73,11 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do ...@@ -73,11 +73,11 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
describe '.valid_scan_type?' do describe '.valid_scan_type?' do
it 'returns true when scan type is valid' do it 'returns true when scan type is valid' do
expect(described_class.valid_scan_type?('secret_detection')).to be_truthy expect(Security::ScanExecutionPolicy.valid_scan_type?('secret_detection')).to be_truthy
end end
it 'returns false when scan type is invalid' do it 'returns false when scan type is invalid' do
expect(described_class.valid_scan_type?('invalid')).to be_falsey expect(Security::ScanExecutionPolicy.valid_scan_type?('invalid')).to be_falsey
end end
end end
...@@ -206,7 +206,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do ...@@ -206,7 +206,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
] ]
end end
subject(:active_policies) { security_orchestration_policy_configuration.active_policies } subject(:active_scan_execution_policies) { security_orchestration_policy_configuration.active_scan_execution_policies }
before do before do
allow(security_policy_management_project).to receive(:repository).and_return(repository) allow(security_policy_management_project).to receive(:repository).and_return(repository)
...@@ -214,7 +214,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do ...@@ -214,7 +214,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
end end
it 'returns only enabled policies' do it 'returns only enabled policies' do
expect(active_policies).to eq(expected_active_policies) expect(active_scan_execution_policies).to eq(expected_active_policies)
end end
context 'when feature is disabled' do context 'when feature is disabled' do
...@@ -223,7 +223,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do ...@@ -223,7 +223,7 @@ RSpec.describe Security::OrchestrationPolicyConfiguration do
end end
it 'returns empty array' do it 'returns empty array' do
expect(active_policies).to eq([]) expect(active_scan_execution_policies).to eq([])
end end
end end
end end
......
...@@ -29,7 +29,7 @@ RSpec.describe Security::SecurityOrchestrationPolicies::RuleScheduleService do ...@@ -29,7 +29,7 @@ RSpec.describe Security::SecurityOrchestrationPolicies::RuleScheduleService do
project.repository.create_branch('production', project.default_branch) project.repository.create_branch('production', project.default_branch)
allow_next_instance_of(Security::OrchestrationPolicyConfiguration) do |instance| allow_next_instance_of(Security::OrchestrationPolicyConfiguration) do |instance|
allow(instance).to receive(:active_policies).and_return([policy]) allow(instance).to receive(:active_scan_execution_policies).and_return([policy])
end end
end end
......
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