Repository navigation
fix(ci): make autofix verification gates hermetic to runner git config #8961
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 2 commits
ef871f3
1213ee8
e0031b8
e7cb3b4
1cfa5e0
aff0a97
0dcf714
39b9d12
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 |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #!/usr/bin/env bash | ||
| set -uo pipefail | ||
|
|
||
| # Re-sanitizes the git config surfaces a PAT-bearing git step is about to | ||
| # read, AFTER branch/agent code has run on the host. The inlined job-start | ||
| # sanitize steps are pre-checkout hygiene; between them and the push, the | ||
| # verification gates run branch test code on the host and the sandboxed | ||
| # agent has the workspace mounted — either can plant exec keys in the | ||
| # repo's LOCAL .git/config (the highest-precedence file, which the push | ||
| # reads) or rewrite the runner user's REAL global config: the gates' env | ||
| # redirect is inherited-env enforcement, not a filesystem boundary — a | ||
| # direct file write, `env -u GIT_CONFIG_GLOBAL git config --global`, or | ||
| # `git config --file "$HOME/.gitconfig"` all bypass it (probe-verified in | ||
| # the #8961 review). | ||
| # | ||
| # Invoked as `bash "${RUNNER_TEMP}/resanitize-git-config.sh"` from the | ||
| # copy the staging step took off the TRUSTED base checkout — never from | ||
| # the working tree, which holds the branch under test at call time. | ||
| # | ||
| # The allowlist and denylist are copies of the inlined pre-checkout | ||
| # sanitize steps in qwen-autofix.yml (which cannot call this script: it | ||
| # does not exist on disk before their checkout). The workflow contract | ||
| # tests pin every copy byte-identical — edit them together. | ||
|
|
||
| if [ -e .git ]; then | ||
| # Worktree-scoped config first, then the local allowlist sweep — same | ||
| # ordering rationale as the inlined step (config.worktree can carry | ||
| # core.hooksPath and is invisible to `git config --local`). | ||
| rm -f "$(git rev-parse --git-path config.worktree 2>/dev/null || echo /nonexistent)" 2>/dev/null || true | ||
| git config --local --unset-all extensions.worktreeConfig 2>/dev/null || true | ||
|
Comment on lines
+37
to
+38
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. Fixed in 1cfa5e0 — resanitize now |
||
| git config --local --name-only --list 2>/dev/null \ | ||
| | { grep -ivE '^(core\.(repositoryformatversion|bare|filemode|symlinks|ignorecase|precomposeunicode|logallrefupdates|worktree|hidedotfiles|protecthfs|protectntfs)|remote\.[^.]+\.(url|fetch|pushurl)|branch\.|extensions\.|gc\.|pack\.|fetch\.|index\.|safe\.|submodule\.[^.]+\.(url|active|branch))' || true; } \ | ||
|
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. Addressed in 1cfa5e0 — the fork and salvage fetches carry |
||
| | while IFS= read -r key; do git config --local --unset-all "$key" 2>/dev/null || true; done | ||
| fi | ||
| { git config --global --name-only --list 2>/dev/null || true; } \ | ||
| | { grep -iE '^(core\.(hookspath|fsmonitor|pager|editor|sshcommand|askpass|alternaterefscommand|gitproxy)$|diff\.external$|diff\..+\.(command|textconv)$|merge\..+\.driver$|filter\.|alias\.|pager\.|difftool\.|mergetool\.|interactive\.difffilter$|sequence\.editor$|gpg\.(.+\.)?program$|init\.templatedir$|remote\..+\.(uploadpack|receivepack)$|submodule\..+\.update$|include\.|includeif\.|protocol\.ext\.allow$)' || true; } \ | ||
| | while IFS= read -r key; do git config --global --unset-all "$key" 2>/dev/null || true; done | ||
|
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. Fixed in e0031b8 — reproduced your probe independently on git 2.55 (listing omits XDG keys, |
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,29 @@ set -eo pipefail | |||||||
| # environment from the caller. WORKDIR and BRANCH are job-level env; | ||||||||
| # GITHUB_OUTPUT and RUNNER_TEMP are runner-provided. None is defined here. | ||||||||
|
|
||||||||
| # Deterministic verification must not read the RUNNER's git config: the | ||||||||
| # persistent pool accumulates state, and a leaked global exec knob fails | ||||||||
| # branch tests the branch never caused. Measured counterexample, run | ||||||||
| # 31516789251: a stray `diff.external=global-driver` in the runner user's | ||||||||
| # ~/.gitconfig killed four per-hunk probe tests in packages/cli on #8613 — | ||||||||
| # charged to the round (package tests are A/B-exempt), which burned the | ||||||||
| # 18-minute repair on a failure no repair can reach and ended the round as | ||||||||
| # a timeout. Every git this script or its checks spawn (vitest fixture | ||||||||
| # repos included) reads a per-run throwaway global config instead — seeded | ||||||||
| # with the workspace safe.directory actions/checkout put in the real one — | ||||||||
| # and no system config — any system-level git setting the checks ever | ||||||||
| # come to depend on (a CA bundle, a proxy) must be replicated via per-job | ||||||||
| # env, not /etc/gitconfig, because the redirect silently drops it. The | ||||||||
| # redirect also keeps a branch-authored `git config --global` from writing | ||||||||
| # durable state onto the host: it lands in the throwaway file and dies | ||||||||
| # with the run. Enforcement is inherited-env only — branch code writing | ||||||||
| # the real file directly bypasses it, which is why the PAT-bearing steps | ||||||||
| # re-run resanitize-git-config.sh afterwards. | ||||||||
| export GIT_CONFIG_SYSTEM=/dev/null | ||||||||
|
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] Failure scenario: a self-hosted runner with corporate proxy in 中文说明[Suggestion] 失败场景:带企业代理的自托管 runner 在 — deepseek-v4-flash via Qwen Code /review (v0.21.10)
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. Fixed in e0031b8 — both gates emit a guarded |
||||||||
| export GIT_CONFIG_GLOBAL="${RUNNER_TEMP}/autofix-gate-gitconfig" | ||||||||
|
Comment on lines
+41
to
+42
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] GIT_CONFIG_SYSTEM=/dev/null redirect undocumented at the system level The throwaway redirect sets GIT_CONFIG_SYSTEM=/dev/null, which silently drops all system-level git config. A future maintainer adds a system-level git config entry that the gates depend on (e.g., a CA bundle for registry access, a proxy, or a credential helper). The redirect silently bypasses it, and the gate fails with an opaque error (TLS error, auth failure). The comment block documents the global config rationale (pool runner pollution) but the system config bypass is not separately explained.
Suggested change
— deepseek-v4-flash via Qwen Code /review (v0.21.8)
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. Fixed in 1213ee8 — both gates' comment blocks now state that system config is bypassed too and that any system-level git setting the checks come to depend on (CA bundle, proxy) must be replicated via per-job env, not /etc/gitconfig.
Comment on lines
+41
to
+42
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. Fixed in e0031b8 — |
||||||||
| : > "${GIT_CONFIG_GLOBAL}" | ||||||||
| git config --file "${GIT_CONFIG_GLOBAL}" safe.directory "$(pwd)" | ||||||||
|
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] Test efficacy: hunk-survived — the Failure scenario: the redirect is silently removed or broken; the ordering test still passes (it checks string presence, not behavior), and the gate runs exposed to the host's global config. 中文说明[Suggestion] 测试有效性:hunk 存活—— 失败场景:重定向被静默移除或破坏;顺序测试仍然通过(它检查字符串存在而非行为),门暴露在宿主机的全局配置下运行。 — deepseek-v4-flash via Qwen Code /review (v0.21.10)
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. Fixed in e0031b8 — the contract test now EXECUTES the extracted redirect block: hostile HOME ( |
||||||||
|
|
||||||||
| # Record whether the agent left a commit FIRST — this is a ref-only | ||||||||
| # diff, so it runs before the failure.md early-exits and covers an | ||||||||
| # agent that commits and then aborts. The failure handoff keys its | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -761,10 +761,39 @@ jobs: | |
| - name: 'Sanitize workspace git config' | ||
| run: |- | ||
| set -uo pipefail | ||
| # The runner USER's global config is the same exec surface as the | ||
| # workspace config below: pool jobs run human-authored code (branch | ||
| # tests) as this user, and a stray `git config --global` outlives | ||
| # the job on the persistent pool. Measured: run 31516789251 found | ||
| # diff.external=global-driver in ~/.gitconfig, failing per-hunk | ||
| # probe tests in every later verification gate on this host. The | ||
| # gates read a throwaway global config now, so this scrub is host | ||
| # hygiene plus protection for THIS job's PAT-bearing git steps, | ||
| # which do read the real file. It runs BEFORE the .git early-exit: | ||
| # host hygiene owes nothing to the workspace existing. Denylist | ||
| # here, not the local allowlist below: the file belongs to the | ||
| # pool image, so routing/credential keys (http.*, url.*, | ||
| # credential.*) may be deliberate infra and are left alone — only | ||
| # the command-execution families go, plus include/includeIf (which | ||
| # can pull any of them back in) and protocol.ext.allow (which arms | ||
| # the command-executing ext:: transport a kept url.insteadOf could | ||
| # redirect to). Subsection slots are `.+`, never `[^.]+`: git | ||
| # subsection names may contain dots (`[diff "a.b"] command` | ||
| # flattens to diff.a.b.command and would slip past `[^.]+`); | ||
| # overmatching is harmless in a denylist. Guarded `|| true` twice: | ||
| # no global file and no match are both normal, and either would | ||
| # kill the step under the default `bash -e` + pipefail otherwise. | ||
| # The same denylist lives in resanitize-git-config.sh, which the | ||
| # PAT-bearing steps re-run AFTER branch code executed on the host; | ||
| # the workflow contract tests pin every copy byte-identical — edit | ||
| # them together. | ||
| { git config --global --name-only --list 2>/dev/null || true; } \ | ||
| | { grep -iE '^(core\.(hookspath|fsmonitor|pager|editor|sshcommand|askpass|alternaterefscommand|gitproxy)$|diff\.external$|diff\..+\.(command|textconv)$|merge\..+\.driver$|filter\.|alias\.|pager\.|difftool\.|mergetool\.|interactive\.difffilter$|sequence\.editor$|gpg\.(.+\.)?program$|init\.templatedir$|remote\..+\.(uploadpack|receivepack)$|submodule\..+\.update$|include\.|includeif\.|protocol\.ext\.allow$)' || true; } \ | ||
| | while IFS= read -r key; do git config --global --unset-all "$key" 2>/dev/null || true; done | ||
|
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. Fixed in e0031b8 — |
||
| # `.git` is a directory in a normal checkout but a gitlink file in | ||
| # a worktree; -e covers both, and a missing .git (first run) too. | ||
| if [ ! -e .git ]; then | ||
| echo "no prior workspace; nothing to sanitize" | ||
| echo "no prior workspace; nothing local to sanitize" | ||
| exit 0 | ||
| fi | ||
| # Worktree-scoped config FIRST: `extensions.worktreeConfig=true` is | ||
|
|
@@ -894,6 +923,7 @@ jobs: | |
| cp .github/scripts/check-settings-schema.sh "${RUNNER_TEMP}/check-settings-schema.sh" | ||
| cp .github/scripts/check-autofix-contracts.sh "${RUNNER_TEMP}/check-autofix-contracts.sh" | ||
| cp .github/scripts/resolve-owning-packages.sh "${RUNNER_TEMP}/resolve-owning-packages.sh" | ||
| cp .github/scripts/resanitize-git-config.sh "${RUNNER_TEMP}/resanitize-git-config.sh" | ||
|
|
||
| - name: 'Check bot credentials' | ||
| env: | ||
|
|
@@ -1402,6 +1432,16 @@ jobs: | |
| run: |- | ||
| BRANCH="autofix/issue-${ISSUE}" | ||
|
|
||
| # Hermetic git config for the gate and every check it spawns, same | ||
| # rationale and shape as run-autofix-review-verification.sh (a | ||
| # leaked global exec knob on the persistent pool must not fail | ||
| # branch tests, and a branch-authored `git config --global` must | ||
| # not outlive the run) — edit the two copies together. | ||
| export GIT_CONFIG_SYSTEM=/dev/null | ||
| export GIT_CONFIG_GLOBAL="${RUNNER_TEMP}/autofix-gate-gitconfig" | ||
|
Comment on lines
+1504
to
+1505
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. Fixed in 1213ee8. New |
||
| : > "${GIT_CONFIG_GLOBAL}" | ||
| git config --file "${GIT_CONFIG_GLOBAL}" safe.directory "$(pwd)" | ||
|
|
||
| if [[ -f "${WORKDIR}/failure.md" && -n "$(git status --porcelain)" ]]; then | ||
| echo "❌ Agent wrote failure.md after leaving a dirty workspace:" | ||
| git status --short | ||
|
|
@@ -1544,14 +1584,25 @@ jobs: | |
| exit 1 | ||
| fi | ||
| BRANCH="autofix/issue-${ISSUE}" | ||
| # The agent and the verification gate ran branch code on the host | ||
| # since the job-start sanitize; re-scrub the local and global git | ||
| # config surfaces this PAT-bearing step is about to read. Invoked | ||
| # from the trusted-base staged copy — the working tree holds the | ||
| # agent-authored branch at this point. | ||
| bash "${RUNNER_TEMP}/resanitize-git-config.sh" | ||
|
Comment on lines
+1713
to
+1714
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. Fixed in 1cfa5e0 — the stage step records the trusted PATH into GITHUB_OUTPUT before any branch code runs, and every PAT step + both gate steps now |
||
| git config --local --unset-all http.https://github.com/.extraheader || true | ||
| git config core.hooksPath /dev/null | ||
| # Authenticate the push with a one-shot, host-scoped credential | ||
| # helper via `git -c`: nothing is written to the reused | ||
| # workspace's .git/config (no error path can strand it there), | ||
| # argv holds only the literal ${GITHUB_TOKEN} reference, and the | ||
| # host scope means it cannot answer a non-GitHub URL. | ||
| git -c credential."https://github.com".helper='!f(){ echo username=x-access-token; echo "password=${GITHUB_TOKEN}"; };f' \ | ||
| # host scope means it cannot answer a non-GitHub URL. The leading | ||
| # empty credential.helper RESETS the inherited helper list first: | ||
| # helpers run in config order and the first to answer wins, so a | ||
| # helper planted at any earlier scope would otherwise see the | ||
| # request (and the env) before ours answers — probe-verified in | ||
| # the #8961 review. | ||
| git -c credential.helper= -c credential."https://github.com".helper='!f(){ echo username=x-access-token; echo "password=${GITHUB_TOKEN}"; };f' \ | ||
| push --no-verify "https://github.com/${REPO}.git" "${BRANCH}" | ||
|
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. Fixed in e0031b8, both legs: the denylist now scrubs |
||
|
|
||
| PR_URL="$(gh pr create --repo "${REPO}" \ | ||
|
|
@@ -3171,10 +3222,39 @@ jobs: | |
| - name: 'Sanitize workspace git config' | ||
| run: |- | ||
| set -uo pipefail | ||
| # The runner USER's global config is the same exec surface as the | ||
| # workspace config below: pool jobs run human-authored code (branch | ||
| # tests) as this user, and a stray `git config --global` outlives | ||
| # the job on the persistent pool. Measured: run 31516789251 found | ||
| # diff.external=global-driver in ~/.gitconfig, failing per-hunk | ||
| # probe tests in every later verification gate on this host. The | ||
| # gates read a throwaway global config now, so this scrub is host | ||
| # hygiene plus protection for THIS job's PAT-bearing git steps, | ||
| # which do read the real file. It runs BEFORE the .git early-exit: | ||
| # host hygiene owes nothing to the workspace existing. Denylist | ||
| # here, not the local allowlist below: the file belongs to the | ||
| # pool image, so routing/credential keys (http.*, url.*, | ||
| # credential.*) may be deliberate infra and are left alone — only | ||
| # the command-execution families go, plus include/includeIf (which | ||
| # can pull any of them back in) and protocol.ext.allow (which arms | ||
| # the command-executing ext:: transport a kept url.insteadOf could | ||
| # redirect to). Subsection slots are `.+`, never `[^.]+`: git | ||
| # subsection names may contain dots (`[diff "a.b"] command` | ||
| # flattens to diff.a.b.command and would slip past `[^.]+`); | ||
| # overmatching is harmless in a denylist. Guarded `|| true` twice: | ||
| # no global file and no match are both normal, and either would | ||
| # kill the step under the default `bash -e` + pipefail otherwise. | ||
| # The same denylist lives in resanitize-git-config.sh, which the | ||
| # PAT-bearing steps re-run AFTER branch code executed on the host; | ||
| # the workflow contract tests pin every copy byte-identical — edit | ||
| # them together. | ||
| { git config --global --name-only --list 2>/dev/null || true; } \ | ||
| | { grep -iE '^(core\.(hookspath|fsmonitor|pager|editor|sshcommand|askpass|alternaterefscommand|gitproxy)$|diff\.external$|diff\..+\.(command|textconv)$|merge\..+\.driver$|filter\.|alias\.|pager\.|difftool\.|mergetool\.|interactive\.difffilter$|sequence\.editor$|gpg\.(.+\.)?program$|init\.templatedir$|remote\..+\.(uploadpack|receivepack)$|submodule\..+\.update$|include\.|includeif\.|protocol\.ext\.allow$)' || true; } \ | ||
| | while IFS= read -r key; do git config --global --unset-all "$key" 2>/dev/null || true; done | ||
| # `.git` is a directory in a normal checkout but a gitlink file in | ||
| # a worktree; -e covers both, and a missing .git (first run) too. | ||
| if [ ! -e .git ]; then | ||
| echo "no prior workspace; nothing to sanitize" | ||
| echo "no prior workspace; nothing local to sanitize" | ||
| exit 0 | ||
| fi | ||
| # Worktree-scoped config FIRST: `extensions.worktreeConfig=true` is | ||
|
|
@@ -3462,10 +3542,39 @@ jobs: | |
| - name: 'Sanitize workspace git config' | ||
| run: |- | ||
| set -uo pipefail | ||
| # The runner USER's global config is the same exec surface as the | ||
| # workspace config below: pool jobs run human-authored code (branch | ||
| # tests) as this user, and a stray `git config --global` outlives | ||
| # the job on the persistent pool. Measured: run 31516789251 found | ||
| # diff.external=global-driver in ~/.gitconfig, failing per-hunk | ||
| # probe tests in every later verification gate on this host. The | ||
| # gates read a throwaway global config now, so this scrub is host | ||
| # hygiene plus protection for THIS job's PAT-bearing git steps, | ||
| # which do read the real file. It runs BEFORE the .git early-exit: | ||
| # host hygiene owes nothing to the workspace existing. Denylist | ||
| # here, not the local allowlist below: the file belongs to the | ||
| # pool image, so routing/credential keys (http.*, url.*, | ||
| # credential.*) may be deliberate infra and are left alone — only | ||
| # the command-execution families go, plus include/includeIf (which | ||
| # can pull any of them back in) and protocol.ext.allow (which arms | ||
| # the command-executing ext:: transport a kept url.insteadOf could | ||
| # redirect to). Subsection slots are `.+`, never `[^.]+`: git | ||
| # subsection names may contain dots (`[diff "a.b"] command` | ||
| # flattens to diff.a.b.command and would slip past `[^.]+`); | ||
| # overmatching is harmless in a denylist. Guarded `|| true` twice: | ||
| # no global file and no match are both normal, and either would | ||
| # kill the step under the default `bash -e` + pipefail otherwise. | ||
| # The same denylist lives in resanitize-git-config.sh, which the | ||
| # PAT-bearing steps re-run AFTER branch code executed on the host; | ||
| # the workflow contract tests pin every copy byte-identical — edit | ||
| # them together. | ||
| { git config --global --name-only --list 2>/dev/null || true; } \ | ||
| | { grep -iE '^(core\.(hookspath|fsmonitor|pager|editor|sshcommand|askpass|alternaterefscommand|gitproxy)$|diff\.external$|diff\..+\.(command|textconv)$|merge\..+\.driver$|filter\.|alias\.|pager\.|difftool\.|mergetool\.|interactive\.difffilter$|sequence\.editor$|gpg\.(.+\.)?program$|init\.templatedir$|remote\..+\.(uploadpack|receivepack)$|submodule\..+\.update$|include\.|includeif\.|protocol\.ext\.allow$)' || true; } \ | ||
| | while IFS= read -r key; do git config --global --unset-all "$key" 2>/dev/null || true; done | ||
| # `.git` is a directory in a normal checkout but a gitlink file in | ||
| # a worktree; -e covers both, and a missing .git (first run) too. | ||
| if [ ! -e .git ]; then | ||
| echo "no prior workspace; nothing to sanitize" | ||
| echo "no prior workspace; nothing local to sanitize" | ||
| exit 0 | ||
| fi | ||
| # Worktree-scoped config FIRST: `extensions.worktreeConfig=true` is | ||
|
|
@@ -3585,6 +3694,7 @@ jobs: | |
| cp .github/scripts/check-autofix-contracts.sh "${RUNNER_TEMP}/check-autofix-contracts.sh" | ||
| cp .github/scripts/resolve-owning-packages.sh "${RUNNER_TEMP}/resolve-owning-packages.sh" | ||
| cp .github/scripts/run-autofix-review-verification.sh "${RUNNER_TEMP}/run-autofix-review-verification.sh" | ||
| cp .github/scripts/resanitize-git-config.sh "${RUNNER_TEMP}/resanitize-git-config.sh" | ||
|
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. Fixed in 1cfa5e0 — the stage step now also records |
||
| # The agent step runs AFTER prepare checks out the PR branch, so | ||
| # invoking the runner from the working tree would execute | ||
| # branch-controlled code on the host with the model key in env | ||
|
|
@@ -3829,7 +3939,7 @@ jobs: | |
| # and fine-grained PATs are documented as NOT receiving it. | ||
| # Prove push access NOW, before an agent round is spent, instead | ||
| # of 403ing at the report step after the work is done. | ||
| if ! git -c credential."https://github.com".helper='!f(){ echo username=x-access-token; echo "password=${GITHUB_TOKEN}"; };f' \ | ||
| if ! git -c credential.helper= -c credential."https://github.com".helper='!f(){ echo username=x-access-token; echo "password=${GITHUB_TOKEN}"; };f' \ | ||
| push --no-verify --dry-run "https://github.com/${HEAD_REPO}.git" HEAD:"${BRANCH}" > /dev/null 2>&1; then | ||
|
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] Fork push preflight step has the Failure scenario: a future maintainer does not understand the purpose of the empty 中文说明[Suggestion] Fork push 预检步骤有 失败场景:未来维护者不理解空 — deepseek-v4-flash via Qwen Code /review (v0.21.10)
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. Fixed in e0031b8 — the fork-preflight site now carries a brief comment naming both the helper-list reset and the transport pin, pointing at 'Publish PR' for the full rationale.
Comment on lines
+4157
to
4158
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. Fixed in e7cb3b4 — the fork |
||
| echo "🫥 fork push preflight failed for ${HEAD_REPO} (allow-edits grant or PAT type) — discarding without action or marker" | ||
| { | ||
|
|
@@ -4748,6 +4858,13 @@ jobs: | |
| exit 1 | ||
| fi | ||
|
|
||
| # The gates ran branch test code on the host (and the sandboxed | ||
| # agent had the workspace mounted) since the job-start sanitize; | ||
| # re-scrub the local and global git config surfaces this | ||
|
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. Fixed in e7cb3b4 — two ways: the salvage merge now runs |
||
| # PAT-bearing step is about to read. Invoked from the trusted-base | ||
| # staged copy — the working tree holds the PR branch at this point. | ||
| bash "${RUNNER_TEMP}/resanitize-git-config.sh" | ||
|
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. Fixed in e0031b8 — the staging steps record
Comment on lines
+5339
to
+5340
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. Fixed in e7cb3b4 — the concurrent-job race is closed at the root: the PAT step now reads a per-run throwaway
Comment on lines
+5339
to
+5340
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. Acknowledged — verify-then-execute is inherently TOCTOU on a same-user-writable file. This round narrows it materially (mktemp'd unpredictable throwaway + PATH/LD pin so the sha256sum/bash themselves can't be swapped), but the residual window only fully closes with per-job runner isolation (ephemeral user/container), which is out of this PR's scope. Flagging it to the maintainer as the durable fix — see my summary note.
Comment on lines
+5339
to
+5340
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. R4-15 (refs/replace): acknowledged residual, deferred to follow-up — a lower-severity workspace-ref surface no current PAT-git path reads (explicit refspecs throughout). Noting |
||
|
|
||
| if [[ "${OUTCOME}" == "fixed" ]]; then | ||
| NEXT_ROUND="$(( ROUND + 1 ))" | ||
| git config --local --unset-all http.https://github.com/.extraheader || true | ||
|
|
@@ -4758,8 +4875,10 @@ jobs: | |
| git config core.hooksPath /dev/null | ||
| # Authenticate push/fetch with a one-shot, host-scoped credential | ||
| # helper via a git_auth wrapper (see Publish PR) — nothing lands | ||
| # in .git/config, argv holds only the ${GITHUB_TOKEN} reference. | ||
| git_auth() { git -c credential."https://github.com".helper='!f(){ echo username=x-access-token; echo "password=${GITHUB_TOKEN}"; };f' "$@"; } | ||
| # in .git/config, argv holds only the ${GITHUB_TOKEN} reference, | ||
| # and the leading empty credential.helper resets the inherited | ||
| # helper list so a planted helper never answers first. | ||
| git_auth() { git -c credential.helper= -c credential."https://github.com".helper='!f(){ echo username=x-access-token; echo "password=${GITHUB_TOKEN}"; };f' "$@"; } | ||
| if [[ "${HEAD_REPO:-${REPO}}" != "${REPO}" ]]; then | ||
| # Push back to the FORK branch via allow-edits (PAT has push | ||
| # rights on the upstream, which GitHub extends to the fork's | ||
|
|
||
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.
Fixed in 1cfa5e0 — resanitize now removes
.git/shallowalongside.git/commondir(both file twins of the env channels, both defused).