mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-07 07:55:47 +01:00
Merge master into the preserved catalog integration candidate
Preserve the frozen catalog and its historical qualification separately. Keep current supervisor ownership, installed-artifact and recovery controls, the shipped TestOps cell, and the historical OpenCode candidate's exact model. Production source matches master f2db909393. Focused support checks: 218 passed; full catalog typecheck passed.
This commit is contained in:
commit
b1e3950e6d
2439 files changed
+294354
-92774
No files matched your search
@@ -1,6 +1,25 @@
|
||||
import { readDockerDatabaseReceipt, type DockerRun } from "./docker-postgres.js";
|
||||
import path from "node:path";
|
||||
import { readFile, stat } from "node:fs/promises";
|
||||
import { readFile, realpath, stat, writeFile } from "node:fs/promises";
|
||||
|
||||
const CONTROLLER_DATABASE_OWNER_FILE = ".runner-e2e-controller-owner.json";
|
||||
|
||||
/** Written only after the supervisor has started this fixture's Postgres. */
|
||||
export async function recordControllerDatabaseOwnership(input: {
|
||||
configPath: string; temporaryRoot: string; dataDirectory: string; connectionString: string;
|
||||
externalDatabaseName?: string;
|
||||
}) {
|
||||
const temporaryRoot = await realpath(input.temporaryRoot);
|
||||
const dataDirectory = await realpath(input.dataDirectory);
|
||||
if (!dataDirectory.startsWith(`${temporaryRoot}${path.sep}`)) {
|
||||
throw new Error("Controller database path escaped its fixture-owned root");
|
||||
}
|
||||
await writeFile(path.join(dataDirectory, CONTROLLER_DATABASE_OWNER_FILE), JSON.stringify({
|
||||
version: input.externalDatabaseName ? 2 : 1, externalDatabaseName: input.externalDatabaseName,
|
||||
configPath: await realpath(input.configPath), temporaryRoot,
|
||||
dataDirectory, connectionString: input.connectionString,
|
||||
}), { mode: 0o600 });
|
||||
}
|
||||
|
||||
export async function assertRunnerDatabaseIsolation(
|
||||
configPath: string,
|
||||
@@ -14,6 +33,7 @@ export async function assertRunnerDatabaseIsolation(
|
||||
mode?: string;
|
||||
connectionString?: string;
|
||||
embeddedPostgresDataDir?: string;
|
||||
embeddedPostgresPort?: number;
|
||||
backup?: { dir?: string };
|
||||
};
|
||||
logging?: { logDir?: string };
|
||||
@@ -27,9 +47,12 @@ export async function assertRunnerDatabaseIsolation(
|
||||
localEncrypted?: { keyFilePath?: string };
|
||||
};
|
||||
};
|
||||
if (!config.database) throw new Error("Runner E2E config omitted its database");
|
||||
const docker = dockerReceiptPath ? await readDockerDatabaseReceipt(dockerReceiptPath, temporaryRoot, dockerRun) : undefined;
|
||||
if (docker ? config.database?.mode !== "postgres" || config.database.connectionString !== docker.connectionString : config.database?.mode !== "embedded-postgres" || !!config.database.connectionString) {
|
||||
throw new Error("Runner E2E Paperclip instance did not use its explicitly owned database lane");
|
||||
const supervised = !docker && config.database?.mode === "postgres";
|
||||
if (docker ? config.database?.mode !== "postgres" || config.database.connectionString !== docker.connectionString : !config.database || (!supervised &&
|
||||
(config.database.mode !== "embedded-postgres" || config.database.connectionString))) {
|
||||
throw new Error("Runner E2E Paperclip instance did not use its fixture-owned database");
|
||||
}
|
||||
if (
|
||||
config.storage?.provider !== "local_disk" ||
|
||||
@@ -41,8 +64,8 @@ export async function assertRunnerDatabaseIsolation(
|
||||
);
|
||||
}
|
||||
const isolatedPaths = {
|
||||
...(docker ? {} : { database: config.database!.embeddedPostgresDataDir }),
|
||||
backup: config.database!.backup?.dir,
|
||||
...(docker ? {} : { database: config.database.embeddedPostgresDataDir }),
|
||||
backup: config.database.backup?.dir,
|
||||
logs: config.logging?.logDir,
|
||||
storage: config.storage.localDisk?.baseDir,
|
||||
secretsKey: config.secrets.localEncrypted?.keyFilePath,
|
||||
@@ -60,13 +83,37 @@ export async function assertRunnerDatabaseIsolation(
|
||||
}
|
||||
if (!docker) {
|
||||
const databasePath = path.resolve(isolatedPaths.database!);
|
||||
if (supervised) {
|
||||
try {
|
||||
const root = await realpath(temporaryRoot);
|
||||
const directory = await realpath(databasePath);
|
||||
if (!directory.startsWith(`${root}${path.sep}`)) throw new Error("Database escaped fixture");
|
||||
const owner = JSON.parse(await readFile(path.join(directory, CONTROLLER_DATABASE_OWNER_FILE), "utf8"));
|
||||
const port = config.database.embeddedPostgresPort;
|
||||
const connection = new URL(config.database.connectionString!);
|
||||
const external = owner.version === 2 && /^runner_e2e_[a-f0-9]{32}$/.test(owner.externalDatabaseName)
|
||||
&& ["postgres:", "postgresql:"].includes(connection.protocol)
|
||||
&& ["127.0.0.1", "localhost", "[::1]"].includes(connection.hostname)
|
||||
&& connection.pathname === `/${owner.externalDatabaseName}`;
|
||||
const embedded = owner.version === 1 && Number.isInteger(port) && Number(port) > 0 && Number(port) <= 65535
|
||||
&& config.database.connectionString === `postgres://paperclip:paperclip@127.0.0.1:${port}/paperclip`
|
||||
&& (await stat(path.join(directory, "PG_VERSION"))).isFile();
|
||||
if ((!external && !embedded) || owner.temporaryRoot !== root || owner.dataDirectory !== directory
|
||||
|| owner.configPath !== await realpath(configPath) || owner.connectionString !== config.database.connectionString) {
|
||||
throw new Error("Supervisor database ownership mismatch");
|
||||
}
|
||||
} catch (cause) {
|
||||
throw new Error("Runner E2E Paperclip instance did not use its fixture-owned database", { cause });
|
||||
}
|
||||
}
|
||||
const databaseStat = await stat(databasePath);
|
||||
if (!databaseStat.isDirectory()) throw new Error("Embedded database path is not a directory");
|
||||
if (!databaseStat.isDirectory())
|
||||
throw new Error("Embedded database path is not a directory");
|
||||
}
|
||||
const keyStat = await stat(path.resolve(isolatedPaths.secretsKey!));
|
||||
if (!keyStat.isFile())
|
||||
throw new Error("Encrypted-secrets master key path is not a file");
|
||||
}
|
||||
|
||||
/** Compatibility entry point remains embedded-only, never ambient external DB. */
|
||||
/** The compatibility entry point still requires an owned controller/embedded database. */
|
||||
export async function assertEmbeddedDatabaseIsolation(configPath: string, temporaryRoot: string) { return assertRunnerDatabaseIsolation(configPath, temporaryRoot); }
|
||||
Reference in new issue
Block a user