fix(runner-e2e): align restart control directory

This commit is contained in:
Dotta 2026-09-02 16:39:56 -05:00
parent dfe7aaf26e
commit e04611d65d
4 changed files with 46 additions and 17 deletions

View File

@ -26,6 +26,21 @@ const AMBIENT_EXTERNAL_STATE_KEYS = [
] as const;
const PROVIDER_SECRET_KEY = /^(?:OPENAI|ANTHROPIC|OPENROUTER|DAYTONA)(?:_|$)/;
export function runnerE2EServerControlPaths(temporaryRoot: string) {
const controlDirectory = path.join(temporaryRoot, "control");
return {
controlDirectory,
restartRequestPath: path.join(
controlDirectory,
"server-restart.request.json",
),
restartAcknowledgementPath: path.join(
controlDirectory,
"server-restart.ack.json",
),
};
}
/**
* Local native cells use the debug binary produced by build:runner-binaries.
* Preserve an explicit override for release builds and developer workflows.

View File

@ -6,6 +6,7 @@ import { RunnerApi, pollUntil } from "./api.js";
import { buildRuntimeUsage, summarizeExecutionBilling } from "./billing.js";
import { runnerExecutionById } from "./catalog.js";
import { classifyFailure } from "./failure-classifier.js";
import { runnerE2EServerControlPaths } from "./harness-env.js";
import { setupLiveFixtures, type LiveFixtureValues } from "./live-fixtures.js";
import { evaluateMatcher, type MatcherResult } from "./matchers.js";
import {
@ -166,15 +167,11 @@ async function restartIsolatedPaperclipServer(input: {
requestId: string;
deadlineAt: number;
}): Promise<void> {
const controlDirectory = path.join(privateRoot!, "control");
const requestPath = path.join(
const {
controlDirectory,
"server-restart.request.json",
);
const acknowledgementPath = path.join(
controlDirectory,
"server-restart.ack.json",
);
restartRequestPath: requestPath,
restartAcknowledgementPath: acknowledgementPath,
} = runnerE2EServerControlPaths(temporaryRoot!);
await mkdir(controlDirectory, { recursive: true });
const temporaryRequestPath = `${requestPath}.${process.pid}.${input.requestId}.tmp`;
await writeFile(
@ -237,10 +234,11 @@ const executionIds = (() => {
})();
const executions = executionIds.map(runnerExecutionById);
const attempt = Number(process.env.PAPERCLIP_RUNNER_E2E_ATTEMPT ?? "1");
const temporaryRoot = process.env.PAPERCLIP_RUNNER_E2E_TEMP_ROOT;
const privateRoot = process.env.PAPERCLIP_RUNNER_E2E_PRIVATE_DIR;
const workspacePath = process.env.PAPERCLIP_RUNNER_E2E_WORKSPACE;
if (!privateRoot || !workspacePath)
throw new Error("Runner E2E private/workspace paths are required");
if (!temporaryRoot || !privateRoot || !workspacePath)
throw new Error("Runner E2E temporary/private/workspace paths are required");
function record(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value)
@ -1424,8 +1422,7 @@ for (const execution of executions) {
)?.[1] ??
/Using fallback workspace "([^"]+)"/.exec(runLogContent)?.[1];
const cwd = String(workspaceContext.cwd ?? fallbackWorkspace ?? "");
const isolatedRoot = process.env.PAPERCLIP_RUNNER_E2E_TEMP_ROOT ?? "";
if (!isolatedRoot || !cwd.startsWith(`${isolatedRoot}/`)) {
if (!cwd.startsWith(`${temporaryRoot}/`)) {
invariantFailures.push(
`local run workspace escaped the isolated root: ${cwd}`,
);

View File

@ -5,6 +5,7 @@ import path from "node:path";
import {
assertIsolatedServerEnvironment,
buildPaperclipServerEnvironment,
runnerE2EServerControlPaths,
} from "./harness-env.js";
function required(name: string) {
@ -21,12 +22,11 @@ const port = required("PAPERCLIP_RUNNER_E2E_PORT");
const repositoryRoot = path.resolve(import.meta.dirname, "../..");
const tsxCli = path.join(repositoryRoot, "cli/node_modules/tsx/dist/cli.mjs");
const paperclipCli = path.join(repositoryRoot, "cli/src/index.ts");
const controlDirectory = path.join(temporaryRoot, "control");
const restartRequestPath = path.join(
const {
controlDirectory,
"server-restart.request.json",
);
const restartAckPath = path.join(controlDirectory, "server-restart.ack.json");
restartRequestPath,
restartAcknowledgementPath: restartAckPath,
} = runnerE2EServerControlPaths(temporaryRoot);
const restartTimeoutMs = 180_000;
const gracefulStopTimeoutMs = 30_000;
const serverEnvironment = buildPaperclipServerEnvironment(process.env, {

View File

@ -11,6 +11,7 @@ import {
assertIsolatedServerEnvironment,
buildPaperclipServerEnvironment,
resolvePaperclipRunnerBinaryForHarness,
runnerE2EServerControlPaths,
} from "./harness-env.js";
import { runnerExecutionById } from "./catalog.js";
import { assertEmbeddedDatabaseIsolation } from "./instance-isolation.js";
@ -354,6 +355,22 @@ describe("runner E2E failure policy", () => {
});
describe("runner E2E server isolation", () => {
it("shares restart control files beneath the isolated temporary root", () => {
expect(runnerE2EServerControlPaths("/tmp/cell")).toEqual({
controlDirectory: path.join("/tmp/cell", "control"),
restartRequestPath: path.join(
"/tmp/cell",
"control",
"server-restart.request.json",
),
restartAcknowledgementPath: path.join(
"/tmp/cell",
"control",
"server-restart.ack.json",
),
});
});
it("strips database and paid-provider credentials from the Paperclip process", () => {
const env = buildPaperclipServerEnvironment(
{