Repository navigation
Base-branch config-folder restore silently reverts changes that race the agent run (trusted triggers) #55318
Description
Summary
The base-branch config-folder snapshot/restore (#26380) silently reverts legitimate changes to .github / .claude / etc. in the PR it produces, whenever the base branch advances during the agent run. The snapshot is taken at activation time but the PR is committed against a later base tip, so the force-restore writes stale config back over changes that landed in between — and these deletions are attributed to the agent PR.
This is noted as intentional ("protects against concurrent base branch mutations during execution"), but for trusted, non-fork triggers (workflow_dispatch, command, scheduled) it produces incorrect, confusing diffs rather than protecting anything, and it silently defeats the create_pull_request allowed_files scoping (the restore runs outside that filter).
Repro (observed in production)
- A
command-triggered workflow withsafe-outputs.create_pull_request.allowed_filesscoped to a single file, andprotect_top_level_dot_folders: true. - Activation job checks out base (
master) at SHAAand snapshotsGH_AW_AGENT_FOLDERS(incl..github) into/tmp/gh-aw/base. - During the ~2-minute agent run, an unrelated human PR merges to
master(SHAB), adding a step to.github/workflows/publish.yml. create_pull_requestcommits the agent's change on top ofB;restore_base_github_folders.shoverwrites.githubwith the SHA-Asnapshot.- Resulting PR diff: the intended one-line change plus a spurious deletion of the step added in
B— even though the agent never touched.githuband it isn't inallowed_files.
Confirmed at the git level: the workflow blob in the agent's commit is byte-identical to <base-add-commit>^ (pre-change base), while the commit's parent already contains the change.
Impact
- Silent reverts of workflow/config changes that raced the run — a correctness and, for
.github/.mcp.json, a supply-chain-adjacent concern. allowed_filesgives false confidence: it does not bound what the PR actually changes.- Noisy PRs that reviewers must manually clean up (or worse, merge).
Suggested fixes (either)
- Re-snapshot against the base tip at PR-creation time (re-fetch base right before
restore_base_github_folders.sh) so the restore reflects the actual PR base, not the activation-time base. - Scope the force-restore to untrusted contexts only (fork PRs /
pull_request_target/issue_comment), where the threat model applies. Trustedworkflow_dispatch/command/schedule runs don't need it. - At minimum, extend the
allowed_filesguard to the restore step so config-folder writes outside the declared scope are dropped rather than committed.
Environment
- setup action
v0.77.5, firewall/agent images0.25.58. - Scripts
actions/setup/sh/{save,restore}_base_github_folders.shunchanged onmainat time of filing.
Activity
pelikhan commentedon Oct 7, 2026
Status (2026-10-07; Needs progress check): The August 24 report describes an activation-time config-folder snapshot overwriting changes added to the base branch during an agent run, outside the stated
allowed_filesscope; no subsequent progress is provided here. The next step is to check the current restore behavior and whether a fix is planned for this race.pelikhan commentedon Oct 16, 2026
Community issue refresher — 2026-10-16: Still relevant.
There is a recent concrete proposal: #68817 would preserve a trusted checkout when HEAD exactly matches the local default-branch tip, with real-Git coverage for the activation-at-A / agent-at-B race. However, that PR is closed without merging.
Current main still restores the activation snapshot by deleting/copying config directories. The compiler's non-PR restore path runs whenever the snapshot directory exists; it does not refresh that snapshot against the later checkout tip. This remains consistent with the reported stale-config overwrite mechanism.
The remaining gap is a reviewed trusted-checkout exception or equivalent fix, while retaining restoration for untrusted PR/feature heads and verifying the final PR contains only intended changes. The closed proposal supplies useful regression scenarios, not proof of a shipped fix. I did not reproduce the concurrent-merge race in a live run.