Merge branch 'codex/work-folders-staging-hardening-refresh' into codex/work-folders-remote-recovery-refresh

* codex/work-folders-staging-hardening-refresh:
  Fix frozen provider graph and retain snapshots across failed launches
This commit is contained in:
Dotta 2026-09-11 14:40:43 -05:00
commit 140dcc2a59
5 changed files with 744 additions and 69 deletions

View File

@ -296,7 +296,7 @@ COPY packages ./packages
COPY server/package.json ./server/package.json
COPY ui/package.json ./ui/package.json
COPY cli/package.json ./cli/package.json
ARG PAPERCLIP_RUNNER_LOCK_SHA256=21aa3df50da53c338660b9f5f2611e9d46c896ad05c0e7a9976185ebce340f52
ARG PAPERCLIP_RUNNER_LOCK_SHA256=101481086be52f63be8b83b9047d70aeb0995a4ebe1deb638a43346386f9085e
RUN printf '%s pnpm-lock.yaml\n' "${PAPERCLIP_RUNNER_LOCK_SHA256}" > /tmp/provider-lock.sha256 \
&& sha256sum -c /tmp/provider-lock.sha256 \
&& pnpm install --frozen-lockfile --filter '@paperclipai/paperclip-runner...'

View File

@ -29,7 +29,7 @@ COPY cli/package.json ./cli/package.json
# The complete resolved lock (including transitive integrity hashes) is reviewed.
# Reject registry-time drift BEFORE installing packages or running lifecycle code.
# Refresh this digest together with source/provider dependency changes.
ARG PAPERCLIP_RUNNER_LOCK_SHA256=21aa3df50da53c338660b9f5f2611e9d46c896ad05c0e7a9976185ebce340f52
ARG PAPERCLIP_RUNNER_LOCK_SHA256=101481086be52f63be8b83b9047d70aeb0995a4ebe1deb638a43346386f9085e
RUN printf '%s pnpm-lock.yaml\n' "${PAPERCLIP_RUNNER_LOCK_SHA256}" > /tmp/provider-lock.sha256 \
&& sha256sum -c /tmp/provider-lock.sha256 \
&& pnpm install --frozen-lockfile --filter '@paperclipai/paperclip-runner...'

File diff suppressed because it is too large Load Diff

View File

@ -778,6 +778,22 @@ describe("ACPX installation integrity", () => {
expect(() => lease.spawn()).toThrow("Verified ACPX command lease is closed");
});
it("a failed reusable launch preserves the snapshot of an already spawned child", async () => {
const fixture = await installationFixture();
const installation = await verifyQualifiedAcpxInstallation(fixture.profile, fixture.resolve);
const lease = await installation.openCommand({ reusable: true });
try {
const output = expectPinnedOutput(lease.spawn(), "verified");
// Node rejects this argument synchronously, before creating another child.
expect(() => lease.spawn(["invalid\0argument"])).toThrow();
await lease.close();
await output;
expect(() => lease.spawn()).toThrow("Verified ACPX command lease is closed");
} finally {
await lease.close();
}
});
it("launches the verified bytes after the open inode is modified", async () => {
const fixture = await installationFixture();
const installation = await verifyQualifiedAcpxInstallation(

View File

@ -1503,6 +1503,16 @@ function commandLease(
],
},
);
activeChildren++;
let childSettled = false;
const settleChild = (): void => {
if (childSettled) return;
childSettled = true;
activeChildren--;
void closeSnapshotIfIdle().catch(() => undefined);
};
child.once("exit", settleChild);
child.once("error", settleChild);
if (guarded) {
const guardianOwnerPipe = child.stdio[
providerOwnershipFd - 1
@ -1534,22 +1544,14 @@ function commandLease(
launchBytes.fill(0);
verifiedBytes.fill(0);
releaseDirectoriesBestEffort();
void privateSnapshot?.close();
closed = true;
void closeSnapshotIfIdle().catch(() => undefined);
throw error;
}
activeChildren++;
let childSettled = false;
const settleChild = (): void => {
if (childSettled) return;
childSettled = true;
activeChildren--;
void closeSnapshotIfIdle().catch(() => undefined);
};
child.once("exit", settleChild);
child.once("error", settleChild);
if (!reusable) releaseDirectoriesBestEffort();
const sourceInput = child.stdio[COMMAND_SOURCE_FD] as Writable | null;
if (sourceInput === null) {
closed = true;
consumed = true;
launchBytes.fill(0);
verifiedBytes.fill(0);