Repository navigation
api_trigger fires a run for every webhook delivery with no event/action filter #605
Description
What happens
An api_trigger node fires one automation run per HTTP delivery, with no way to narrow deliveries by event type or action. Pointing a GitHub repository webhook at <public-url>/api/v1/webhooks/automations/<nodeId> therefore runs the whole graph for every subscribed event, including events the automation cannot possibly care about.
Observed on our deployment (one automation, one api_trigger, one target task) after enabling the events a PR-review automation plausibly wants — pull_request, push, check_run:
- 3,291 runs in ~2.5 days (~1,300/day), all against the same task.
- Of the last 100 webhook deliveries, 85 were
check_run: GitHub emitscheck_runper job per state (queued→in_progress→completed), so a single push to a repo with ~10 CI jobs fans out into dozens of deliveries within a minute. Runs arrive in bursts of ~20/minute, matching the deliveries one-for-one. - Nothing downstream can prevent it: the graph's
github.pr_statecondition runs after the trigger, so it suppresses work but not the run — and once the run reaches atrigger_ai_agentnode, suppression is moot: a sandbox Job has already been requested.
The only workaround today is to uncheck event types in the GitHub hook, which is coarse: dropping check_run is fine, but pull_request still fires on opened, synchronize, labeled, closed, review_requested, … and the automation has no way to say "only opened and synchronize".
Why the code cannot already filter
ReceiveWebhook (services/api/internal/transport/http/handler/automation_handler.go) reads exactly one thing from the request — the X-Webhook-Token header — and calls HandleWebhookTrigger(ctx, nodeID, token). The body is never read and X-GitHub-Event is never inspected, so the delivery's identity is discarded before the service layer sees it. TriggerConfig (services/api/internal/domain/automation/entity.go) has narrowing fields for status, tag, sprint, due date and watched tasks, but nothing for an external webhook's event.
Proposed fix
An optional, GitHub-shaped allow-list on the trigger config:
{
"target_task_id": "746e4bfb-…",
"github_events": ["pull_request:opened", "pull_request:synchronize", "push"]
}- Each entry is
eventorevent:action, matched against theX-GitHub-Eventheader and the JSON body'sactionstring. - Empty/absent
github_eventskeeps today's behaviour exactly (fire on every delivery) — no migration, no breaking change for non-GitHub senders. - All entries are OR'd; a delivery matching none is accepted and discarded: still
202, no run, no stream entry, so the sender never retries and the token-verification response stays indistinguishable (no event-name probing). - Validated at save time like the other narrowing fields (
ErrNodeConfigInvalid): non-empty event, at most one:, non-empty action when the:is present; rejected on any trigger type other thanapi_trigger.
Deliberately GitHub-shaped rather than a general matcher: action + header is exactly the discriminator every GitHub integration has, and a generic JSONPath/expression language would be a much larger surface for the same result. A plugin-level filter can come later if a non-GitHub sender needs it.
Acceptance criteria
- A run is enqueued only for deliveries matching
github_events; a delivery that matches nothing returns202and leavesautomation_runsuntouched. - An
api_triggerwith nogithub_eventsbehaves exactly as today. - Invalid filter entries are rejected by the existing node-save validation path.
- Unit tests cover matching (
event,event:action, no filter, mismatch, malformed body, missing header) and the validation rules.
Impact where this was found
~1,300 runs/day collapse to the handful of PR events that actually matter, which also keeps trigger_ai_agent from requesting a sandbox per CI job — a 2 CPU / 4 Gi sandbox against a 12-pod namespace quota.
Activity
pullfrog commentedon Oct 19, 2026
kayahk commentedon Oct 19, 2026
Implemented in #606: optional
github_eventson the api_trigger config (eventorevent:action), matched againstX-GitHub-Event+ the body'saction; a non-matching delivery is accepted (202) and dropped without creating a run. Covered by a unit test on the matcher, save-time validation tests, and an e2e that asserts zero runs for acheck_rundelivery and a fired run forpull_request:opened.kayahk commentedon Oct 19, 2026
Closing: this moved to the GitHub plugin, where GitHub event handling belongs (per the maintainer's guidance on #606).
check_runbut never handled it, paying a repository lookup + HMAC per CI job): fix(webhook): drop unhandled events before the repository lookup paca-plugin-github#27github.pr_updatedtopic: Automations cannot narrow GitHub PR triggers to specific actions paca-plugin-github#28The original report's evidence still holds: ~3,300 runs in 2.5 days on one automation, ~85% of deliveries
check_run, because anapi_triggerhad no way to filter. That is now handled on the sender side (the hook no longer subscribes tocheck_run) and, in the plugin, in front of the database.GitHub issue transfer between the two repos isn't available to a non-maintainer, hence the fresh issue over there rather than a move.