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 with safe-outputs.create_pull_request.allowed_files scoped to a single file, and protect_top_level_dot_folders: true.
- Activation job checks out base (
master) at SHA A and snapshots GH_AW_AGENT_FOLDERS (incl. .github) into /tmp/gh-aw/base.
- During the ~2-minute agent run, an unrelated human PR merges to
master (SHA B), adding a step to .github/workflows/publish.yml.
create_pull_request commits the agent's change on top of B; restore_base_github_folders.sh overwrites .github with the SHA-A snapshot.
- Resulting PR diff: the intended one-line change plus a spurious deletion of the step added in
B — even though the agent never touched .github and it isn't in allowed_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_files gives 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. Trusted workflow_dispatch/command/schedule runs don't need it.
- At minimum, extend the
allowed_files guard 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 images 0.25.58.
- Scripts
actions/setup/sh/{save,restore}_base_github_folders.sh unchanged on main at time of filing.
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 thecreate_pull_requestallowed_filesscoping (the restore runs outside that filter).Repro (observed in production)
command-triggered workflow withsafe-outputs.create_pull_request.allowed_filesscoped to a single file, andprotect_top_level_dot_folders: true.master) at SHAAand snapshotsGH_AW_AGENT_FOLDERS(incl..github) into/tmp/gh-aw/base.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.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
.github/.mcp.json, a supply-chain-adjacent concern.allowed_filesgives false confidence: it does not bound what the PR actually changes.Suggested fixes (either)
restore_base_github_folders.sh) so the restore reflects the actual PR base, not the activation-time base.pull_request_target/issue_comment), where the threat model applies. Trustedworkflow_dispatch/command/schedule runs don't need it.allowed_filesguard to the restore step so config-folder writes outside the declared scope are dropped rather than committed.Environment
v0.77.5, firewall/agent images0.25.58.actions/setup/sh/{save,restore}_base_github_folders.shunchanged onmainat time of filing.