Repository navigation
ci: sweep Roadmap board Status every 5 minutes - #623
Conversation
Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
…k on changes requested Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
robinnsc
left a comment
There was a problem hiding this comment.
One question first: has an Actions policy allowing pull_request_target been set up for this repo or this workflow? GitHub is rolling out a default rule that disables pull_request_target on public repos without an allowing event policy, enforced from December 2 (changelog, docs). No workflow on main uses it today, so unless a policy is added, the opened, reopened, ready_for_review and review_requested runs would start failing then, leaving only the issues and same-repo review runs. We couldn't read the org or repo policy to confirm. A scheduled sweep from main would be one alternative that needs no fork-triggered runs.
Otherwise, the script doesn't interpolate any payload text into the script or the GraphQL query, and it never checks out PR code, so there's no injection or code-execution path from a fork. Two things about the description:
- It's behind the second commit. Drafts are no longer skipped (they move to In Progress on open, review request and any review), a card in Review does move back on changes requested, the
issuesassigned/unassigned trigger isn't mentioned, and neither is the header's instruction to turn off the board's built-in "Code changes requested" workflow. PROJECT_TOKENis already set, andpull_request_reviewruns the workflow from the PR's merge ref, so reviews on this PR (including this one) run the script against the live board before merge. It should do little here since the PR closes no issues, but it's worth knowing those are the first end-to-end runs.
| if: >- | ||
| github.event_name != 'pull_request_review' || | ||
| github.event.pull_request.head.repo.full_name == github.repository | ||
| runs-on: extenddb_ubuntu-2404_4-core |
There was a problem hiding this comment.
On main the 4-core pool is only used for the Rust build and test jobs, and every lightweight job runs on ubuntu-latest, which is free for a public repo. This job makes a few GraphQL calls on every issue assign/unassign and every PR event, and with pull_request_target forks can start it without approval, so ubuntu-latest would keep it out of the queue the merge checks wait on. Unassign events that still leave assignees could also be filtered in the job's if: (for example with toJSON(github.event.issue.assignees) != '[]') so they don't start a runner at all.
There was a problem hiding this comment.
Both jobs now run on ubuntu-latest (L52, L103), so the merge-check pool is untouched.
On filtering unassign events: forks can't start runs any more, and only people with triage access can assign or unassign. Each run sweeps the whole board, so an extra run just catches up. I left it unfiltered on purpose, so the issue-triggered run also works as a fast catch-up when scheduled runs are delayed. Happy to add toJSON(github.event.issue.assignees) != '[]' if you'd still prefer it, so I'll leave this thread open for you.
Addresses review on #623: no pull_request_target (off by default from 2026-12-02), runs only from main via a main-only environment, uses a GitHub App token, pins actions to SHAs, runs on ubuntu-latest, ignores author/bot reviews, ignores Closes # from untrusted PRs, and leaves archived, unknown-status and hand-moved cards alone. Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
- Read hand moves from the issue/PR timeline's last status-change event on this board; Status.creator is the first creator and never changes. - An issue's hand move is released by its trusted linked PR changing too. - Use latestOpinionatedReviews for verdicts so an old changes-requested is never lost past the last 30 reviews. - Warn when linked-PR lists are truncated. - environment deployment: false; step names; separate dry-run concurrency group; setup notes name the right built-in workflows. Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
|
In the next revision, will push the tests for this change along with some failure modes which are being tested. |
- Health: rewrite a 'Board sweep: ...' draft card on the board each run, and a report job opens one alert issue on failed/degraded runs and closes it on the next clean run. - Re-requested review after changes requested moves a PR to Review. - 'Auto status = Off' board field holds a card permanently. - Retry GraphQL calls with backoff; stop early on a low rate limit. - Fetch full linked-PR lists when the first page is truncated. - Report renamed status options, a missing Status field, conflicting built-in board workflows, and cards the App cannot read. - Run on issue assigned/unassigned too, for faster issue updates. - Token covers the repos the App is installed on, not just extenddb. - Add node:test unit tests and a Scripts test workflow. Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
|
@robinnsc thanks for the thorough review. I reworked the PR around your
Tests are in: 44 |
Scheduled and issue-triggered runs only happen while the repo variable PROJECT_SWEEP_ENABLED is 'true'. Manual runs always work, so the sweep can be dry-run after merge before it moves any card, and paused later by deleting the variable. Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
The repo is public, so Actions logs are public; the board is not. - Log one line of totals only: no issue/PR numbers, statuses, draft counts or board settings. - Put every detail (moves, problems, skipped) on the private 'Board sweep: ...' health card; dry runs write only that card. - Remove the report job: it opened a public issue describing the private board. - Fail the run when the health card cannot be written, since it is now the only alert channel. - Tests: public log leaks nothing, card has the details, card write failure fails the run. Signed-off-by: navareamol <28789438+navareamol@users.noreply.github.com>
|
Pushed 09a6b77: privacy fix. This repo is public, so Actions logs are public while the board is not. The sweep now logs one line of totals only. Every detail goes to a board-only |
What
Adds a sweep that sets Status on the ExtendDB org Project board from the real
state of each open issue and PR. CI-only; no product code changes.
.github/workflows/project-status-sweep.ymldry_runinput)..github/scripts/project-status-sweep.js.github/scripts/project-status-sweep.test.jsnode --test), no dependencies..github/workflows/scripts-test.yml.github/scripts/.Also removes
project-review-status.yml, added in this branch's first commits.How it works
flowchart TD A[Schedule, issue assigned/unassigned, or manual run; always from main] --> B[Mint short-lived GitHub App token] B --> C[Read all board items, 50 per page, with retries] C --> D{For each item} D -->|archived, draft, closed, unreadable| S[Skip] D -->|Status not Todo / In Progress / Review| S D -->|Auto status = Off| S D -->|person moved it, nothing changed since| S D --> E{Issue or PR?} E -->|PR| F[Status from draft flag, human reviews, review requests] E -->|Issue| G[Status from assignees and trusted open PRs] F --> H{Same as now?} G --> H H -->|yes| S H -->|no| I[Set Status, retried on error] I --> J[Write details to the private 'Board sweep:' card] S --> J J --> K[Public log: one line of totals]Cases it handles
Closes #NCloses #NAuto statusfield set to OffPrivacy
This repo is public, so the workflow's Actions logs are public; the board is
private. The sweep keeps the board's contents out of anything public:
Sweep ok: 3 card(s) moved, 0 problem(s), query cost 54.No issue or PR numbers, statuses, draft counts or board settings.
draft card,
Board sweep: ..., which only org members can see.Failure modes and how they are handled
Auto status = Offholds a card for good. Hand moves still hold until the work changes.reviewRequestsno longer blocks; card goes to Review.deployment: falseand the branch ruleWhy
The board's built-in workflows have no "review requested/approved" trigger, and
"Pull request linked to issue" moves cards for any PR, including outside ones.
Every trigger here runs from the default branch, so no fork can start it, and
it needs no
pull_request_target(off by default for public repos from 2026-12-02).Addresses the earlier review on this PR: no
pull_request_target; no secretreachable from a non-main ref (environment limited to
main); GitHub App token,not a personal PAT; actions pinned to SHAs;
ubuntu-latest; author and botreviews ignored;
Closes #from untrusted PRs ignored; unknown statuses,archived cards and missing options left alone and flagged, not a red run.
No linked issue.
Setup (done)
Repository → Issues, Pull requests, Metadata read; no webhook; installed on
extenddb.project-board, deployment branchesmainonly, with variablePROJECT_APP_CLIENT_IDand secretPROJECT_APP_PRIVATE_KEY.Auto statusfield (single select, optionOff) is on the board.PROJECT_TOKENrepo secret is deleted.After merge: run the workflow once with
dry_run: trueand read the board'sBoard sweep: DRY RUN ...card.Testing done
project-status-sweep.test.jscovering every case, failuremode and the privacy rule above, with a fake GitHub client. Checked that they
fail when the re-request, author-reply, trust, retry, hold, rate-limit,
card-failure and log-privacy logic is broken. CI runs them with Node.
the sweep in dry-run mode: query cost 54 per sweep, 0 problems, and the public
log line contained only totals.
main.Checklist
cargo test,cargo fmt,cargo clippy(no Rust changes).github/scripts/project-status-sweep.test.js)Storage, auth model, on-disk format or CLI change)ADR / RFC: n/a
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.