78 lines
2.8 KiB
TypeScript
78 lines
2.8 KiB
TypeScript
import { execFile } from "node:child_process";
|
|
import { access, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
import { join, resolve } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { pathToFileURL } from "node:url";
|
|
|
|
import { expect, it } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
const expectedFailure =
|
|
"package did not retain its MCP Registry ownership marker";
|
|
|
|
it("keeps npm pack output in the owned workspace when package validation fails", async () => {
|
|
const testRoot = await createTestTempDirectory("rea-pack-isolation-");
|
|
const packageRoot = join(testRoot, "source");
|
|
const workspace = join(testRoot, "workspace");
|
|
const npmCache = join(testRoot, "npm-cache");
|
|
const archiveName = "rea-agents-6.0.0.tgz";
|
|
const archivePath = join(packageRoot, archiveName);
|
|
const sentinel = Buffer.from("caller-owned archive\n");
|
|
await Promise.all([mkdir(packageRoot), mkdir(workspace), mkdir(npmCache)]);
|
|
await Promise.all([
|
|
writeFile(
|
|
join(packageRoot, "package.json"),
|
|
JSON.stringify({
|
|
name: "rea-agents",
|
|
version: "6.0.0",
|
|
mcpName: "invalid-owner",
|
|
bin: { rea: "scripts/rea.mjs", "rea-agents": "scripts/rea.mjs" },
|
|
dependencies: { "@lydell/node-pty": "1.1.0" },
|
|
}),
|
|
),
|
|
writeFile(archivePath, sentinel),
|
|
]);
|
|
const packageContentsBefore = (await readdir(packageRoot)).sort();
|
|
const packerUrl = pathToFileURL(
|
|
resolve("scripts/verify-package-pack.mjs"),
|
|
).href;
|
|
const harness = `
|
|
import { rm } from "node:fs/promises";
|
|
const workspace = ${JSON.stringify(workspace)};
|
|
let failure;
|
|
try {
|
|
const { verifyPackagePack } = await import(${JSON.stringify(packerUrl)});
|
|
await verifyPackagePack({ root: ${JSON.stringify(packageRoot)}, workspace });
|
|
} catch (cause) {
|
|
if (!(cause instanceof Error) || cause.message !== ${JSON.stringify(expectedFailure)}) throw cause;
|
|
failure = cause.message;
|
|
} finally {
|
|
await rm(workspace, { recursive: true, force: true });
|
|
}
|
|
if (failure !== ${JSON.stringify(expectedFailure)}) throw new Error("Expected package metadata validation to fail after packing");
|
|
process.stdout.write(JSON.stringify({ failure }));
|
|
`;
|
|
const { stdout } = await execFileAsync(
|
|
process.execPath,
|
|
["--input-type=module", "--eval", harness],
|
|
{
|
|
cwd: process.cwd(),
|
|
env: {
|
|
...process.env,
|
|
npm_config_cache: npmCache,
|
|
TEMP: npmCache,
|
|
TMP: npmCache,
|
|
TMPDIR: npmCache,
|
|
},
|
|
maxBuffer: 1_024 * 1_024,
|
|
},
|
|
);
|
|
|
|
expect(JSON.parse(stdout)).toEqual({ failure: expectedFailure });
|
|
expect((await readdir(packageRoot)).sort()).toEqual(packageContentsBefore);
|
|
expect(await readFile(archivePath)).toEqual(sentinel);
|
|
await expect(access(workspace)).rejects.toMatchObject({ code: "ENOENT" });
|
|
});
|