Skip to content

ci: dispatch UI tests from a default-branch workflow; PR CI keeps no write token - #15226

Merged
teamleaderleo merged 5 commits into
mainfrom
ci-ui-tests-dispatch-from-main
Sep 28, 2026
Merged

teamleaderleo merged 5 commits into
mainfrom
ci-ui-tests-dispatch-from-main

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Pull request CI no longer holds actions: write. The ui-tests job in ci.yml was the one job with it, and a pull_request run takes ci.yml from the pull request, so a same-repository author could rewrite that job. #15193 made it run main's dispatcher but left the token in PR CI.

Now the dispatch runs in a new workflow, ci-ui-tests.yml, which always runs from the default branch. It starts on every CI run attempt (workflow_run: requested).

  • ci.yml ui-tests (contents and actions read only) validates each selector as cmuxUITests/<Class>[/<method>] and uploads them as ui-tests-request-<attempt>. It then waits for the dispatch run serving its attempt and reports that run's verdict, so UI tests still start on their own, still gate ci-status, and the result stays on the pull request.
  • ci-ui-tests.yml reads the CI attempt from the API. It serves only a same-repository pull_request run of .github/workflows/ci.yml, and returns at once when the pull request changes nothing under cmuxUITests/. Otherwise it waits for the request and checks it again: the head SHA must equal the one GitHub reports, the selectors must match the same pattern, and the merge SHA is used only to fetch objects. It then runs main's dispatcher with routing variables it reads itself. If the CI attempt ends first (a newer push, or ui-tests gave up), it cancels the dispatched run, unless the dispatcher only attached to someone else's identical run.
  • A pass requires the dispatch step itself to have succeeded, so a dispatch run that found no request never reads as green.
  • Re-runs by the owned-pool rescue and failure attribution use GITHUB_TOKEN, which may emit no workflow_run event. Those two now dispatch ci-ui-tests.yml for the new attempt themselves. A duplicate joins the same concurrency group.

Transition: open pull requests still on the old ci.yml keep dispatching from their own job. The new workflow finds no request for them and exits when their attempt completes, so nothing is dispatched twice. The new workflow only acts once this merges.

Tests: tests/test_ci_ui_tests_dispatch.py (new, 24 cases: validation, request wait, verdict lookup, cancellation, workflow shape), plus the updated test_ci_change_areas (no job in ci.yml has actions write), test_ci_owned_pool_rescue, test_ci_classify_failures, test_ci_workflow_run_sources, test_ci_fork_runner_routing, test_ci_linux_guard_routing, and actionlint, all passing locally.

— Icicle g1 ⚙️ (run_worker_20260927_686a3a99)

🤖 Generated with Claude Code


Summary by cubic

Removes the actions: write token from PR CI. The ui-tests job was the only job holding it, and a pull_request run takes ci.yml from the pull request, so a same-repository author could rewrite that job; the UI test dispatch now happens in ci-ui-tests.yml, which always runs from the default branch.

The ui-tests job (now actions: read) validates the selectors, uploads them as ui-tests-request-<attempt>, waits for the dispatch run serving that attempt, and reports its verdict, so UI tests still start on their own and still gate ci-status. ci-ui-tests.yml serves only same-repository pull requests, re-validates the head SHA and selector pattern, runs main's dispatcher, and cancels the dispatched run when the CI attempt ends first, unless the dispatcher attached to someone else's identical run.

  • No job in ci.yml holds actions: write, and the new workflow's permissions block is empty.
  • A pass requires the dispatch step itself to have succeeded, so a dispatch run that found no request is never green.
  • Re-runs by the owned-pool rescue and failure attribution dispatch ci-ui-tests.yml for the new attempt themselves, since a GITHUB_TOKEN re-run may emit no workflow_run event; duplicates join the same concurrency group. The rescue passes the attempt it started (attempt + 1), because a read right after the re-run can still report the old attempt.
  • Adds scripts/ci/ui_tests_dispatch.py and tests/test_ci_ui_tests_dispatch.py, both registered in the guard and execution test suites.

Migration

  • Open pull requests still on the old ci.yml keep dispatching from their own job; the new workflow finds no request for them and exits when their attempt completes, so nothing is dispatched twice.

Written for commit a5a2b74. Summary will update on new commits.

Review in cubic

teamleaderleo and others added 2 commits September 28, 2026 04:04
…-only

ci.yml's ui-tests job held actions: write, and a pull_request run takes
ci.yml from the pull request. The job now validates the selectors, uploads
them as ui-tests-request-<attempt>, and waits for the verdict of
ci-ui-tests.yml, which runs from the default branch on every CI run
attempt (workflow_run: requested), re-validates the request against the
run GitHub reports, runs main's dispatcher, and cancels the dispatched run
when the CI attempt ends first. No job in ci.yml holds actions: write.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Find a queued labeled run's dispatch run from the run's creation, and
  only a default-branch dispatch run counts.
- exec the dispatcher so a cancelled step reaches it and it cancels the
  dispatched run; never cancel a run it only attached to.
- Do not dispatch for an attempt that already completed.
- Bot re-runs (owned-pool rescue, failure attribution) start the dispatch
  for the new attempt themselves, since a GITHUB_TOKEN re-run may emit no
  workflow_run event.
- Retry single reads; read the request every two minutes; fall back from
  the App token only on 401/403.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 0d061be5-df1a-4947-b116-2f0f6e0a16a9

📥 Commits

Reviewing files that changed from the base of the PR and between 4c15bb3 and a5a2b74.

📒 Files selected for processing (14)
  • .github/workflows/ci-guards.yml
  • .github/workflows/ci-ui-tests.yml
  • .github/workflows/ci.yml
  • scripts/ci/choose_ci_suite.py
  • scripts/ci/classify_failures.py
  • scripts/ci/owned_pool_rescue.py
  • scripts/ci/ui_tests_dispatch.py
  • scripts/ci/workflow_guard_groups.py
  • tests/test-execution.toml
  • tests/test_ci_change_areas.py
  • tests/test_ci_classify_failures.py
  • tests/test_ci_fork_runner_routing.py
  • tests/test_ci_owned_pool_rescue.py
  • tests/test_ci_ui_tests_dispatch.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Dogfood build of a5a2b74278be1d7d61db6265873105e94adfafa0

cmux DEV pr-15226-a5a2b742.app

The link opens this exact commit in the cmux dev menu bar app. The build starts on each push and the page waits until it is ready; a newer push replaces it. It signs in against production, so Cloud or backend changes still need a tagged build with a development backend.

A read right after the re-run may still show the old attempt, so the
rescue passes target.attempt + 1 instead of reading it back.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

CI failure attribution

CI passes on a5a2b74278 (run 36398046055 attempt 1).

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's.

teamleaderleo and others added 2 commits September 28, 2026 04:27
…, not a sleep

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Catch-up merge by scripts/ci/catch_up_pr.py (RFC #14631).
Merged by scripts/merge-main.sh: mf/main at 4c15bb3.

Catch-up-previous-head: a9c9170
Catch-up-base: 4c15bb3
@cursor

cursor Bot commented Sep 28, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@teamleaderleo
teamleaderleo merged commit b0d5083 into main Sep 28, 2026
64 checks passed
@teamleaderleo
teamleaderleo deleted the ci-ui-tests-dispatch-from-main branch September 28, 2026 08:39
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for a5a2b74278: every check was green at merge (17 verified; 17 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 28, 2026
ba94a13 CI: let Iroh release gate reuse unchanged TUI artifact
71a921c fix(web): stop orphaned Cloud VM alert pages (manaflow-ai#15138)
9971c2c Keep newer iOS connections alive when a recovery is superseded (manaflow-ai#15141)
c307ab0 cmux-tui: only connect to derived local sockets served by this user (manaflow-ai#15144)
1220252 codex-teams: keep the watcher's socket password out of its arguments (manaflow-ai#15140)
b3a73f0 chatmux-relay: keep cmux-tui sockets and journal cursors private to this user (manaflow-ai#15156)
b0d5083 ci: dispatch UI tests from a default-branch workflow; PR CI keeps no write token (manaflow-ai#15226)
1255448 test: fix three app-host tests that keep main red (manaflow-ai#15204)
0fc4975 test: pin the fixture PATH inside the zsh watcher sleep test (manaflow-ai#15237)
758aaeb fix(ios): clear read notifications on foreground return (manaflow-ai#14725)
4c15bb3 cmux-browser: stop requiring GPL for web/package.json (manaflow-ai#15231)
97fe6b4 test: keep the Cloud notification harness workspace unselected (manaflow-ai#15215)
61083e3 test: keep workspace cwd inheritance tests off the shared standard defaults (manaflow-ai#15227)
eae4994 Pin password badge actions to their source runtime (manaflow-ai#14921)
fd96369 Check the owner of the Claude shim directory in the app, workspace commands and nushell (manaflow-ai#15185)
0ebf8d7 Fix main-thread freeze during SSH paste detection (manaflow-ai#15113)
a98c560 test: pin font magnification in the Cloud outline attention test (manaflow-ai#15213)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant