Draft: Post GitLab Duo root cause analysis for Product Security pipelines
Problem
Pipeline failures in the Product Security tooling repos reach
#sec-prod-sec-eng-automation-failures through GitLab's pipelines-email
integration, pointed at a Slack email-to-channel address. That alert reports
that a pipeline broke but nothing about why, so triaging it always starts
with opening the job log by hand.
GitLab already ships the feature that answers this: Duo Root Cause Analysis,
the /troubleshoot chat tool scoped to a Ci::Build. This MR wires it to the
pipeline.failed webhook so the explanation shows up in the channel on its own.
I first looked at having triage-ops post @GitLab why did the pipeline <url> fail and let the GitLab for Slack app answer. That does not work: Duo in
Slack
is an Experiment behind the default-off slack_duo_agent flag, it requires a
Slack account linked to a GitLab account (a bot has none, and the authorize
prompt is ephemeral), and it runs the Developer Flow over channel history rather
than the CI root-cause tool.
Changes
Triage::PipelineFailure::RootCauseAnalysis issues an aiAction mutation
scoped to the failed build, then polls aiMessages for the assistant reply.
GitLab reads the job log server-side, so job logs never pass through
triage-ops. Polling is bounded at 60s, well under the 110s
SUCKER_PUNCH_SHUTDOWN_TIMEOUT. Any failure — blank token, refusal, message
errors, timeout, non-200 — returns nil instead of raising.
Triage::ProductSecurity::PipelineFailureRca reacts to pipeline.failed for
projects under gitlab-com/gl-security/ and gitlab-private/gl-security/,
skipping merge request and triggered pipelines. It matches on namespace prefix
rather than an explicit project list, since webhook configuration is already
the real gate. When no analysis comes back it posts nothing, so it never
duplicates the existing email alert.
I kept this as a standalone processor rather than another
PipelineFailure::Config class: PipelineHealth::PipelineFailureManagement is
built around incident creation and escalation, none of which applies here, and
it is the critical master-broken path.
It authenticates with a new GITLAB_SECURITYBOT_API_TOKEN rather than the
shared triage-ops bot token, because troubleshoot_job_with_ai resolves to
can?(:read_build) & troubleshoot_job_cloud_connector_authorized & troubleshoot_job_with_ai_authorized. That access belongs to Product Security's
own gitlab-securitybot identity, which already holds Reporter on the in-scope
projects. Leaving the variable unset disables the analysis.
Validation
- New specs pass: 30 examples, 0 failures. RuboCop clean on all four new files.
- Full suite: 5212 examples, 6 failures, all in
spec/processor/runway_migration_test_spec.rb. They reproduce identically on a cleanmaster(they needGITLAB_BOT_API_TOKEN_ON_COMlocally) and are unrelated to this change. glab ci lintvalid on the full config.- Replayed synthetic
pipeline.failedpayloads throughapplicable?:product-security/inventoryandproduct-security-engineering/token-hunter-reportsmatch,gitlab-org/gitlabdoes not. - Confirmed against gitlab.com's live GraphQL schema that
aiActiontakeschat: { resourceId, content }and returnsrequestId, read back viaaiMessages(requestIds:, roles: [ASSISTANT]). - Confirmed RCA is available for these namespaces:
troubleshootJobWithAi: trueon a real failed pipeline (product-security/inventorypipeline2804549805) andduoFeaturesEnabled: trueon both agitlab-com/gl-securityand agitlab-private/gl-securityproject.
I have not yet made a live /troubleshoot call, so the response text and
latency are still unmeasured. I plan to validate that during rollout with the
securitybot token, behind the unset-token switch.
Before this does anything
Nothing changes on merge until these are in place, which is deliberate:
- a GitLab Duo seat for
gitlab-securitybot, and theGITLAB_SECURITYBOT_API_TOKENCI/CD variable plus Runway/Vault copy pipeline_eventswebhooks on the in-scope projects pointing at the triage-ops endpointgitlab-securitybotadded as Reporter onproduct-security-engineering/token-hunter-reports, the one in-scope project where it is not currently a member
Worth a reviewer's eye: these are security tooling pipelines, so job logs can contain sensitive values. RCA sends log segments to the AI Gateway and the summary lands in Slack and in triage-ops' logs.
Action items
- Environment variable for a reactive processor added to
config/triage-web.yamland.gitlab/ci/triage-web.yml - Handbook page for Triage Operations — deferring to the reviewer on whether
a Security-department processor belongs there; documented in
doc/pipeline_failure_management.mdfor now - Affected groups:
- Relevant Slack channels =>
#sec-prod-sec-eng-automation-failures
- Relevant Slack channels =>