[backend] Add pipeline execution schedule policy branch filter
Following the introduction of the pipeline execution policy, which allows for enforcing CI jobs/scripts within triggered pipelines, we plan to extend support for scheduled enforcement.
Like scheduled scan execution policies (SEP), we want to be able to start pipelines on specific branches. For SEPs there are two options:
-
branch_typewhich is eitherall,protectedor `default. -
brancheswhich is an array of literal branch names, limited to 5.
We need to analyze the risk of triggering too many pipelines and add limits to branch_type: all and branches.
Implementation Plan
Schema change
Add branch/branch_type fields to schedule objects (see the schema change for schedules).
schedules:
- type: daily
branch_type: default
start_time: "05:00"
end_time: "11:00"
- type: weekly
branches: [rc-*]
days:
- Monday
- Friday
start_time: "02:00"
end_time: "04:00"
backend
diff --git a/ee/app/models/security/pipeline_execution_project_schedule.rb b/ee/app/models/security/pipeline_execution_project_schedule.rb
index c36452f9e1d0..7e7df00d5051 100644
--- a/ee/app/models/security/pipeline_execution_project_schedule.rb
+++ b/ee/app/models/security/pipeline_execution_project_schedule.rb
@@ -47,8 +47,20 @@ def snoozed?
snoozed_until.future?
end
+ def branches
+ return [project.default_branch_or_main] if branches_content.nil?
+
+ branches_content.select { |branch| project.repository.branch_names.include?(branch) }
+ end
+
private
+ def branches_content
+ schedule_content = security_policy.content['schedules']&.first || {}
+
+ schedule_content['branches']
+ end
+
def timezone
security_policy.content.dig('schedule', 'timezone')
end
diff --git a/ee/app/validators/json_schemas/pipeline_execution_schedule_policy_content.json b/ee/app/validators/json_schemas/pipeline_execution_schedule_policy_content.json
index 6c4112313c61..09628f86cd0f 100644
--- a/ee/app/validators/json_schemas/pipeline_execution_schedule_policy_content.json
+++ b/ee/app/validators/json_schemas/pipeline_execution_schedule_policy_content.json
@@ -53,6 +53,15 @@
"daily"
]
},
+ "branches": {
+ "type": "array",
+ "description": "List of branches to run pipelines for (max 5). Pipelines will only be created for branches that exist in the project.",
+ "maxItems": 5,
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ }
+ },
"start_time": {
"type": "string",
"description": "HH:mm format",
@@ -137,6 +146,15 @@
},
"description": "List of days, e.g. ['Monday', 'Friday']"
},
+ "branches": {
+ "type": "array",
+ "description": "List of branches to run pipelines for (max 5). Pipelines will only be created for branches that exist in the project.",
+ "maxItems": 5,
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ }
+ },
"start_time": {
"type": "string",
"description": "HH:mm format",
@@ -215,6 +233,15 @@
},
"description": "Dates within the month, e.g. [3, 10, 17]"
},
+ "branches": {
+ "type": "array",
+ "description": "List of branches to run pipelines for (max 5). Pipelines will only be created for branches that exist in the project.",
+ "maxItems": 5,
+ "uniqueItems": true,
+ "items": {
+ "type": "string"
+ }
+ },
"start_time": {
"type": "string",
"description": "HH:mm format",
diff --git a/ee/app/workers/security/pipeline_execution_policies/run_schedule_worker.rb b/ee/app/workers/security/pipeline_execution_policies/run_schedule_worker.rb
index 4701e85a05e2..5c00fc21c8f6 100644
--- a/ee/app/workers/security/pipeline_execution_policies/run_schedule_worker.rb
+++ b/ee/app/workers/security/pipeline_execution_policies/run_schedule_worker.rb
@@ -26,22 +26,26 @@ def perform(schedule_id)
return
end
- result = execute(schedule)
+ ci_content = schedule.ci_content.deep_stringify_keys.to_yaml
- log_pipeline_creation_failure(result, schedule) if result.error?
+ schedule.branches.each do |branch|
+ result = create_pipeline(schedule, ci_content, branch)
+ track_pipeline_creation_event(schedule, result)
+ log_pipeline_creation_failure(result, schedule) if result.error?
+ end
end
private
- def execute(schedule)
- ci_content = schedule.ci_content.deep_stringify_keys.to_yaml
-
- result = Ci::CreatePipelineService.new(
+ def create_pipeline(schedule, ci_content, ref)
+ Ci::CreatePipelineService.new(
schedule.project,
schedule.project.security_policy_bot,
- ref: schedule.project.default_branch_or_main
+ ref: ref
).execute(PIPELINE_SOURCE, content: ci_content, ignore_skip_ci: true)
+ end
+ def track_pipeline_creation_event(schedule, result)
::Gitlab::InternalEvents.track_event(
'execute_job_scheduled_pipeline_execution_policy',
project: schedule.project,
@@ -49,8 +53,6 @@ def execute(schedule)
label: result.status.to_s
}
)
-
- result
end
def log_pipeline_creation_failure(result, schedule)
@@ -61,7 +63,9 @@ def log_pipeline_creation_failure(result, schedule)
reason: result.reason,
project_id: schedule.project_id,
schedule_id: schedule.id,
- policy_id: schedule.security_policy.id))
+ policy_id: schedule.security_policy.id
+ )
+ )
end
def experiment_enabled?(schedule)
Edited by Andy Schoenen