Files
reverse-engineering-anything/tests/boundary/process/clientVerifierSetupTargets.test.ts
T

104 lines
4.7 KiB
TypeScript

import { spawnSync } from "node:child_process";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { expect, it } from "vitest";
it.each(
(
[
["gemini", "relative path", false],
["gemini", "profile traversal", false],
["gemini", "profile root alias", false],
["gemini", "skill root alias", false],
["gemini", "skill traversal", false],
["gemini", "owned child", true],
["copilot", "relative path", false],
["copilot", "sibling", false],
["copilot", "skill traversal", false],
["copilot", "owned child", true],
["qwen", "relative path", false],
["qwen", "profile traversal", false],
["qwen", "profile root alias", false],
["qwen", "skill root alias", false],
["qwen", "skill traversal", false],
["qwen", "profile child", true],
["qwen", "skill child", true],
] as const
).filter(([client]) => process.platform !== "win32" || client !== "copilot"),
)(
"%s checks %s setup-plan targets before writing",
async (client, kind, allowed) => {
const state = await mkdtemp(join(tmpdir(), "rea-client-plan-"));
try {
const commands = join(state, "commands.mjs");
const fixture = join(state, "fixture.mjs");
const hook = join(state, "hook.mjs");
await writeFile(
commands,
`import {writeFile} from 'node:fs/promises'; import {join} from 'node:path';
export async function createVerifierCommands(){return {
async exec(command,args,options={}){
if(command==='git')return {stdout:'',stderr:''};
if(args.includes('--version'))return {stdout:'fake client',stderr:''};
if(args.includes('setup') && args.includes('--dry-run')){
const client=process.env.CLIENT; const kind=process.env.KIND;
const profile=client==='gemini'?options.env.GEMINI_CLI_HOME:client==='copilot'?options.env.COPILOT_HOME:options.env.QWEN_HOME;
const skills=join(client==='gemini'?profile:options.env.HOME,'.agents','skills');
const skill=join(skills,'reverse-engineer-anything');
const config=join(profile,client==='gemini'?'.gemini/settings.json':client==='copilot'?'mcp-config.json':'settings.json');
const candidate=kind==='relative path'?'relative/AGENTS.md':kind==='profile root alias'?profile+'/child/..':kind==='skill root alias'?skills+'/child/..':kind==='profile traversal'?profile+'/../outside/AGENTS.md':kind==='skill traversal'?(client==='copilot'?skill:skills)+'/../outside/AGENTS.md':kind==='sibling'?skill+'-sibling/AGENTS.md':kind==='profile child'?config:join(skill,'SKILL.md');
const selectedSkill=(kind==='skill traversal'||kind==='skill root alias')&&client==='gemini'?candidate:join(skill,'SKILL.md');
const actions=client==='qwen'?[{target:candidate}]:[{target:config},{target:client==='copilot'?skill:selectedSkill},{target:candidate}];
return {stdout:JSON.stringify({status:'planned',plannedActions:actions}),stderr:''};
}
await writeFile(process.env.STATE+'/setup-advanced','yes'); throw Error('intentional stop before setup mutation');
}, async close(){} };}`,
);
await writeFile(
fixture,
`export async function createOpenAiModelFixture(){return {baseUrl:'http://127.0.0.1:1',async close(){}};}`,
);
await writeFile(
hook,
`import {registerHooks} from 'node:module';import{pathToFileURL}from'node:url';
registerHooks({resolve(specifier,context,next){if(context.parentURL?.endsWith('/scripts/verify-'+process.env.CLIENT+'-client.mjs')){let f;if(specifier==='./lib/verify-commands.mjs')f='commands.mjs';if(specifier==='./verify/clients/model-fixture.mjs')f='fixture.mjs';if(f)return{url:pathToFileURL(process.env.STATE+'/'+f).href,shortCircuit:true};}return next(specifier,context);}});`,
);
const script = fileURLToPath(
new URL(
`../../../scripts/verify-${client}-client.mjs`,
import.meta.url,
),
);
const result = spawnSync(process.execPath, ["--import", hook, script], {
encoding: "utf8",
timeout: 10_000,
env: {
...process.env,
STATE: state,
CLIENT: client,
KIND: kind,
TMPDIR: state,
TMP: state,
TEMP: state,
},
});
expect(result.status).not.toBe(0);
const advanced = await readFile(
join(state, "setup-advanced"),
"utf8",
).then(
() => true,
() => false,
);
expect(advanced).toBe(allowed);
expect(result.stderr).toContain(
allowed ? "intentional stop before setup mutation" : "AssertionError",
);
} finally {
await rm(state, { recursive: true, force: true });
}
},
);