Exclude private nested repositories before checkpoint path validation
Reproduce Codex plugin-cache repositories with real Git and preserve private-runtime exclusions before validating directory entries. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
36f8d69931
commit
97bf34eb60
|
|
@ -47,9 +47,9 @@ Sandbox runs use the operating-system user's home directory. Both legacy
|
|||
adapters and the native runner enter the same host-owned lifecycle before
|
||||
dispatch. Local execution keeps its existing workspace and home behavior.
|
||||
Legacy ACP proxies use a private host staging directory while agent sessions start
|
||||
in the sandbox home. When managed Git launchers are present, the remote agent
|
||||
starts without another login-shell profile pass, which could replace the assigned
|
||||
PATH before the agent starts. For API-key Codex ACP runs, the adapter writes the explicit
|
||||
in the sandbox home. After login-shell initialization, remote agents restore the
|
||||
managed Git PATH ahead of paths added by the profile. This preserves both the
|
||||
Git launcher and custom runtime initialization. For API-key Codex ACP runs, the adapter writes the explicit
|
||||
key to an owner-only login file in the staging copy; host credentials stay unchanged.
|
||||
Per-run GitHub launchers declare their own CommonJS package scope so warm runs
|
||||
inside ES-module repositories can still execute Git and GitHub CLI commands. Native runner launches carry the validated scoped paths
|
||||
|
|
@ -158,7 +158,8 @@ warm checkout keeps both its completed setup and reusable caches.
|
|||
A complete repository checkpoint includes Git objects, refs, HEAD and index,
|
||||
tracked working files, and nonignored untracked files. It excludes dependencies
|
||||
and generated ignored caches, Git credentials/configuration, hooks, and private
|
||||
runtime state. Checkpoints reject in-progress Git locks and a tree that changes
|
||||
runtime state, including nested plugin repositories inside private runner caches.
|
||||
Checkpoints reject in-progress Git locks and a tree that changes
|
||||
during scanning. The database pointer advances only after all required objects
|
||||
and the manifest have been saved. Restores verify ownership and hashes, then
|
||||
publish the restored directory atomically. Git origin configuration is recreated
|
||||
|
|
|
|||
|
|
@ -63,4 +63,18 @@ describe("sandbox work folder transport with real Node and Git", () => {
|
|||
expect(paths).not.toContain(".git/config");
|
||||
expect(paths.some((entry) => entry.startsWith("node_modules/"))).toBe(false);
|
||||
});
|
||||
it("excludes nested Git repositories in private runner state before validating their trailing slash", async () => {
|
||||
const dir = await root();
|
||||
await exec("git", ["init", dir]);
|
||||
const privateRepo = path.join(dir, ".paperclip-runtime/session/codex-home/.tmp/plugins");
|
||||
await mkdir(privateRepo, { recursive: true });
|
||||
await exec("git", ["init", privateRepo]);
|
||||
await writeFile(path.join(privateRepo, "private-config"), "not durable");
|
||||
await writeFile(path.join(dir, "keep.txt"), "durable work");
|
||||
const listed = await exec("git", ["-C", dir, "ls-files", "--others", "--exclude-standard", "-z"]);
|
||||
expect(listed.stdout).toContain(".paperclip-runtime/session/codex-home/.tmp/plugins/\0");
|
||||
const paths = (await transport.scan(dir, true)).map((entry) => entry.path);
|
||||
expect(paths).toContain("keep.txt");
|
||||
expect(paths.some((entry) => entry.includes(".paperclip-runtime"))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@ function scan() {
|
|||
const files = execFileSync("git", ["-C", input.root, "ls-files", "--cached", "--others", "--exclude-standard", "-z"],
|
||||
{ encoding: "utf8", maxBuffer: 16 * 1024 * 1024 }).split("\0").filter(Boolean);
|
||||
for (const relative of [...new Set(files)].sort()) {
|
||||
// Git reports nested repositories with a trailing slash. Private runner
|
||||
// caches can contain them and must be excluded before path validation.
|
||||
if (relative.split("/").includes(".paperclip-runtime")) continue;
|
||||
try { fs.lstatSync(full(relative)); entry(relative); } catch (error) { if (error.code !== "ENOENT") throw error; }
|
||||
}
|
||||
for (const name of children(gitDir)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue