Skip to content

workflow_run webhook not fired when workflow file does not exist on the default branch #37169

@vasco-cruz

Description

@vasco-cruz

Description

Summary

The workflow_run webhook event is silently dropped when a workflow is triggered (e.g. via workflow_dispatch API) from a branch where the workflow file exists, but the workflow file does not exist on the repository's default branch.

Steps to Reproduce

  1. Have a repository where the default branch (e.g. main) does not contain .gitea/workflows/my-workflow.yml
  2. Create a feature branch that does contain .gitea/workflows/my-workflow.yml
  3. Configure a repository webhook listening to the workflow_run event
  4. Trigger the workflow via the API:
    POST /api/v1/repos/{owner}/{repo}/actions/workflows/my-workflow.yml/dispatches
    
  5. Observe that the webhook is never called — neither on requested nor completed

Expected Behavior

The workflow_run webhook should fire for any workflow run, regardless of whether the workflow file exists on the default branch.

Actual Behavior

The webhook is silently dropped. The following errors appear in Gitea logs:

services/webhook/notifier.go:1037:(*webhookNotifier).WorkflowRunStatusUpdate() [E] GetActionWorkflow: workflow "my-workflow.yml" not found
services/actions/notifier.go:810:(*actionsNotifier).WorkflowRunStatusUpdate() [E] GetActionWorkflow: workflow "my-workflow.yml" not found

Root Cause

In services/convert/convert.go, GetActionWorkflow always resolves the workflow file from the default branch:

func GetActionWorkflow(ctx context.Context, gitrepo *git.Repository, repo *repo_model.Repository, workflowID string) (*api.ActionWorkflow, error) {
    defaultBranchCommit, err := gitrepo.GetBranchCommit(repo.DefaultBranch) // ← always default branch
    ...
    return nil, util.NewNotExistErrorf("workflow %q not found", workflowID)
}

This is called from services/webhook/notifier.go inside WorkflowRunStatusUpdate, which passes run.WorkflowID but not run.Ref. When the workflow file doesn't exist on the default branch, the function returns NotExist, causing the notifier to return early — swallowing the webhook event entirely.

Suggested Fix

GetActionWorkflow (and its caller) should fall back to looking up the workflow file from the ref/branch of the actual run (run.Ref) when it is not found on the default branch. Alternatively, WorkflowRunStatusUpdate could pass the run's ref so the lookup can be performed against the correct commit.

Environment

  • Gitea version: 1.25.5
  • Triggered via: workflow_dispatch API on a non-default branch

Gitea Version

1.25.5

Can you reproduce the bug on the Gitea demo site?

No

Log Gist

https://gist.github.com/vasco-cruz/92c540681c3cf7031cd1469738266548

Screenshots

No response

Git Version

No response

Operating System

Docker

How are you running Gitea?

Docker compose

networks:
  gitea:

services:
  gitea:
    image: gitea/gitea:${GITEA_VERSION:-1.25.5}
    container_name: gitea
    restart: always
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__actions__ENABLED=true
      - GITEA__webhook__ALLOWED_HOST_LIST=webhook-bridge
      - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN}
    networks:
      - gitea
    volumes:
      - ./gitea:/data
    ports:
      - "3000:3000"
      - "222:22"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000"]
      interval: 30s
      timeout: 5s
      retries: 10
      start_period: 30s


  webhook-bridge:
    image: node:${NODE_VERSION:-18}
    container_name: webhook-bridge
    working_dir: /app
    volumes:
      - ../webhook-bridge:/app
    command: >
      npm install && npm run dev
    restart: always
      - WEBHOOK_BRIDGE_PORT=${WEBHOOK_BRIDGE_PORT:-4000}
      - GITEA_TOKEN=${GITEA_TOKEN}
    networks:
      - gitea
    depends_on:
      - gitea
    ports:
      - "${WEBHOOK_BRIDGE_PORT:-4000}:${WEBHOOK_BRIDGE_PORT:-4000}"
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "-qO-",
          "http://localhost:${WEBHOOK_BRIDGE_PORT:-4000}/health",
        ]
      interval: 60s
      timeout: 5s
      retries: 10
      start_period: 30s

  runner1:
    image: gitea/act_runner:${ACT_RUNNER_VERSION:-0.3.1}
    container_name: gitea-runner1
    privileged: true
    networks:
      - gitea
    depends_on:
      gitea:
        condition: service_healthy
    environment:
      - GITEA_INSTANCE_URL=http://gitea:3000
      - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN}
      - GITEA_RUNNER_NAME=Runner 1
      - GITEA_RUNNER_LABELS=${GITEA_RUNNER_LABELS:-ubuntu-latest,self-hosted,linux,eds.uikit}
      - CONFIG_FILE=/data/config.yaml
    volumes:
      - ./runner-config/config.yaml:/data/config.yaml
      - /var/run/docker.sock:/var/run/docker.sock

Database

SQLite

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions