mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-03 01:27:09 +01:00
64 lines
4.2 KiB
TypeScript
64 lines
4.2 KiB
TypeScript
import { afterEach, expect, it, vi } from "vitest";
|
|
import { createLocalEncryptedCipher } from "../../server/src/secrets/local-encrypted-provider.js";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
start: vi.fn(), observer: vi.fn(), stop: vi.fn(), close: vi.fn(), writeFile: vi.fn(),
|
|
}));
|
|
vi.mock("node:fs/promises", () => ({ mkdir: async () => {}, rename: async () => {}, writeFile: mocks.writeFile,
|
|
readFile: async () => JSON.stringify({ database: { mode: "postgres", connectionString: "postgres://fixture" },
|
|
secrets: { localEncrypted: { keyFilePath: "/fixture/secrets/master.key" } } }) }));
|
|
vi.mock("../../packages/shared/src/config-schema.js", () => ({ paperclipConfigSchema: { parse: (value: unknown) => value } }));
|
|
vi.mock("./rolling-deployment-process.js", () => ({ startRollingDeploymentProcess: mocks.start }));
|
|
vi.mock("./rolling-deployment-proxy.js", () => ({ startRollingDeploymentProxy: async () => ({ origin: "http://127.0.0.1:1", routeTo() {}, close: mocks.close }) }));
|
|
vi.mock("./controller-recovery-observer.js", () => ({ createControllerRecoveryObserver: mocks.observer }));
|
|
vi.mock("./server-restart-request.js", () => ({ readRestartRequest: async () => ({ requestId: "key-check", rollingDeployment: true, recoveryBinding: { companyId: "business-company" } }) }));
|
|
import { superviseRollingDeployment } from "./rolling-deployment-supervisor.js";
|
|
|
|
afterEach(() => { vi.unstubAllEnvs(); vi.unstubAllGlobals(); vi.clearAllMocks(); });
|
|
|
|
it.each([undefined, "prior-disposable-key"])("shares the server key with checkpoint observation and restores %s on failure", async prior => {
|
|
vi.stubEnv("PAPERCLIP_SECRETS_MASTER_KEY", prior);
|
|
let material: ReturnType<ReturnType<typeof createLocalEncryptedCipher>["encrypt"]>;
|
|
mocks.start.mockImplementation(async ({ sharedEnvironment }) => {
|
|
expect(process.env.PAPERCLIP_SECRETS_MASTER_KEY).toBe(sharedEnvironment.PAPERCLIP_SECRETS_MASTER_KEY);
|
|
expect(mocks.writeFile).toHaveBeenCalledWith("/fixture/secrets/master.key", sharedEnvironment.PAPERCLIP_SECRETS_MASTER_KEY,
|
|
{ mode: 0o600, flag: "wx" });
|
|
material = createLocalEncryptedCipher("write").encrypt("synthetic checkpoint");
|
|
return { child: { exitCode: null, signalCode: null }, configPath: "/fixture/config.json",
|
|
origin: "http://127.0.0.1:2", waitForReady: async () => {}, stop: mocks.stop };
|
|
});
|
|
mocks.observer.mockImplementation(async () => {
|
|
expect(createLocalEncryptedCipher("read").decrypt(material)).toBe("synthetic checkpoint");
|
|
throw new Error("synthetic observer failure");
|
|
});
|
|
await expect(superviseRollingDeployment({ temporaryRoot: "/fixture", repositoryRoot: "/fixture",
|
|
configPath: "/fixture/config.json", port: 1, executionIds: ["rolling"], cancelled: () => false,
|
|
environment: { PAPERCLIP_STORAGE_PROVIDER: "s3" },
|
|
})).rejects.toThrow("synthetic observer failure");
|
|
expect(mocks.observer).toHaveBeenCalledOnce();
|
|
expect(mocks.stop).toHaveBeenCalledOnce();
|
|
expect(mocks.close).toHaveBeenCalledOnce();
|
|
expect(process.env.PAPERCLIP_SECRETS_MASTER_KEY).toBe(prior);
|
|
});
|
|
|
|
|
|
it("keeps open deployment probe tasks out of the agent workflow's company", async () => {
|
|
mocks.start.mockResolvedValue({ child: { exitCode: null, signalCode: null }, configPath: "/fixture/config.json",
|
|
origin: "http://127.0.0.1:2", waitForReady: async () => {}, stop: mocks.stop });
|
|
mocks.observer.mockResolvedValue(undefined);
|
|
const routes: string[] = [];
|
|
vi.stubGlobal("fetch", vi.fn(async (url: string) => {
|
|
const route = new URL(url).pathname;
|
|
routes.push(route);
|
|
if (route === "/api/companies") return new Response(JSON.stringify({ id: "probe-company" }));
|
|
if (route === "/api/companies/probe-company/issues") throw new Error("probe fixture boundary reached");
|
|
throw new Error(`Probe modified business workflow: ${route}`);
|
|
}));
|
|
await expect(superviseRollingDeployment({ temporaryRoot: "/fixture", repositoryRoot: "/fixture",
|
|
configPath: "/fixture/config.json", port: 1, executionIds: ["rolling"], cancelled: () => false,
|
|
environment: { PAPERCLIP_STORAGE_PROVIDER: "s3" },
|
|
})).rejects.toThrow("probe fixture boundary reached");
|
|
expect(routes).toEqual(["/api/companies", "/api/companies/probe-company/issues"]);
|
|
expect(mocks.stop).toHaveBeenCalledOnce();
|
|
});
|