Define a minimal, stable filter attribute set for the pipeline_hooks flow trigger
Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.
Background
The pipeline_hooks flow trigger (behind the ai_flow_trigger_pipeline_hooks feature flag) already supports customer-configurable filters via a GraphQL mutation. The filter evaluation engine (Ai::FlowTriggers::FilterEvaluator + Gitlab::FilterEvaluator) supports the following operators: eq, ne, gt, lt, contains, not_contains, in, not_in.
Filters are stored as a JSON structure on Ai::FlowTrigger#filter, keyed by hook scope (e.g. pipeline_hooks), and evaluated against the full pipeline webhook payload produced by Gitlab::DataBuilder::Pipeline (the same serializer used for project webhooks).
Today, the Fix CI/CD Pipeline foundational flow uses this mechanism with a built-in precondition (not customer-configurable) that enforces:
{
"match": "all",
"rules": [
{ "field": "object_attributes.status", "operator": "eq", "value": "failed" }
]
}Customers have expressed a need to further scope which failing pipelines trigger the flow — for example, only master-broken failures (source: push && ref: master) or only non-draft MR pipelines (source: merge_request_event && merge_request.title not_contains Draft:).
Problem
The current filter implementation evaluates rules against the entire pipeline webhook payload (Gitlab::DataBuilder::Pipeline). This payload is large and was designed for webhook consumers, not for flow trigger configuration. Exposing it directly to customers creates tight coupling to an internal serialization format that may change, and surfaces many fields that are irrelevant or potentially sensitive in the context of flow triggers.
Before the ai_flow_trigger_pipeline_hooks FF is rolled out broadly, we need to define a minimal, stable set of pipeline attributes that customers can filter on, and validate/allowlist those fields in the filter evaluation path.
Requirements
Filterable attributes (minimum viable set)
The following attributes must be supported as filter fields for the pipeline_hooks trigger:
| Field path | Type | Description | Example values |
|---|---|---|---|
pipeline.source |
string | How the pipeline was triggered | push, merge_request_event, schedule, web, api, trigger |
pipeline.ref |
string | The branch or tag the pipeline ran on | master, main, release/1.0 |
pipeline.merge_request.title |
string | Title of the associated merge request (if any) | "Fix login bug", "Draft: WIP feature" |
Note:
pipeline.statusis already handled by the Fix Pipeline foundational flow's built-in precondition (object_attributes.status eq failed) and does not need to be part of the customer-configurable filter set for that flow. However, it may be useful for custom flows.
Supported operators
All three fields must support the following operators (already implemented in Gitlab::FilterEvaluator):
eq— equalsne— not equalscontains— string contains substringnot_contains— string does not contain substring
Field allowlisting / validation
- The filter evaluation for
pipeline_hooksmust only accept the fields listed above (andobject_attributes.statusfor the precondition). Any filter rule referencing an unlisted field path should be rejected at save time (GraphQL mutation validation) and/or silently skipped at evaluation time. - This prevents customers from coupling their trigger configuration to internal webhook payload fields that may change.
Payload mapping
The filter data passed to Ai::FlowTriggers::FilterEvaluator for pipeline_hooks must be a purpose-built minimal hash (not the raw Gitlab::DataBuilder::Pipeline output). The mapping from pipeline model attributes to filter field paths should be:
| Filter field path | Pipeline model attribute |
|---|---|
pipeline.source |
Ci::Pipeline#source |
pipeline.ref |
Ci::Pipeline#ref |
pipeline.merge_request.title |
Ci::Pipeline#merge_request&.title |
object_attributes.status |
Ci::Pipeline#status (for precondition compatibility) |
Example filter configurations
Only trigger on master-broken pipelines (push to master):
{
"pipeline_hooks": {
"match": "all",
"rules": [
{ "field": "pipeline.source", "operator": "eq", "value": "push" },
{ "field": "pipeline.ref", "operator": "eq", "value": "master" }
]
}
}Only trigger on MR pipelines that are not drafts:
{
"pipeline_hooks": {
"match": "all",
"rules": [
{ "field": "pipeline.source", "operator": "eq", "value": "merge_request_event" },
{ "field": "pipeline.merge_request.title", "operator": "not_contains", "value": "Draft:" }
]
}
}What exists today
Ai::FlowTriggers::FilterEvaluator— merges the customer-definedbase_filterwith the foundational flow'spreconditionand delegates toGitlab::FilterEvaluator.evaluate.Gitlab::FilterEvaluator— generic rule engine supporting nested groups,match: all/any, and the operators listed above. Field values are resolved via dot-notation path traversal (dig_value).EE::Ci::Pipelines::HookService#execute_flow_triggers— callsproject.execute_flow_triggers(hook_data, :pipeline_hooks)wherehook_datais the fullGitlab::DataBuilder::Pipelinepayload.Mutations::Ai::FlowTriggers::Create/Update— accept a free-form JSONfilterargument (no field-level validation today).- The Fix Pipeline precondition (
object_attributes.status eq failed) is defined inAi::Catalog::FoundationalFlow['fix_pipeline/v1'].preconditionand is always AND-ed with the customer filter.
Out of scope
- UI for configuring filters (tracked separately — see the thread on #592451 (closed))
- Group/instance-level enablement controls (tracked in #600203)
- Expanding the filterable attribute set beyond the minimum defined here (can be done incrementally once the allowlist mechanism is in place)
- Renaming the
pipeline_hooksevent type (separate concern)
References
- Parent issue: #592451 (closed) — Implement trigger: Pipeline Failed
- Discussion thread: #592451 (comment 3467210059)
Ai::FlowTriggers::FilterEvaluator:ee/app/services/ai/flow_triggers/filter_evaluator.rbGitlab::FilterEvaluator:lib/gitlab/filter_evaluator.rbEE::Ci::Pipelines::HookService:ee/app/services/ee/ci/pipelines/hook_service.rbAi::Catalog::FoundationalFlow(fix_pipeline/v1 precondition):ee/app/models/ai/catalog/foundational_flow.rb