Repository navigation
ci(cla-rerun): start the CLA janitor on each CLA failure; re-run guard rejects on PRs that propose no policy - #25525
Conversation
…d rejects on PRs that propose no policy The CLA quota janitor ran only on a cron GitHub fired late or not at all (12:35Z to 14:19Z on 2026-10-26, while #25466 sat blocked 80 min), and a pass that found the GITHUB_TOKEN budget spent with the reset over 15 min away did nothing (15:42Z: 0 of 5000 left, reset 16:13Z). - Trigger on workflow_run completed of CLA Assistant and CLA policy guard: a pull request's failure, or the completion of a re-run (so a backlog drains pass by pass). The cron stays as the fallback. Concurrency moves to the job so comment-triggered CLA runs, which start no job, never displace a pending pass. - Wait up to 40 min (was 15) for a near reset; job timeout 47 min. - New guard evidence that needs no x-ratelimit header or 403 wording: a pull request whose files touch none of the paths validate-cla-policy.rb reads as policy proposes no policy, so only a failed read can reject it (attempts 1 and 2 only). A test keeps POLICY_PATHS equal to the guard's lists. - Read open pull requests most recently updated first (over 500 are open). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
|
All contributors have signed the CLA ✍️ ✅ |
|
Owned by an agent session · session |
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Passes: CI passes on CI passes on Written by
Merge receipt for |
…ce a retry heuristic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
…B_TOKEN as fallback (#25611) The guard's GitHub reads (the pull request, its files, the test merge and, for a policy change, the reviews) now use a token minted from the manaflow-glaeda-route App: GITHUB_TOKEN's core budget, shared by every workflow, ran out hourly on 2026-10-26 and the guard then rejected every pull request until the reset (#25525). - cla-policy-guard.yml: a pinned actions/create-github-app-token step (read-only contents and pull-requests, this repository only, continue-on-error, 1-minute timeout) after the checkout verification; the validation step reads steps.glaeda-token.outputs.token || secrets.GITHUB_TOKEN. Its shell is unchanged. - validate-cla-policy.rb admits exactly that layout. Any write permission, other action, moved key, missing fallback or reordered step is rejected (new regression cases). EXPECTED_GUARD_WORKFLOW_DIGEST and EXPECTED_GUARD_SCRIPT_DIGEST move to the new bytes. - tests/test_cla_guard_metadata_routing.py pins both digests to the files and checks the read-only, fallback and rejection contract. Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The CLA quota janitor (#25415) re-ran quota-caused CLA failures, but too late. p0-swift-linux reported that from about 12:40Z on 2026-10-26 the CLA policy guard rejected every PR, and #25466 was blocked for 80 minutes.
Root cause (from the run logs)
gh apiread (api_jsonraisesPolicyError, and the guard prints only "rejected the proposed policy"). CLA Assistant runs for the same PRs at the same moments loggedAPI rate limit exceeded for installation, for example run 40355511173 at 16:04:27Z next to guard 40355524808 at 16:04:22Z on ci(cmux-next): DEV publish retries a release call the rate limit refused #25517, and 40354478049 next to 40354477800 on ci(rescue): wait through GitHub rate limits instead of leaving a cancelled run un-re-run #25510.*/10cron fired at 12:35Z and then not again until 14:19Z (104 min). That gap matches ci(cmux-next): re-land Linux DEV signing with the signer executable, and guard script modes #25466's 80 minutes.Change
ci-cla-quota-rerun.ymlnow also runs onworkflow_runcompletedof CLA Assistant and CLA policy guard. A job starts only for apull_request_targetrun that failed, or for a completed re-run (attempt above 1), so a backlog drains one pass after another. The cron stays as a fallback. No new secrets, no permission changes, and nopull_request_target. The job reads nothing from the triggering run and checks out its own default-branch script.SOURCE_WORKFLOW_PATHSis declared, astest_ci_workflow_run_sourcesrequires.skipped) never take the pending slot.x-ratelimitheader, no 403 wording and no CLA Assistant failure: if a PR's files (pulls/N/files, at most 3 pages) touch none of the pathsvalidate-cla-policy.rbreads as policy (CLA_POLICY_PATHS+GUARD_PATHS, renames included), the PR proposes no policy and a failed read is the likely cause. This is a retry heuristic, not proof: a stale event base, or an old policy with no usable test-merge commit, can still be rejected for real. So it is used on attempts 1 and 2 only, and a real reject of that kind stays failed after that. A test keepsPOLICY_PATHSequal to the guard's own lists.sort=updated). More than 500 are open, and a fresh reject's PR was just updated.A real policy reject still fails: when a PR changes a policy path, the guard is re-run only on the existing API-failure evidence.
Not changed: the guard's own token
The guard's
GH_TOKENis pinned to${{ secrets.GITHUB_TOKEN }}byvalidate-cla-policy.rb(GUARD_VALIDATE_ENV), and the guard workflow's bytes are digest-pinned (EXPECTED_GUARD_WORKFLOW_DIGEST). Moving it to the glaeda-route App budget, as #25408 did for risk tier, would mean exposing the App key to apull_request_targetcontrol-plane workflow. That is a trust-policy change, so this PR does not make it.Risk
Low and CI-only. A pass reads about 12 calls from the App's own budget and makes only the free
rate_limitread of the workflow token. Failure triggers that arrive during a pass collapse into one pending pass. A run that keeps failing for real stops atMAX_GUARD_ATTEMPT/NO_POLICY_MAX_ATTEMPT.Tests
cmux-ci test(fast-checks run 40357180685):tests/test_cla_quota_rerun.pyplus the workflow_run-sources, concurrency, job-scoped-permissions, actionlint-coverage and workflow_run-budget suites gave 88 passed. The one failure,test_ci_failfast_keeps_failure_rollups_and_bounds_observed_tails("ci.yml has no tests job"), fails the same way on main.check_workflow_concurrency.pyand actionlint 1.7.7 on the workflow both pass. On the final head,ci-guards.ymlrunstests/test_cla_quota_rerun.py(29 tests OK, and the wiring guard passes).Review: an independent Codex gpt-6-astra xhigh reviewer gave SHIP on head e775a3f, with no blocking findings. Its one nonblocking note (call the no-policy evidence a heuristic) is addressed.
Agent session: agent session
🤖 Generated with Claude Code