Add `branch_type` support to Scan execution policies
Summary
We are adding branch_type
support to security policies (&9468 (closed)).
Our implementation needs to support group-level protected branches (&8679).
Implementation Plan
A proof-of-concept can be found on the 9468-branch-expressions branch.
-
backend Add or use the feature flag
security_policies_branch_type
. If disabled for an actor,branch_type
rules are skipped from processing. -
backend Extend the schema so that policy rules provide either
branches
orbranch_types
. -
backend Change
ValidatePolicyService
to validate that eitherbranches
orbranch_types
are provided.
diff --git ee/app/services/security/security_orchestration_policies/validate_policy_service.rb
@@ -40,7 +40,7 @@ def blank_name?
def blank_branch_for_rule?
return false if policy_type == :scan_result_policy
- policy[:rules].any? { |rule| rule[:agents].blank? && rule[:branches].blank? }
+ policy[:rules].any? { |rule| rule[:agents].blank? && rule[:branches].blank? && rule[:branch_type].blank? }
end
def missing_branch_for_rule?
-
backend Implement a service
PolicyBranchesService
that accepts as inputs (1) a list of policy rules and (2) a project. The output of the service is a list of all branch names present in the project's repository as matched by the provided rules.
type: pipeline
-
backend Change
ScanExecutionPolicy#active_policies_scan_actions
to usePolicyBranchesService
to determine if a ref is in the set of matched branches.
diff --git ee/app/models/concerns/security/scan_execution_policy.rb b/ee/app/models/concerns/security/scan_execution_policy.rb
@@ -46,9 +46,9 @@ def scan_execution_policy
policy_by_type(:scan_execution_policy)
end
- def active_policies_scan_actions(ref)
+ def active_policies_scan_actions(ref, project)
active_scan_execution_policies
- .select { |policy| applicable_for_ref?(policy, ref) }
+ .select { |policy| applicable_for_ref?(policy, ref, project) }
.flat_map { |policy| policy[:actions] }
end
@@ -71,14 +71,14 @@ def active_policy_names_with_dast_profiles
end
end
- def applicable_for_ref?(policy, ref)
+ def applicable_for_ref?(policy, ref, project)
return false unless Gitlab::Git.branch_ref?(ref)
- branch_name = Gitlab::Git.ref_name(ref)
+ ref_name = Gitlab::Git.ref_name(ref)
+ pipeline_rules = policy[:rules].select { |rule| rule[:type] == RULE_TYPES[:pipeline] }
- policy[:rules].any? do |rule|
- rule[:type] == RULE_TYPES[:pipeline] && rule[:branches].any? { |branch| RefMatcher.new(branch).matches?(branch_name) }
- end
+ applicable_branches = Security::SecurityOrchestrationPolicies::PolicyBranchesService.new(pipeline_rules, project).execute
+ ref_name.in?(applicable_branches)
end
end
end
diff --git ee/lib/gitlab/ci/config/security_orchestration_policies/processor.rb
@@ -103,7 +103,7 @@ def insert_scan_policy_stage_after_build_stage_or_first(defined_stages)
def active_scan_actions
scan_actions do |configuration|
- configuration.active_policies_scan_actions(@ref)
+ configuration.active_policies_scan_actions(@ref, project)
end
end
type: schedule
-
backend Change
OrchestrationPolicyRuleSchedule#applicable_branches
to usePolicyBranchesService
to determine applicable branches.
diff --git ee/app/models/security/orchestration_policy_rule_schedule.rb b/ee/app/models/security/orchestration_policy_rule_schedule.rb
@@ -37,14 +37,11 @@ def policy
end
def applicable_branches(project = security_orchestration_policy_configuration.project)
- configured_branches = policy&.dig(:rules, rule_index, :branches)
- return [] if configured_branches.blank? || project.blank?
-
- branch_names = project.repository.branches
-
- configured_branches
- .flat_map { |pattern| RefMatcher.new(pattern).matching(branch_names).map(&:name) }
- .uniq
+ # rubocop: disable CodeReuse/ServiceClass
+ Security::SecurityOrchestrationPolicies::PolicyBranchesService
+ .new(policy[:rules], project)
+ .execute
+ # rubocop: enable CodeReuse/ServiceClass
end
def applicable_agents
Edited by Dominic Bauer