mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-01 15:35:12 +01:00
Add the Kimi lifecycle and recovery qualification harness. Preserve original grades and cleanup evidence, strict native ownership audits, bounded startup and cleanup, and early rejection of unsupported local fault execution before credentials or resources. Co-Authored-By: Paperclip <noreply@paperclip.ing>
72 lines
3.1 KiB
TypeScript
72 lines
3.1 KiB
TypeScript
import { lstatSync, realpathSync } from "node:fs";
|
|
import { chmod, lstat, mkdir, realpath } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
|
|
export const RUNNER_E2E_RESULTS_ROOT = "PAPERCLIP_RUNNER_E2E_RESULTS_ROOT";
|
|
|
|
function contains(parent: string, child: string) {
|
|
return child === parent || child.startsWith(`${parent}${path.sep}`);
|
|
}
|
|
|
|
export function resolveRunnerE2EResultsRoot(
|
|
repositoryRoot: string,
|
|
environment: NodeJS.ProcessEnv = process.env,
|
|
): string {
|
|
const configured = environment[RUNNER_E2E_RESULTS_ROOT];
|
|
if (configured === undefined)
|
|
return path.join(repositoryRoot, "tests/runner-e2e/results");
|
|
if (!configured || configured.trim() !== configured || /[\u0000-\u001f]/u.test(configured)
|
|
|| !path.isAbsolute(configured) || path.normalize(configured) !== configured)
|
|
throw new Error(`${RUNNER_E2E_RESULTS_ROOT} requires a normalized absolute directory`);
|
|
const repository = path.resolve(repositoryRoot);
|
|
if (path.dirname(configured) === configured || contains(configured, repository)
|
|
|| contains(repository, configured) || contains(configured, os.homedir()))
|
|
throw new Error(`${RUNNER_E2E_RESULTS_ROOT} requires a dedicated directory outside the checkout and home roots`);
|
|
|
|
let ancestor = configured;
|
|
while (true) {
|
|
try {
|
|
const metadata = lstatSync(ancestor);
|
|
if (!metadata.isDirectory() || realpathSync(ancestor) !== ancestor)
|
|
throw new Error(`${RUNNER_E2E_RESULTS_ROOT} must not use files or symbolic-link paths`);
|
|
break;
|
|
} catch (error) {
|
|
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
ancestor = path.dirname(ancestor);
|
|
}
|
|
}
|
|
return configured;
|
|
}
|
|
|
|
export async function prepareRunnerE2ECampaignDirectory(resultsRoot: string, campaignId: string) {
|
|
if (!/^[A-Za-z0-9_.-]+$/u.test(campaignId) || campaignId === "." || campaignId === "..")
|
|
throw new Error("Runner E2E campaign requires one safe path segment");
|
|
const directory = path.join(resultsRoot, campaignId);
|
|
await assertRunnerE2EResultsPath(resultsRoot, directory);
|
|
await mkdir(resultsRoot, { recursive: true, mode: 0o700 });
|
|
await chmod(resultsRoot, 0o700);
|
|
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
await assertRunnerE2EResultsPath(resultsRoot, directory);
|
|
return directory;
|
|
}
|
|
|
|
export async function assertRunnerE2EResultsPath(resultsRoot: string, directory: string) {
|
|
if (!path.isAbsolute(resultsRoot) || path.normalize(resultsRoot) !== resultsRoot
|
|
|| !path.isAbsolute(directory) || path.normalize(directory) !== directory
|
|
|| directory === resultsRoot || !contains(resultsRoot, directory))
|
|
throw new Error("Runner E2E output must remain beneath its results root");
|
|
let ancestor = directory;
|
|
while (true) {
|
|
try {
|
|
const metadata = await lstat(ancestor);
|
|
if (!metadata.isDirectory() || await realpath(ancestor) !== ancestor)
|
|
throw new Error("Runner E2E output must use physical directories without symbolic links");
|
|
return;
|
|
} catch (error) {
|
|
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
ancestor = path.dirname(ancestor);
|
|
}
|
|
}
|
|
}
|