Skip to content

Commit dbcb3b6

Browse files
committed
fix(project): enforce global gateway target names
1 parent 75c8193 commit dbcb3b6

2 files changed

Lines changed: 62 additions & 22 deletions

File tree

src/core/project/manager.tsx

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ export class FsProjectManager implements ProjectManager {
210210
break;
211211
}
212212
case "gateway-target": {
213+
this.assertUniqueGatewayTargetName(existingProjectSpec, input.resourceConfig.name);
213214
const gatewayIndex = existingProjectSpec.agentCoreGateways.findIndex(
214215
(gateway) => gateway.name === input.gatewayName,
215216
);
@@ -219,11 +220,6 @@ export class FsProjectManager implements ProjectManager {
219220
);
220221
}
221222
const gateway = existingProjectSpec.agentCoreGateways[gatewayIndex]!;
222-
this.assertUniqueName(
223-
gateway.targets,
224-
input.resourceConfig.name,
225-
`target in gateway '${input.gatewayName}'`,
226-
);
227223

228224
const gateways = [...existingProjectSpec.agentCoreGateways];
229225
gateways[gatewayIndex] = {
@@ -307,6 +303,22 @@ export class FsProjectManager implements ProjectManager {
307303
};
308304
}
309305

306+
private assertUniqueGatewayTargetName(project: Project["spec"], name: string): void {
307+
const gateway = project.agentCoreGateways.find((candidate) =>
308+
candidate.targets.some((target) => target.name === name),
309+
);
310+
if (gateway) {
311+
throw new InputValidationError(
312+
`a gateway target with name '${name}' already exists in gateway '${gateway.name}'`,
313+
);
314+
}
315+
if (project.unassignedTargets?.some((target) => target.name === name)) {
316+
throw new InputValidationError(
317+
`an unassigned gateway target with name '${name}' already exists`,
318+
);
319+
}
320+
}
321+
310322
private assertUniqueName(
311323
resources: readonly { name: string }[],
312324
name: string,

src/handlers/project/add/gateway-add.test.ts

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -364,22 +364,54 @@ describe("project add gateway-target", () => {
364364
expect((await projectSpec(projectRoot)).agentCoreGateways[0].targets[0]).toEqual(target);
365365
});
366366

367-
test("allows equal Target names in different Gateways but not the same Gateway", async () => {
367+
test("rejects duplicate Target names across every Gateway in the project", async () => {
368368
const projectRoot = await inProject();
369369
await addGateway("tools");
370370
await addGateway("payments");
371+
await run([
372+
"add",
373+
"gateway-target",
374+
"--gateway",
375+
"tools",
376+
"--name",
377+
"search",
378+
"--endpoint",
379+
"https://tools.example.com",
380+
]);
381+
371382
for (const gateway of ["tools", "payments"]) {
372-
await run([
373-
"add",
374-
"gateway-target",
375-
"--gateway",
376-
gateway,
377-
"--name",
378-
"search",
379-
"--endpoint",
380-
`https://${gateway}.example.com`,
381-
]);
383+
await expect(
384+
run([
385+
"add",
386+
"gateway-target",
387+
"--gateway",
388+
gateway,
389+
"--name",
390+
"search",
391+
"--endpoint",
392+
`https://${gateway}.example.com`,
393+
]),
394+
).rejects.toThrow("already exists in gateway 'tools'");
382395
}
396+
397+
const gateways = (await projectSpec(projectRoot)).agentCoreGateways;
398+
expect(gateways[0].targets).toHaveLength(1);
399+
expect(gateways[1].targets).toHaveLength(0);
400+
});
401+
402+
test("rejects a Target name already present in unassignedTargets", async () => {
403+
const projectRoot = await inProject();
404+
const spec = await projectSpec(projectRoot);
405+
spec.unassignedTargets = [
406+
{
407+
name: "search",
408+
targetType: "mcpServer",
409+
endpoint: "https://unassigned.example.com",
410+
},
411+
];
412+
await writeProjectSpec(projectRoot, spec);
413+
await addGateway("tools");
414+
383415
await expect(
384416
run([
385417
"add",
@@ -389,13 +421,9 @@ describe("project add gateway-target", () => {
389421
"--name",
390422
"search",
391423
"--endpoint",
392-
"https://duplicate.example.com",
424+
"https://tools.example.com",
393425
]),
394-
).rejects.toThrow("already exists");
395-
396-
const gateways = (await projectSpec(projectRoot)).agentCoreGateways;
397-
expect(gateways[0].targets).toHaveLength(1);
398-
expect(gateways[1].targets).toHaveLength(1);
426+
).rejects.toThrow("unassigned gateway target");
399427
});
400428
});
401429

0 commit comments

Comments
 (0)