Skip to content

Commit fe288fe

Browse files
author
CodeBuddy Attribution Bot
committed
fix(attribution): manageGateway/queryGateway 未返回完整可访问 URL,导致评测框架构造了错误的 hostname 触发 TLS 证书不 (issue_mojh1bit_4ih8ny)
1 parent e2ca73f commit fe288fe

2 files changed

Lines changed: 78 additions & 10 deletions

File tree

mcp/src/tools/gateway.test.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,11 @@ describe("gateway tools", () => {
7676
],
7777
});
7878
mockGetDomainList.mockResolvedValue({
79-
DefaultDomain: "env-test.app.tcloudbase.com",
79+
DefaultDomain: "env-test.tcbaccess-in.tencentcloudbase.com",
8080
EnableService: true,
8181
ServiceSet: [
8282
{
83-
Domain: "api.example.com",
83+
Domain: "env-test.app.tcloudbase.com",
8484
},
8585
],
8686
});
@@ -174,12 +174,15 @@ describe("gateway tools", () => {
174174
expect(payload).toMatchObject({
175175
success: true,
176176
message:
177-
"已为目标 helloFn 创建网关访问路径。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。",
177+
"已为目标 helloFn 创建网关访问路径。可访问 URL: https://env-test.app.tcloudbase.com/api/hello。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。",
178178
data: {
179179
action: "createAccess",
180180
targetType: "function",
181181
targetName: "helloFn",
182182
path: "/api/hello",
183+
urls: ["https://env-test.app.tcloudbase.com/api/hello"],
184+
primaryUrl: "https://env-test.app.tcloudbase.com/api/hello",
185+
domains: ["env-test.app.tcloudbase.com"],
183186
},
184187
nextActions: [
185188
expect.objectContaining({
@@ -225,6 +228,8 @@ describe("gateway tools", () => {
225228
targetType: "function",
226229
targetName: "helloFn",
227230
path: "/helloFn",
231+
urls: ["https://env-test.app.tcloudbase.com/helloFn"],
232+
primaryUrl: "https://env-test.app.tcloudbase.com/helloFn",
228233
},
229234
});
230235
});
@@ -271,10 +276,10 @@ describe("gateway tools", () => {
271276
targetType: "function",
272277
targetName: "helloFn",
273278
total: 1,
274-
domains: ["env-test.app.tcloudbase.com", "api.example.com"],
279+
domains: ["env-test.app.tcloudbase.com"],
280+
allDomains: ["env-test.tcbaccess-in.tencentcloudbase.com", "env-test.app.tcloudbase.com"],
275281
urls: [
276282
"https://env-test.app.tcloudbase.com/api/hello",
277-
"https://api.example.com/api/hello",
278283
],
279284
enableService: true,
280285
},
@@ -287,6 +292,34 @@ describe("gateway tools", () => {
287292
});
288293
});
289294

295+
it("queryGateway(action=getAccess) should exclude internal domains from urls", async () => {
296+
// Verify that internal domains (tencentcloudbase.com) are filtered out of urls
297+
// but still available in allDomains
298+
const result = await tools.queryGateway.handler({
299+
action: "getAccess",
300+
targetType: "function",
301+
targetName: "helloFn",
302+
});
303+
304+
const payload = JSON.parse(result.content[0].text);
305+
306+
// urls should NOT contain the internal domain
307+
expect(payload.data.urls).not.toContain(
308+
"https://env-test.tcbaccess-in.tencentcloudbase.com/api/hello",
309+
);
310+
// domains should NOT contain the internal domain
311+
expect(payload.data.domains).not.toContain(
312+
"env-test.tcbaccess-in.tencentcloudbase.com",
313+
);
314+
// allDomains should still contain both
315+
expect(payload.data.allDomains).toContain(
316+
"env-test.tcbaccess-in.tencentcloudbase.com",
317+
);
318+
expect(payload.data.allDomains).toContain(
319+
"env-test.app.tcloudbase.com",
320+
);
321+
});
322+
290323
it("queryGateway(action=listRoutes) should list gateway routes", async () => {
291324
const result = await tools.queryGateway.handler({
292325
action: "listRoutes",

mcp/src/tools/gateway.ts

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,29 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
109109
}
110110
};
111111

112+
/**
113+
* Internal domains (e.g. *.tcbaccess-in.tencentcloudbase.com) do not have
114+
* public TLS certificates and cannot be accessed over HTTPS from external
115+
* clients. Only *.tcloudbase.com domains are externally reachable.
116+
*/
117+
const isExternalDomain = (domain: string) =>
118+
domain.endsWith(".tcloudbase.com") || domain === "tcloudbase.com";
119+
112120
const listGatewayDomains = async () => {
113121
const cloudbase = await getManager();
114122
const result = await cloudbase.access.getDomainList();
115123
logCloudBaseResult(server.logger, result);
116124

117-
const domains = [
125+
const allDomains = [
118126
result.DefaultDomain,
119127
...(result.ServiceSet || []).map((item) => item.Domain),
120-
].filter(Boolean);
128+
].filter(Boolean) as string[];
129+
130+
const domains = allDomains.filter(isExternalDomain);
121131

122132
return {
123133
domains,
134+
allDomains,
124135
enableService: result.EnableService,
125136
raw: result,
126137
};
@@ -207,10 +218,11 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
207218
{
208219
action: input.action,
209220
domains: result.domains,
221+
allDomains: result.allDomains,
210222
enableService: result.enableService,
211223
raw: result.raw,
212224
},
213-
`已获取 ${result.domains.length} 个网关域名`,
225+
`已获取 ${result.domains.length} 个外部可访问网关域名(共 ${result.allDomains.length} 个,已过滤内部域名)`,
214226
[
215227
{
216228
tool: "queryGateway",
@@ -297,6 +309,7 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
297309
apis: accessList.APISet || [],
298310
total: accessList.Total || 0,
299311
domains: domainInfo.domains,
312+
allDomains: domainInfo.allDomains,
300313
urls,
301314
enableService:
302315
accessList.EnableService ?? domainInfo.enableService ?? false,
@@ -305,7 +318,7 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
305318
domainList: domainInfo.raw,
306319
},
307320
},
308-
`已获取目标 ${input.targetName} 的网关访问配置`,
321+
`已获取目标 ${input.targetName} 的网关访问配置(urls 仅包含外部可访问域名)`,
309322
[
310323
{
311324
tool: "manageGateway",
@@ -355,15 +368,37 @@ export function registerGatewayTools(server: ExtendedMcpServer) {
355368
}
356369
logCloudBaseResult(server.logger, result);
357370

371+
// Fetch domain list so we can return the accessible URL immediately
372+
let domainInfo: Awaited<ReturnType<typeof listGatewayDomains>> | undefined;
373+
try {
374+
domainInfo = await listGatewayDomains();
375+
} catch {
376+
// Non-fatal: domain lookup failure should not block the createAccess response
377+
}
378+
379+
const urls =
380+
domainInfo && domainInfo.domains.length > 0
381+
? domainInfo.domains.map(
382+
(domain) => `https://${domain}${accessPath}`,
383+
)
384+
: [];
385+
386+
const primaryUrl = urls[0] || null;
387+
358388
return buildEnvelope(
359389
{
360390
action: input.action,
361391
targetType: input.targetType,
362392
targetName: input.targetName,
363393
path: accessPath,
394+
urls,
395+
primaryUrl,
396+
domains: domainInfo?.domains ?? [],
364397
raw: result,
365398
},
366-
`已为目标 ${input.targetName} 创建网关访问路径。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`,
399+
primaryUrl
400+
? `已为目标 ${input.targetName} 创建网关访问路径。可访问 URL: ${primaryUrl}。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`
401+
: `已为目标 ${input.targetName} 创建网关访问路径。注意:路由配置传播通常需要等待 30 秒到 3 分钟,请勿立即访问。该操作只创建网关入口,不会自动放开函数安全规则;若需要匿名或浏览器直接访问,请继续检查函数资源权限。`,
367402
[
368403
{
369404
tool: "queryGateway",

0 commit comments

Comments
 (0)