mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
fix(setup): recognize inherited owned launcher
This commit is contained in:
1 parent
f2277454b8
commit
d2da713859
3 files changed
+128
-1
No files matched your search
@@ -705,7 +705,17 @@ const registrationOwnershipBlocker = (
|
||||
value: effective.servers[name],
|
||||
paths: client.configPaths ?? [client.configPath],
|
||||
});
|
||||
if (Object.hasOwn(parsed.servers, name))
|
||||
const fragment = parsed.servers[name];
|
||||
// A layered policy fragment inherits its launcher. Classify the effective
|
||||
// launcher above, but also admit any explicit command this write replaces.
|
||||
const inheritsLauncher =
|
||||
effective !== undefined &&
|
||||
effective !== parsed &&
|
||||
typeof fragment === "object" &&
|
||||
fragment !== null &&
|
||||
!Array.isArray(fragment) &&
|
||||
!Object.hasOwn(fragment, "command");
|
||||
if (Object.hasOwn(parsed.servers, name) && !inheritsLauncher)
|
||||
entries.push({ value: parsed.servers[name], paths: [client.configPath] });
|
||||
if (legacyClientServerPath(parsed, name) !== undefined) {
|
||||
entries.push({
|
||||
|
||||
@@ -262,3 +262,71 @@ cliTest(
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
cliTest(
|
||||
"OpenCode setup refreshes an owned inherited launcher through a policy fragment",
|
||||
async ({ cli }) => {
|
||||
const home = await createTestTempDirectory("rea-setup-owned-layer-");
|
||||
const directory = join(home, ".config", "opencode");
|
||||
await mkdir(directory, { recursive: true });
|
||||
const lower = join(directory, "config.json");
|
||||
const upper = join(directory, "opencode.json");
|
||||
const originalLower = JSON.stringify({
|
||||
mcp: { rea: { type: "local", command: ["rea", "mcp"] } },
|
||||
});
|
||||
const originalUpper = JSON.stringify({
|
||||
mcp: { rea: { environment: { CUSTOM: "keep" } } },
|
||||
});
|
||||
await writeFile(lower, originalLower);
|
||||
await writeFile(upper, originalUpper);
|
||||
const result = await cli.run({
|
||||
arguments: [
|
||||
"setup",
|
||||
"--client",
|
||||
"opencode",
|
||||
"--skill=false",
|
||||
"--yes",
|
||||
"--json",
|
||||
],
|
||||
cwd: home,
|
||||
environment: {
|
||||
HOME: home,
|
||||
USERPROFILE: home,
|
||||
XDG_CONFIG_HOME: join(home, ".config"),
|
||||
},
|
||||
});
|
||||
expect(result.exitCode, result.stdout).toBe(0);
|
||||
expect(await readFile(lower, "utf8")).toBe(originalLower);
|
||||
expect(await readFile(`${upper}.rea.backup`, "utf8")).toBe(originalUpper);
|
||||
expect(JSON.parse(await readFile(upper, "utf8"))).toMatchObject({
|
||||
mcp: { rea: { type: "local", environment: { CUSTOM: "keep" } } },
|
||||
});
|
||||
const foreignFragment = JSON.stringify({
|
||||
mcp: { rea: { command: ["other", "mcp"] } },
|
||||
});
|
||||
await writeFile(upper, foreignFragment);
|
||||
const blocked = await cli.run({
|
||||
arguments: [
|
||||
"setup",
|
||||
"--client",
|
||||
"opencode",
|
||||
"--skill=false",
|
||||
"--yes",
|
||||
"--json",
|
||||
],
|
||||
cwd: home,
|
||||
environment: {
|
||||
HOME: home,
|
||||
USERPROFILE: home,
|
||||
XDG_CONFIG_HOME: join(home, ".config"),
|
||||
},
|
||||
});
|
||||
expect(blocked.exitCode, blocked.stdout).toBe(1);
|
||||
expect(blocked.json).toMatchObject({
|
||||
status: "needs_human",
|
||||
remediation: expect.stringContaining("foreign ownership"),
|
||||
});
|
||||
expect(await readFile(upper, "utf8")).toBe(foreignFragment);
|
||||
expect(await readFile(`${upper}.rea.backup`, "utf8")).toBe(originalUpper);
|
||||
},
|
||||
);
|
||||
@@ -136,3 +136,52 @@ it("blocks an inherited foreign row before planning creation of a missing write
|
||||
code: "ENOENT",
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["other", "rea"])(
|
||||
"rechecks an inherited %s launcher after preflight for a policy fragment",
|
||||
async (command) => {
|
||||
const home = await createTestTempDirectory("rea-setup-layer-recheck-");
|
||||
const lower = join(home, "config.json");
|
||||
const configPath = join(home, "opencode.json");
|
||||
const client: SetupClient = {
|
||||
name: "opencode",
|
||||
format: "opencode",
|
||||
configPath,
|
||||
configPaths: [lower, configPath],
|
||||
};
|
||||
await writeFile(
|
||||
lower,
|
||||
'{"mcp":{"rea":{"type":"local","command":["rea","mcp"]}}}',
|
||||
);
|
||||
const original = '{"mcp":{"rea":{"environment":{"CUSTOM":"keep"}}}}';
|
||||
await writeFile(configPath, original);
|
||||
expect(
|
||||
await inspectClientConfiguration(client, {}, ["rea", "mcp"]),
|
||||
).toMatchObject({ status: "update" });
|
||||
// The write transaction must use a fresh source discovery after preflight.
|
||||
await writeFile(
|
||||
lower,
|
||||
JSON.stringify({
|
||||
mcp: { rea: { type: "local", command: [command, "mcp"] } },
|
||||
}),
|
||||
);
|
||||
const result = await configureClientConfiguration(client, {}, [
|
||||
"rea",
|
||||
"mcp",
|
||||
]);
|
||||
if (command === "other") {
|
||||
expect(result).toMatchObject({
|
||||
status: "failed",
|
||||
reason: "registration_ownership",
|
||||
detail: expect.stringContaining("foreign ownership"),
|
||||
});
|
||||
expect(await readFile(configPath, "utf8")).toBe(original);
|
||||
await expect(readFile(`${configPath}.rea.backup`)).rejects.toMatchObject({
|
||||
code: "ENOENT",
|
||||
});
|
||||
} else {
|
||||
expect(result).toMatchObject({ status: "configured" });
|
||||
expect(await readFile(`${configPath}.rea.backup`, "utf8")).toBe(original);
|
||||
}
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user