-
Notifications
You must be signed in to change notification settings - Fork 3k
fix(ci): run the autofix scan lane on the persistent pool #10055
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2e7c750
3bc6ade
61bd03f
f9e56f4
ad784af
590c32a
4bcd1ca
36f880b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -200,7 +200,10 @@ jobs: | |
| # Full rationale → qwen-autofix.md#af-004 | ||
| if: |- | ||
| ${{ github.repository == 'QwenLM/qwen-code' && (github.event_name != 'issue_comment' || (github.event.issue.pull_request && (startsWith(github.event.comment.body, '@qwen-code /takeover') || startsWith(github.event.comment.body, '@qwen-code /retry')))) && (github.event_name != 'pull_request' || github.event.label.name == 'autofix/takeover') && (github.event_name != 'pull_request_review' || github.event.pull_request.state == 'open') }} | ||
| runs-on: 'ubuntu-latest' | ||
| # Persistent pool, not hosted: a hosted backlog queued route past the cron | ||
| # period, and af-005's supersede then starved every scan round. | ||
| # Full rationale → qwen-autofix.md#af-148 | ||
| runs-on: '${{ (github.repository == ''QwenLM/qwen-code'' && vars.MAINTAINER_ECS_RUNNER_DISABLED != ''true'' && (github.event_name != ''pull_request'' && github.event_name != ''pull_request_review'' || github.event.pull_request.head.repo.full_name == github.repository || contains(fromJSON(''["OWNER","MEMBER","COLLABORATOR"]''), github.event.pull_request.author_association))) && fromJSON(''["self-hosted", "linux", "x64", "ecs-qwen"]'') || fromJSON(''["ubuntu-latest"]'') }}' | ||
| timeout-minutes: 5 | ||
| concurrency: | ||
| # Concurrency is keyed by TARGET, not shared and not fully unique: | ||
|
|
@@ -256,6 +259,23 @@ jobs: | |
| COMMENT_PR_AUTHOR: '${{ github.event.issue.user.login }}' | ||
| HAS_PR_URL: '${{ github.event.issue.pull_request.url }}' | ||
| run: |- | ||
| # gh has its own reroute channels: pin the host, drop planted tokens, | ||
| # and point gh at a fresh empty config dir — on the persistent pool | ||
| # the shared ~/.config/gh is attacker-writable (config.yml can carry | ||
| # http_unix_socket transport reroutes), and a forged collaborator- | ||
| # permission response here would open the /takeover and /retry gates. | ||
| # Mirrors the heavy jobs' preamble. Full rationale → qwen-autofix.md#af-148 | ||
| export GH_HOST=github.com | ||
| unset GH_ENTERPRISE_TOKEN GH_TOKEN | ||
| # `export VAR="$(...)"` reports export's status, not the | ||
| # substitution's: a failing mktemp must abort the step, not continue | ||
| # with an empty GH_CONFIG_DIR that gh treats as unset — falling back | ||
| # to the shared ~/.config/gh this preamble closes. | ||
| if ! GH_CONFIG_DIR="$(mktemp -d "${RUNNER_TEMP}/autofix-gh-config.XXXXXX")"; then | ||
| echo "::error::could not create gh config dir; refusing to run gh without reroute hardening" | ||
| exit 1 | ||
| fi | ||
| export GH_CONFIG_DIR | ||
| DO_ISSUE=false | ||
| DO_REVIEW=false | ||
| TAKEOVER_ACK='' | ||
|
|
@@ -2054,7 +2074,8 @@ jobs: | |
| needs: 'route' | ||
| if: |- | ||
| ${{ needs.route.outputs.do_review == 'true' }} | ||
| runs-on: 'ubuntu-latest' | ||
| # Same pool decision as route. Full rationale → qwen-autofix.md#af-148 | ||
|
wenshao marked this conversation as resolved.
wenshao marked this conversation as resolved.
|
||
| runs-on: '${{ (github.repository == ''QwenLM/qwen-code'' && vars.MAINTAINER_ECS_RUNNER_DISABLED != ''true'' && (github.event_name != ''pull_request'' && github.event_name != ''pull_request_review'' || github.event.pull_request.head.repo.full_name == github.repository || contains(fromJSON(''["OWNER","MEMBER","COLLABORATOR"]''), github.event.pull_request.author_association))) && fromJSON(''["self-hosted", "linux", "x64", "ecs-qwen"]'') || fromJSON(''["ubuntu-latest"]'') }}' | ||
| timeout-minutes: 15 | ||
| # A forced scan can write the same status comment as review-address. | ||
| # Share its per-PR lock so neither writer can erase the other's state. | ||
|
|
@@ -2072,6 +2093,11 @@ jobs: | |
| enum_failed: '${{ steps.scan.outputs.enum_failed }}' | ||
| env: | ||
| REPO: '${{ github.repository }}' | ||
| # Per-run home for the scan's API dumps. A fixed autofix* name (not | ||
| # mktemp's tmp.*) so the age sweep in the heavy jobs can reclaim it | ||
| # after a hard runner kill; cleaned normally by the always() step. | ||
| # Full rationale → qwen-autofix.md#af-148 | ||
| WORKDIR: '/tmp/autofix-scan-${{ github.run_id }}' | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] Nothing pins this value — specifically the expect(reviewScanJob).toContain("WORKDIR: '/tmp/autofix-scan-${{ github.run_id }}'");中文说明没有任何钉扎固定这个值——尤其是 (修复代码见上方代码块。) — qwen3.8-max via Qwen Code /review (v0.22.0)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Applied in f9e56f4 — the exact value WORKDIR: '/tmp/autofix-scan-${{ github.run_id }}' is pinned beside the other scan-lane pins, with a comment naming the autofix* prefix as the age-sweep contract. Flip-checked: the /tmp/scan- prefix mutant now fails the suite. |
||
| steps: | ||
| - name: 'Scan for PRs with new feedback' | ||
| id: 'scan' | ||
|
|
@@ -2083,6 +2109,24 @@ jobs: | |
| REVIEW_SENDER: '${{ needs.route.outputs.review_sender }}' | ||
| DISPATCH_SOURCE: "${{ github.event_name == 'workflow_dispatch' && inputs.source || '' }}" | ||
| run: |- | ||
| # gh reroute hardening, mirroring the heavy jobs: pin the host, drop | ||
| # planted tokens, and use a fresh empty config dir — the pool's | ||
| # shared ~/.config/gh is attacker-writable, and a config.yml with an | ||
| # http_unix_socket reroute would swallow this step's gh calls, | ||
| # CI_DEV_BOT_PAT in the Authorization header included. | ||
| # Full rationale → qwen-autofix.md#af-148 | ||
| export GH_HOST=github.com | ||
| unset GH_ENTERPRISE_TOKEN GH_TOKEN | ||
| # `export VAR="$(...)"` reports export's status, not the | ||
| # substitution's: a failing mktemp must abort the step, not continue | ||
| # with an empty GH_CONFIG_DIR that gh treats as unset — falling back | ||
| # to the shared ~/.config/gh this preamble closes. | ||
| if ! GH_CONFIG_DIR="$(mktemp -d "${RUNNER_TEMP}/autofix-gh-config.XXXXXX")"; then | ||
| echo "::error::could not create gh config dir; refusing to run gh without reroute hardening" | ||
| exit 1 | ||
| fi | ||
| export GH_CONFIG_DIR | ||
|
|
||
| # Every lane that reaches this scan is supposed to hold the PAT: | ||
| # route now declines the one event GitHub is known to run without | ||
| # secrets (a fork PR's own review) before it can set do_review. | ||
|
|
@@ -2092,17 +2136,28 @@ jobs: | |
| exit 1 | ||
| fi | ||
|
|
||
| # Pre-clean before create, mirroring the heavy jobs: run_id is | ||
| # public and sequential, and mkdir -p alone would succeed over a | ||
| # dir or symlink pre-planted on the shared pool /tmp — the scan's | ||
| # redirects would then land in an attacker-chosen place, and a | ||
| # planted bot-prs.json would feed the forced-PR guard below. | ||
| rm -rf "${WORKDIR}" | ||
| (umask 077; mkdir -p "${WORKDIR}") | ||
|
|
||
| # Fleet visibility: every per-PR decision below also records a row so | ||
| # the run summary shows the WHOLE managed fleet in one table. | ||
| # Reconstructing this by hand (list bot PRs, regex each one's eval | ||
| # markers, cross-check checks and fork state) was the only way to see | ||
| # a stall, so stalls stayed invisible until someone went looking. | ||
| FLEET_FILE="$(mktemp)" | ||
| trap 'rm -f "${FLEET_FILE}"' EXIT | ||
| # Inside WORKDIR, not mktemp's /tmp/tmp.*: on a cancelled run the | ||
| # EXIT trap never fires, and only the always() step and the heavy | ||
| # jobs' autofix* age sweep reclaim what this step leaves — neither | ||
| # can reach a tmp.* name. | ||
| FLEET_FILE="${WORKDIR}/fleet.tsv" | ||
| trap 'rm -f "${FLEET_FILE}"; rm -rf "${WORKDIR}"' EXIT | ||
| fleet_row() { | ||
| printf '%s\t%s\t%s\n' "$1" "$2" "$3" >> "${FLEET_FILE}" | ||
| } | ||
| WORKDIR="$(mktemp -d)" | ||
|
|
||
| read_forced_pr_meta() { | ||
| local attempt meta | ||
|
|
@@ -3264,6 +3319,16 @@ jobs: | |
| echo "targets=${TARGETS}" >> "${GITHUB_OUTPUT}" | ||
| echo "has_targets=$([[ "${COUNT}" -gt 0 ]] && echo true || echo false)" >> "${GITHUB_OUTPUT}" | ||
|
|
||
| # Nothing else removes the per-run WORKDIR; on the persistent pool | ||
| # every scan would leave its API dumps behind forever. always() covers | ||
| # cancellation (the in-step EXIT trap does not fire on a killed run); | ||
| # only a hard runner kill abandons the dir, and the autofix* age sweep | ||
| # in the heavy jobs reclaims it. Mirrors issue-autofix's cleanup step. | ||
| # Full rationale → qwen-autofix.md#af-148 | ||
| - name: 'Clean up scan workdir' | ||
| if: 'always()' | ||
| run: 'rm -rf "${WORKDIR}"' | ||
|
|
||
| # =========================================================================== | ||
| # REVIEW PHASE (build) — compile the trusted-base CLI bundle ONCE per scan | ||
| # and fan it out to the address legs as an artifact. Each leg otherwise | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-blocking nit: this records
404284, butqwen-autofix.ymlat the head commit is 405,204 bytes — the final "fail loud when the scan lane's gh config dir cannot be minted" commit grew the file by 920 bytes without re-bumping (verified via the contents API:404284at both590c32aand the merge4bcd1ca,405204at36f880b). Well within the 4,096-byte growth allowance, so the ratchet stays green — but since the previous commit made this baseline exact again, a re-bump to405204would keep it tight and preserve the full allowance headroom for the next PR that touches this file.非阻断小问题:这里记录的是
404284,但 head 提交上qwen-autofix.yml实际为 405,204 字节——最后一个"fail loud"提交让文件涨了 920 字节却没有同步 bump(经 contents API 核实:590c32a与合并提交4bcd1ca均为 404284,36f880b为 405204)。远在 4,096 字节增长容差之内,ratchet 保持绿色——但既然前一个提交刚把基线调回精确值,顺手 re-bump 到405204能保持基线收紧,也给下一个改这个文件的 PR 留足容差。