Fix actions concurrency groups cross-branch leak#37311
Merged
silverwind merged 5 commits intogo-gitea:mainfrom Apr 21, 2026
Merged
Fix actions concurrency groups cross-branch leak#37311silverwind merged 5 commits intogo-gitea:mainfrom
silverwind merged 5 commits intogo-gitea:mainfrom
Conversation
Workflow-level concurrency groups were evaluated in PrepareRunAndInsert
before the run was inserted, with run.ID still 0 and run.Index still 0.
GenerateGiteaContext hardcoded run_id to "", so expressions like
${{ github.head_ref || github.run_id }} collapsed to the same string on
every push event, causing cancel-in-progress to cancel unrelated runs
across different branches.
Move the workflow-level evaluation into InsertRun after run.Index is
assigned, and fall back to run.Index in the context when run.ID is not
yet set. run.Index is unique per repo, which is enough for concurrency
grouping (groups are scoped per repo).
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Member
Author
|
This is a critical bug in the concurrency groups feature added in #32751, it causes cross-branch interference. @Zettat123 can you review? It's a partial extract from #37119. |
wxiaoguang
previously requested changes
Apr 20, 2026
Contributor
wxiaoguang
left a comment
There was a problem hiding this comment.
Even if I don't understand "Actions", I clearly know such hacky patch can't be right.
You should never make "run_id" sometimes be "id" sometimes be "index"
github.run_id during pre-insert concurrency evalAddress review feedback on PR go-gitea#37311: the previous revision overloaded github.run_id to fall back to run.Index when run.ID was not yet set, which was semantically incorrect — run_id should always mean run.ID. Instead, reorder InsertRun so that db.Insert happens before concurrency evaluation. This gives the run a real ID at eval time, so ${{ github.head_ref || github.run_id }} resolves to a per-run unique value and no longer collapses across branches on push events. The concurrency-derived fields (concurrency_group, concurrency_cancel, status) are persisted with a follow-up UpdateRun. Replace the narrow context unit test with a broader regression test exercising EvaluateRunConcurrencyFillModel against two persisted fixture runs, asserting distinct ConcurrencyGroup values for the real head_ref || run_id expression. Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Member
Author
|
Better fix pushed in e9498a6, verified and pr description updated. |
Zettat123
reviewed
Apr 20, 2026
Addresses review feedback on PR go-gitea#37311: jobparser.Parse also needs a non-zero run.ID so that github.run_id interpolates correctly in run-name, job names, and runs-on — not just in workflow concurrency group expressions. Moves jobparser.Parse inside the InsertRun transaction, after db.Insert(ctx, run), and consolidates all concurrency field persistence (raw_concurrency, concurrency_group, concurrency_cancel, status) into the single final UpdateRun at end-of-transaction. This also fixes an intermediate regression where raw_concurrency was set in memory but never written to the DB — services/actions/rerun.go reads it from the DB on rerun. Simplifies GenerateGiteaContext to set run_id from run.ID unconditionally; all callers now pass a persisted run. Adds TestPrepareRunAndInsert_ExpressionsSeeRunID exercising the full PrepareRunAndInsert flow with \${{ github.run_id }} in both run-name and concurrency group; a re-ordering regression would fail both assertions. Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
lunny
reviewed
Apr 20, 2026
The default title (commit message) was already persisted by db.Insert; only include "title" in the final UpdateRun when jobs[0].RunName actually overrode it. Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
lunny
approved these changes
Apr 20, 2026
Zettat123
approved these changes
Apr 20, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
silverwind
added a commit
that referenced
this pull request
Apr 21, 2026
Backport #37311 by @silverwind ## Problem Workflow-level concurrency groups were evaluated — and jobs were parsed — before the run was persisted, so `run.ID` was `0` and `github.run_id` in the expression context resolved to an empty string. Expressions like: ```yaml concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true ``` collapsed to `<workflow>-` on every push event (`head_ref` is empty on push), so `cancel-in-progress` cancelled in-progress runs across **unrelated branches**, not just the current one. Reproduced on a 1.26 instance: - push to `master` → `ci` run starts - push to `feature-branch` → the `master` run gets cancelled GitHub Actions' documented semantic: on push events `github.run_id` is unique per run, so the group is unique → no cancellation; on PR events `github.head_ref` is the source branch → cancellation is per-PR. ## Fix Insert the run **before** parsing jobs or evaluating workflow-level concurrency, so `run.ID` is populated in time for every expression that reads `github.run_id` — not just the concurrency group, but also `run-name`, job names, and `runs-on`. `jobparser.Parse` now runs inside the `InsertRun` transaction, after `db.Insert(ctx, run)`. Workflow-level concurrency evaluation runs next and only mutates `run` in memory. All concurrency-derived fields (`raw_concurrency`, `concurrency_group`, `concurrency_cancel`) plus `status` and `title` are persisted in a single final `UpdateRun` at end-of-transaction — one `INSERT` + one `UPDATE` per run in both the concurrency and non-concurrency paths (matches pre-branch parity, one fewer `UpdateRepoRunsNumbers` `COUNT` than the interim state). `GenerateGiteaContext` now sets `run_id` from `run.ID` unconditionally; every caller passes a persisted run. **Verification**: tested end-to-end on a 1.26 deployment. Before the patch, two successive `ci` pushes (one to master, one to a feature branch) cross-cancelled each other. After the patch, the same pushes — in both orders (master→branch, branch→master) — run to completion simultaneously across 15+ runs with zero cancellations. **Regression tests** in `services/actions/context_test.go`: - `TestEvaluateRunConcurrency_RunIDFallback` — unit check that `EvaluateRunConcurrencyFillModel` resolves `github.run_id` from `run.ID`. - `TestPrepareRunAndInsert_ExpressionsSeeRunID` — full-flow check: calls `PrepareRunAndInsert` with `${{ github.run_id }}` in both `run-name` and the concurrency group, then asserts the persisted `Title`, `ConcurrencyGroup`, and `RawConcurrency` contain / survive the run's ID. Re-ordering `db.Insert` relative to either parse or concurrency eval fails this test. ## Relation to #37119 [#37119](#37119) also moves concurrency evaluation into `InsertRun` but keeps it **before** `db.Insert`, then tries to populate `run_id` only when `run.ID > 0` — which is still `0` at that call site, so the cross-branch leak would survive that PR as written. This PR fixes the ordering so that `run.ID` is actually populated at eval time, and broadens it to cover parse-time expression interpolation too. --- This PR was written with the help of Claude Opus 4.7 Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
silverwind
added a commit
to 6543-forks/gitea
that referenced
this pull request
Apr 21, 2026
…n-better * origin/main: (645 commits) When the requested arch rpm is missing fall back to noarch (go-gitea#37236) Fix `relative-time` error and improve global error handler (go-gitea#37241) Enhance styling in actions page (go-gitea#37323) fix(oauth): Error on auth sources with spaces (go-gitea#37327) Fix actions concurrency groups cross-branch leak (go-gitea#37311) Fix bug when accessing user badges (go-gitea#37321) Fix AppFullLink (go-gitea#37325) Update go js dependencies (go-gitea#37312) Update GitHub Actions to latest major versions (go-gitea#37313) Revert "Add WebKit to e2e test matrix (go-gitea#37298)" (go-gitea#37315) Add `form-fetch-action` to some forms, fix "fetch action" resp bug (go-gitea#37305) Move heatmap to first-party code (go-gitea#37262) Use updated yaml fields for snapcraft (go-gitea#37318) Remove dead code identified by `deadcode` tool (go-gitea#37271) Enable strict TypeScript, add `errorMessage` helper (go-gitea#37292) Fix vite manifest update masking build errors (go-gitea#37279) bump snapcraft base (go-gitea#37301) Add WebKit to e2e test matrix (go-gitea#37298) Don't add useless labels which will bother changelog generation (go-gitea#37267) Fix Repository transferring page (go-gitea#37277) ... # Conflicts: # options/locale/locale_en-US.ini # templates/package/content/debian.tmpl
zjjhot
added a commit
to zjjhot/gitea
that referenced
this pull request
Apr 22, 2026
* main: (25 commits) Add URL to `Learn more about blocking a user` (go-gitea#37355) fix: use TriggerEvent instead of Event in workflow runs API response for scheduled runs (go-gitea#37288) Add event.schedule context for schedule actions task (go-gitea#37320) Fix typos (go-gitea#37346) Fix an issue where changing an organization’s visibility caused problems when users had forked its repositories. (go-gitea#37324) Fail vite build on rolldown warnings via NODE_ENV=test (go-gitea#37270) Use modern "git update-index --cacheinfo" syntax to support more file names (go-gitea#37338) Fix URL related escaping for oauth2 (go-gitea#37334) When the requested arch rpm is missing fall back to noarch (go-gitea#37236) Fix `relative-time` error and improve global error handler (go-gitea#37241) Enhance styling in actions page (go-gitea#37323) fix(oauth): Error on auth sources with spaces (go-gitea#37327) Fix actions concurrency groups cross-branch leak (go-gitea#37311) Fix bug when accessing user badges (go-gitea#37321) Fix AppFullLink (go-gitea#37325) Update go js dependencies (go-gitea#37312) Update GitHub Actions to latest major versions (go-gitea#37313) Revert "Add WebKit to e2e test matrix (go-gitea#37298)" (go-gitea#37315) Add `form-fetch-action` to some forms, fix "fetch action" resp bug (go-gitea#37305) Move heatmap to first-party code (go-gitea#37262) ...
silverwind
added a commit
to silverwind/gitea
that referenced
this pull request
Apr 23, 2026
* origin/main: (32 commits) fix: commit status reporting (go-gitea#37372) Support for Custom URI Schemes in OAuth2 Redirect URIs (go-gitea#37356) Fix cmd tests by mocking builtin paths (go-gitea#37369) chore: upgrade Go version in devcontainer image to 1.26 (go-gitea#37374) Fix button layout shift when collapsing file tree in editor (go-gitea#37363) Update `Block a user` form (go-gitea#37359) Remove IsValidExternalURL/IsAPIURL and use IsValidURL at call sites (go-gitea#37364) Add URL to `Learn more about blocking a user` (go-gitea#37355) fix: use TriggerEvent instead of Event in workflow runs API response for scheduled runs (go-gitea#37288) Add event.schedule context for schedule actions task (go-gitea#37320) Fix typos (go-gitea#37346) Fix an issue where changing an organization’s visibility caused problems when users had forked its repositories. (go-gitea#37324) Fail vite build on rolldown warnings via NODE_ENV=test (go-gitea#37270) Use modern "git update-index --cacheinfo" syntax to support more file names (go-gitea#37338) Fix URL related escaping for oauth2 (go-gitea#37334) When the requested arch rpm is missing fall back to noarch (go-gitea#37236) Fix `relative-time` error and improve global error handler (go-gitea#37241) Enhance styling in actions page (go-gitea#37323) fix(oauth): Error on auth sources with spaces (go-gitea#37327) Fix actions concurrency groups cross-branch leak (go-gitea#37311) ... # Conflicts: # services/actions/commit_status.go
silverwind
added a commit
to silverwind/gitea
that referenced
this pull request
Apr 23, 2026
* origin/main: (204 commits) fix: commit status reporting (go-gitea#37372) Support for Custom URI Schemes in OAuth2 Redirect URIs (go-gitea#37356) Fix cmd tests by mocking builtin paths (go-gitea#37369) chore: upgrade Go version in devcontainer image to 1.26 (go-gitea#37374) Fix button layout shift when collapsing file tree in editor (go-gitea#37363) Update `Block a user` form (go-gitea#37359) Remove IsValidExternalURL/IsAPIURL and use IsValidURL at call sites (go-gitea#37364) Add URL to `Learn more about blocking a user` (go-gitea#37355) fix: use TriggerEvent instead of Event in workflow runs API response for scheduled runs (go-gitea#37288) Add event.schedule context for schedule actions task (go-gitea#37320) Fix typos (go-gitea#37346) Fix an issue where changing an organization’s visibility caused problems when users had forked its repositories. (go-gitea#37324) Fail vite build on rolldown warnings via NODE_ENV=test (go-gitea#37270) Use modern "git update-index --cacheinfo" syntax to support more file names (go-gitea#37338) Fix URL related escaping for oauth2 (go-gitea#37334) When the requested arch rpm is missing fall back to noarch (go-gitea#37236) Fix `relative-time` error and improve global error handler (go-gitea#37241) Enhance styling in actions page (go-gitea#37323) fix(oauth): Error on auth sources with spaces (go-gitea#37327) Fix actions concurrency groups cross-branch leak (go-gitea#37311) ... # Conflicts: # web_src/js/index-domready.ts # web_src/js/markup/content.ts # web_src/js/markup/refissue.ts
silverwind
added a commit
to silverwind/gitea
that referenced
this pull request
Apr 23, 2026
* origin/main: (204 commits) fix: commit status reporting (go-gitea#37372) Support for Custom URI Schemes in OAuth2 Redirect URIs (go-gitea#37356) Fix cmd tests by mocking builtin paths (go-gitea#37369) chore: upgrade Go version in devcontainer image to 1.26 (go-gitea#37374) Fix button layout shift when collapsing file tree in editor (go-gitea#37363) Update `Block a user` form (go-gitea#37359) Remove IsValidExternalURL/IsAPIURL and use IsValidURL at call sites (go-gitea#37364) Add URL to `Learn more about blocking a user` (go-gitea#37355) fix: use TriggerEvent instead of Event in workflow runs API response for scheduled runs (go-gitea#37288) Add event.schedule context for schedule actions task (go-gitea#37320) Fix typos (go-gitea#37346) Fix an issue where changing an organization’s visibility caused problems when users had forked its repositories. (go-gitea#37324) Fail vite build on rolldown warnings via NODE_ENV=test (go-gitea#37270) Use modern "git update-index --cacheinfo" syntax to support more file names (go-gitea#37338) Fix URL related escaping for oauth2 (go-gitea#37334) When the requested arch rpm is missing fall back to noarch (go-gitea#37236) Fix `relative-time` error and improve global error handler (go-gitea#37241) Enhance styling in actions page (go-gitea#37323) fix(oauth): Error on auth sources with spaces (go-gitea#37327) Fix actions concurrency groups cross-branch leak (go-gitea#37311) ... Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com> # Conflicts: # web_src/js/index-domready.ts # web_src/js/markup/content.ts # web_src/js/markup/refissue.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Workflow-level concurrency groups were evaluated — and jobs were parsed — before the run was persisted, so
run.IDwas0andgithub.run_idin the expression context resolved to an empty string. Expressions like:collapsed to
<workflow>-on every push event (head_refis empty on push), socancel-in-progresscancelled in-progress runs across unrelated branches, not just the current one.Reproduced on a 1.26 instance:
master→cirun startsfeature-branch→ themasterrun gets cancelledGitHub Actions' documented semantic: on push events
github.run_idis unique per run, so the group is unique → no cancellation; on PR eventsgithub.head_refis the source branch → cancellation is per-PR.Fix
Insert the run before parsing jobs or evaluating workflow-level concurrency, so
run.IDis populated in time for every expression that readsgithub.run_id— not just the concurrency group, but alsorun-name, job names, andruns-on.jobparser.Parsenow runs inside theInsertRuntransaction, afterdb.Insert(ctx, run). Workflow-level concurrency evaluation runs next and only mutatesrunin memory. All concurrency-derived fields (raw_concurrency,concurrency_group,concurrency_cancel) plusstatusandtitleare persisted in a single finalUpdateRunat end-of-transaction — oneINSERT+ oneUPDATEper run in both the concurrency and non-concurrency paths (matches pre-branch parity, one fewerUpdateRepoRunsNumbersCOUNTthan the interim state).GenerateGiteaContextnow setsrun_idfromrun.IDunconditionally; every caller passes a persisted run.Verification: tested end-to-end on a 1.26 deployment. Before the patch, two successive
cipushes (one to master, one to a feature branch) cross-cancelled each other. After the patch, the same pushes — in both orders (master→branch, branch→master) — run to completion simultaneously across 15+ runs with zero cancellations.Regression tests in
services/actions/context_test.go:TestEvaluateRunConcurrency_RunIDFallback— unit check thatEvaluateRunConcurrencyFillModelresolvesgithub.run_idfromrun.ID.TestPrepareRunAndInsert_ExpressionsSeeRunID— full-flow check: callsPrepareRunAndInsertwith${{ github.run_id }}in bothrun-nameand the concurrency group, then asserts the persistedTitle,ConcurrencyGroup, andRawConcurrencycontain / survive the run's ID. Re-orderingdb.Insertrelative to either parse or concurrency eval fails this test.Relation to #37119
#37119 also moves concurrency evaluation into
InsertRunbut keeps it beforedb.Insert, then tries to populaterun_idonly whenrun.ID > 0— which is still0at that call site, so the cross-branch leak would survive that PR as written. This PR fixes the ordering so thatrun.IDis actually populated at eval time, and broadens it to cover parse-time expression interpolation too.This PR was written with the help of Claude Opus 4.7