fix: snapshot PR's .claude/ to .claude-pr/ before security restore (#1172)
When a PR modifies files under .claude/, the security restore in restoreConfigFromBase() overwrites them with the base branch version — correct for execution safety, but it means review agents never see what the PR actually changes. Before deleting the PR-controlled .claude/ tree, copy it to .claude-pr/. Review agents can read .claude-pr/ to inspect the PR's hooks, MCP configs, settings, and CLAUDE.md without those files ever being executed. The snapshot is taken before the security delete so it captures the full PR-authored version. Fixes #1134. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eb8baa46af
commit
5150ea9643
@ -1,5 +1,5 @@
|
||||
import { execFileSync } from "child_process";
|
||||
import { rmSync } from "fs";
|
||||
import { cpSync, existsSync, rmSync } from "fs";
|
||||
|
||||
// Paths that are both PR-controllable and read from cwd at CLI startup.
|
||||
//
|
||||
@ -44,6 +44,19 @@ export function restoreConfigFromBase(baseBranch: string): void {
|
||||
`Restoring ${SENSITIVE_PATHS.join(", ")} from origin/${baseBranch} (PR head is untrusted)`,
|
||||
);
|
||||
|
||||
// Snapshot the PR's .claude/ tree to .claude-pr/ before deleting it.
|
||||
// This lets review agents inspect what the PR actually changes (CLAUDE.md,
|
||||
// settings, hooks, MCP configs) without those files ever being executed.
|
||||
// The snapshot is taken before the security delete so it captures the
|
||||
// PR-authored version.
|
||||
rmSync(".claude-pr", { recursive: true, force: true });
|
||||
if (existsSync(".claude")) {
|
||||
cpSync(".claude", ".claude-pr", { recursive: true });
|
||||
console.log(
|
||||
"Preserved PR's .claude/ → .claude-pr/ for review agents (not executed)",
|
||||
);
|
||||
}
|
||||
|
||||
// Delete PR-controlled versions BEFORE fetching so the attacker-controlled
|
||||
// .gitmodules is absent during the network operation. If git reads .gitmodules
|
||||
// during fetch (fetch.recurseSubmodules=on-demand, the git default), it will
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user