workflow_run triggered workflow runs for the wrong commit (older commit) — CD runs for commit #99 after CI for commit #100 completes #15001

Closed
opened 2025-11-02 11:27:45 -06:00 by GiteaMirror · 4 comments
Owner

Originally created by @moemoequte on GitHub (Oct 5, 2025).

Description

Summary

When using workflow_run to trigger a deployment workflow after a CI workflow completes, the triggered workflow (CD) runs for an older commit instead of the commit whose CI just completed. Example: I push commit #100; CI runs for #100 and finishes, but the CD workflow that should run for #100 ends up running for #99.

ci.yml

# Continuous Integration Workflow
# This workflow builds and pushes Docker images to your private registry
# Trigger: Push to dev branch or manual dispatch

name: CI - Build and Push

# Trigger configuration - automatic on dev push, manual dispatch available
on:
  push:
    branches:
      - dev
  workflow_dispatch:
    inputs:
      image_tag:
        description: 'Docker image tag (e.g., latest, v1.0.0)'
        required: false
        default: 'latest'
        type: string

# Environment variables available to all jobs
env:
  CONTAINER_REGISTRY_URL: ${{ secrets.CONTAINER_REGISTRY_URL }}
  CONTAINER_REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }}
  CONTAINER_REGISTRY_NAMESPACE: ${{ secrets.CONTAINER_REGISTRY_NAMESPACE }}
  CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }}
  CONTAINER_IMAGE_NAME: ${{ secrets.CONTAINER_IMAGE_NAME }}
  CONTAINER_IMAGE_TAG: ${{ inputs.image_tag || 'latest' }}

jobs:
  build-and-push:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest
    
    steps:
      # Step 1: Checkout code from repository
      - name: Checkout code
        uses: actions/checkout@v4
      
      # Step 2: Make CI script executable
      - name: Make CI script executable
        run: chmod +x script/ci.sh
      
      # Step 3: Build Docker image
      - name: Build Docker image
        run: ./script/ci.sh build
      
      # Step 4: Push Docker image to registry
      - name: Push Docker image
        run: ./script/ci.sh push
      
      # Step 5: Output summary
      - name: Summary
        run: |
          echo "### :rocket: Build Complete!" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Image:** \`${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Registry:** ${CONTAINER_REGISTRY_URL}" >> $GITHUB_STEP_SUMMARY
          echo "**Tag:** ${CONTAINER_IMAGE_TAG}" >> $GITHUB_STEP_SUMMARY

cd.yml

# Continuous Deployment Workflow
# This workflow deploys your application to Kubernetes cluster
# Trigger: After successful CI build or manual dispatch

#commit test trigger
name: CD - Deploy to Kubernetes
#
#
#
# Trigger configuration - automatic after CI success, manual dispatch available
on:
  workflow_run:
    workflows: ["CI - Build and Push"]
    types:
      - completed
    branches:
      - dev
  workflow_dispatch:
    inputs:
      image_tag:
        description: 'Docker image tag to deploy (e.g., latest, v1.0.0)'
        required: false
        default: 'latest'
        type: string
      namespace:
        description: 'Kubernetes namespace (e.g., production, staging)'
        required: false
        default: 'default'
        type: string
      ingress_host:
        description: 'Ingress host domain (e.g., www.example.com)'
        required: false
        default: ''
        type: string
      force_restart:
        description: 'Force rollout restart (restarts pods even if no changes)'
        required: false
        default: true
        type: boolean

# Environment variables available to all jobs
env:
  # Kubernetes configuration
  KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }}
  KUBERNETES_URL: ${{ secrets.KUBERNETES_URL }}
  KUBERNETES_NAMESPACE: ${{ inputs.namespace || secrets.KUBERNETES_NAMESPACE }}
  KUBERNETES_INGRESS_HOST: ${{ inputs.ingress_host || secrets.KUBERNETES_INGRESS_HOST }}
  
  # Container registry configuration
  CONTAINER_REGISTRY_URL: ${{ secrets.CONTAINER_REGISTRY_URL }}
  CONTAINER_REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }}
  CONTAINER_REGISTRY_NAMESPACE: ${{ secrets.CONTAINER_REGISTRY_NAMESPACE }}
  CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }}
  CONTAINER_IMAGE_NAME: ${{ secrets.CONTAINER_IMAGE_NAME }}
  CONTAINER_IMAGE_TAG: ${{ inputs.image_tag || 'latest' }}
  FORCE_RESTART: ${{ inputs.force_restart }}

jobs:
  deploy:
    name: Deploy to Kubernetes
    runs-on: ubuntu-latest
    # Only run if CI workflow succeeded (for workflow_run trigger)
    if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
    
    steps:
      # Step 1: Checkout code from repository
      - name: Checkout code
        uses: actions/checkout@v4
      
      # Step 2: Make CD script executable
      - name: Make CD script executable
        run: chmod +x script/cd.sh
      
      # Step 3: Deploy to Kubernetes
      - name: Deploy to Kubernetes
        run: ./script/cd.sh deploy
      
      # Step 4: Output deployment summary
      - name: Deployment Summary
        if: success()
        run: |
          echo "### :white_check_mark: Deployment Successful!" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Application:** \`${CONTAINER_IMAGE_NAME}\`" >> $GITHUB_STEP_SUMMARY
          echo "**Namespace:** \`${KUBERNETES_NAMESPACE}\`" >> $GITHUB_STEP_SUMMARY
          echo "**Image:** \`${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY
          echo "**URL:** http://${KUBERNETES_INGRESS_HOST}" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "---" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Deployment Time:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
      
      # Step 5: Output failure message
      - name: Deployment Failed
        if: failure()
        run: |
          echo "### :x: Deployment Failed!" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "Please check the logs above for error details." >> $GITHUB_STEP_SUMMARY

Steps:

  1. Push commit dev → commit #99 (CI run for #99 starts or finishes).
  2. Push commit dev → commit #100.
  3. CI run for #100 starts and completes.
  4. Expected: CD triggers for commit #100 immediately after CI for #100 completes.
  5. Observed: CD triggers for commit #99 instead.

Version

1.25.0-rc0 built with GNU Make 4.3, go1.25.1 : bindata, sqlite, sqlite_unlock_notify

ScreenShot

Image

Gitea Version

1.25.0-rc0 built with GNU Make 4.3, go1.25.1 : bindata, sqlite, sqlite_unlock_notify

Can you reproduce the bug on the Gitea demo site?

Yes

Log Gist

No response

Screenshots

No response

Git Version

No response

Operating System

No response

How are you running Gitea?

Yes

Database

None

Originally created by @moemoequte on GitHub (Oct 5, 2025). ### Description ### Summary When using workflow_run to trigger a deployment workflow after a CI workflow completes, the triggered workflow (CD) runs for an older commit instead of the commit whose CI just completed. Example: I push commit #100; CI runs for #100 and finishes, but the CD workflow that should run for #100 ends up running for #99. ### ci.yml ``` # Continuous Integration Workflow # This workflow builds and pushes Docker images to your private registry # Trigger: Push to dev branch or manual dispatch name: CI - Build and Push # Trigger configuration - automatic on dev push, manual dispatch available on: push: branches: - dev workflow_dispatch: inputs: image_tag: description: 'Docker image tag (e.g., latest, v1.0.0)' required: false default: 'latest' type: string # Environment variables available to all jobs env: CONTAINER_REGISTRY_URL: ${{ secrets.CONTAINER_REGISTRY_URL }} CONTAINER_REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} CONTAINER_REGISTRY_NAMESPACE: ${{ secrets.CONTAINER_REGISTRY_NAMESPACE }} CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} CONTAINER_IMAGE_NAME: ${{ secrets.CONTAINER_IMAGE_NAME }} CONTAINER_IMAGE_TAG: ${{ inputs.image_tag || 'latest' }} jobs: build-and-push: name: Build and Push Docker Image runs-on: ubuntu-latest steps: # Step 1: Checkout code from repository - name: Checkout code uses: actions/checkout@v4 # Step 2: Make CI script executable - name: Make CI script executable run: chmod +x script/ci.sh # Step 3: Build Docker image - name: Build Docker image run: ./script/ci.sh build # Step 4: Push Docker image to registry - name: Push Docker image run: ./script/ci.sh push # Step 5: Output summary - name: Summary run: | echo "### :rocket: Build Complete!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Image:** \`${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Registry:** ${CONTAINER_REGISTRY_URL}" >> $GITHUB_STEP_SUMMARY echo "**Tag:** ${CONTAINER_IMAGE_TAG}" >> $GITHUB_STEP_SUMMARY ``` ### cd.yml ``` # Continuous Deployment Workflow # This workflow deploys your application to Kubernetes cluster # Trigger: After successful CI build or manual dispatch #commit test trigger name: CD - Deploy to Kubernetes # # # # Trigger configuration - automatic after CI success, manual dispatch available on: workflow_run: workflows: ["CI - Build and Push"] types: - completed branches: - dev workflow_dispatch: inputs: image_tag: description: 'Docker image tag to deploy (e.g., latest, v1.0.0)' required: false default: 'latest' type: string namespace: description: 'Kubernetes namespace (e.g., production, staging)' required: false default: 'default' type: string ingress_host: description: 'Ingress host domain (e.g., www.example.com)' required: false default: '' type: string force_restart: description: 'Force rollout restart (restarts pods even if no changes)' required: false default: true type: boolean # Environment variables available to all jobs env: # Kubernetes configuration KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }} KUBERNETES_URL: ${{ secrets.KUBERNETES_URL }} KUBERNETES_NAMESPACE: ${{ inputs.namespace || secrets.KUBERNETES_NAMESPACE }} KUBERNETES_INGRESS_HOST: ${{ inputs.ingress_host || secrets.KUBERNETES_INGRESS_HOST }} # Container registry configuration CONTAINER_REGISTRY_URL: ${{ secrets.CONTAINER_REGISTRY_URL }} CONTAINER_REGISTRY_USERNAME: ${{ secrets.CONTAINER_REGISTRY_USERNAME }} CONTAINER_REGISTRY_NAMESPACE: ${{ secrets.CONTAINER_REGISTRY_NAMESPACE }} CONTAINER_REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} CONTAINER_IMAGE_NAME: ${{ secrets.CONTAINER_IMAGE_NAME }} CONTAINER_IMAGE_TAG: ${{ inputs.image_tag || 'latest' }} FORCE_RESTART: ${{ inputs.force_restart }} jobs: deploy: name: Deploy to Kubernetes runs-on: ubuntu-latest # Only run if CI workflow succeeded (for workflow_run trigger) if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} steps: # Step 1: Checkout code from repository - name: Checkout code uses: actions/checkout@v4 # Step 2: Make CD script executable - name: Make CD script executable run: chmod +x script/cd.sh # Step 3: Deploy to Kubernetes - name: Deploy to Kubernetes run: ./script/cd.sh deploy # Step 4: Output deployment summary - name: Deployment Summary if: success() run: | echo "### :white_check_mark: Deployment Successful!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Application:** \`${CONTAINER_IMAGE_NAME}\`" >> $GITHUB_STEP_SUMMARY echo "**Namespace:** \`${KUBERNETES_NAMESPACE}\`" >> $GITHUB_STEP_SUMMARY echo "**Image:** \`${CONTAINER_REGISTRY_URL}/${CONTAINER_REGISTRY_NAMESPACE}/${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}\`" >> $GITHUB_STEP_SUMMARY echo "**URL:** http://${KUBERNETES_INGRESS_HOST}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "---" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Deployment Time:** $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY # Step 5: Output failure message - name: Deployment Failed if: failure() run: | echo "### :x: Deployment Failed!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Please check the logs above for error details." >> $GITHUB_STEP_SUMMARY ``` ### Steps: 1. Push commit dev → commit `#99` (CI run for `#99` starts or finishes). 2. Push commit dev → commit `#100`. 3. CI run for `#100` starts and completes. 4. Expected: CD triggers for commit `#100` immediately after CI for `#100` completes. 5. Observed: CD triggers for commit `#99` instead. ### Version 1.25.0-rc0 built with GNU Make 4.3, go1.25.1 : bindata, sqlite, sqlite_unlock_notify ### ScreenShot <img width="1485" height="895" alt="Image" src="https://github.com/user-attachments/assets/6fda52b3-18cc-4ba4-85a2-7bae15c281b7" /> ### Gitea Version 1.25.0-rc0 built with GNU Make 4.3, go1.25.1 : bindata, sqlite, sqlite_unlock_notify ### Can you reproduce the bug on the Gitea demo site? Yes ### Log Gist _No response_ ### Screenshots _No response_ ### Git Version _No response_ ### Operating System _No response_ ### How are you running Gitea? [Yes](https://git.cialloo.com/) ### Database None
GiteaMirror added the topic/gitea-actionstype/bug labels 2025-11-02 11:27:45 -06:00
Author
Owner

@ChristopherHX commented on GitHub (Oct 6, 2025):

This needs more information.

workflow_run reads the workflow from default branch master (in your case, sometimes main etc.), unrelated what triggered the run.


This behavior aligns with GitHub Actions, e.g. trigger a privileged workflow from an unprivileged pr from fork using pull_request event.

@ChristopherHX commented on GitHub (Oct 6, 2025): This needs more information. `workflow_run` reads the workflow from default branch `master` (in your case, sometimes main etc.), unrelated what triggered the run. --- This behavior aligns with GitHub Actions, e.g. trigger a privileged workflow from an unprivileged pr from fork using pull_request event.
Author
Owner

@moemoequte commented on GitHub (Oct 6, 2025):

@ChristopherHX Here is my selfhost gitea with the action issue

@moemoequte commented on GitHub (Oct 6, 2025): @ChristopherHX [Here is my selfhost gitea with the action issue](https://git.cialloo.com/cialloo/ActionIssue)
Author
Owner

@ChristopherHX commented on GitHub (Oct 8, 2025):

You just confirmed this is a usage issue. workflow_run always run on the default branch, but you commit to develop that is normal branch.

I suggest to change your cd workflow on your default branch to:

Warning

Be very careful, this is a security nightmare. Anyone who can trigger a workflow_run in a PR is potentially able to prepare malware into the build system or deployment. Only the workflow itself is protected by not behaving like you expect.

      # Step 1: Checkout code from repository
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.workflow_run.head_sha || github.sha }} # the latter is for dispatch
@ChristopherHX commented on GitHub (Oct 8, 2025): You just confirmed this is a usage issue. `workflow_run` always run on the default branch, but you commit to develop that is normal branch. I suggest to change your cd workflow on your default branch to: > [!WARNING] > Be very careful, this is a security nightmare. Anyone who can trigger a workflow_run in a PR is potentially able to prepare malware into the build system or deployment. Only the workflow itself is protected by not behaving like you expect. ```yaml # Step 1: Checkout code from repository - name: Checkout code uses: actions/checkout@v4 with: ref: ${{ github.event.workflow_run.head_sha || github.sha }} # the latter is for dispatch ```
Author
Owner

@moemoequte commented on GitHub (Oct 8, 2025):

You just confirmed this is a usage issue. workflow_run always run on the default branch, but you commit to develop that is normal branch.

I suggest to change your cd workflow on your default branch to:

Warning

Be very careful, this is a security nightmare. Anyone who can trigger a workflow_run in a PR is potentially able to prepare malware into the build system or deployment. Only the workflow itself is protected by not behaving like you expect.

  # Step 1: Checkout code from repository
  - name: Checkout code
    uses: actions/checkout@v4
    with:
      ref: ${{ github.event.workflow_run.head_sha || github.sha }} # the latter is for dispatch

OK

@moemoequte commented on GitHub (Oct 8, 2025): > You just confirmed this is a usage issue. `workflow_run` always run on the default branch, but you commit to develop that is normal branch. > > I suggest to change your cd workflow on your default branch to: > > Warning > > Be very careful, this is a security nightmare. Anyone who can trigger a workflow_run in a PR is potentially able to prepare malware into the build system or deployment. Only the workflow itself is protected by not behaving like you expect. > > # Step 1: Checkout code from repository > - name: Checkout code > uses: actions/checkout@v4 > with: > ref: ${{ github.event.workflow_run.head_sha || github.sha }} # the latter is for dispatch OK
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#15001