fix(ida): report registration timeout bounds (#7893)

This commit is contained in:
morluto authored and GitHub committed 2026-10-29 08:11:07 +08:00
1 parent 3a512303d9
commit b0b25ad93e
2 files changed
+61 -6

No files matched your search

+19 -6
View File
@@ -5,6 +5,7 @@ import { AnalysisCleanupLease } from "../artifacts/AnalysisCleanupLease.js";
import type { RetainedResourceScope } from "../application/AnalysisProvider.js";
import { ConfigurationError } from "../domain/configurationErrors.js";
import { AnalysisCancelledError } from "../domain/analysisErrorCore.js";
import type { AnalysisInputIssue } from "../domain/analysisErrorCore.js";
import { projectInputIssues } from "../domain/inputIssueProjection.js";
import { err, ok, type Result } from "../domain/result.js";
import {
@@ -20,6 +21,8 @@ import { readBoundedFileBytes } from "../process/BoundedFileBytes.js";
/** Omitted registration `timeoutMs` for each upstream IDA MCP request. */
export const DEFAULT_IDA_REQUEST_TIMEOUT_MS = 300_000;
/** Shortest valid registration request timeout. */
const MIN_IDA_REQUEST_TIMEOUT_MS = 1;
/** Node timer ceiling. Larger registration values would be clamped instead of honored. */
export const MAX_IDA_REQUEST_TIMEOUT_MS = 2_147_483_647;
@@ -34,7 +37,7 @@ const common = {
protocol: z.literal("native").optional(),
timeoutMs: z
.int()
.positive()
.min(MIN_IDA_REQUEST_TIMEOUT_MS)
.max(MAX_IDA_REQUEST_TIMEOUT_MS)
.default(DEFAULT_IDA_REQUEST_TIMEOUT_MS),
workspaceRoot: z
@@ -78,6 +81,17 @@ const registrationSchema = z
/** An upstream MCP registration plus REA's database lifecycle selection. */
export type IdaConfiguration = z.infer<typeof registrationSchema>;
/** Render only schema-owned constraints, never rejected registration values. */
const registrationConstraint = (
issue: AnalysisInputIssue,
): string | undefined => {
if (issue.path.length === 1 && issue.path[0] === "timeoutMs")
return `timeoutMs must be an integer from ${String(MIN_IDA_REQUEST_TIMEOUT_MS)} to ${String(MAX_IDA_REQUEST_TIMEOUT_MS)} milliseconds`;
return issue.message === undefined
? undefined
: `${issue.path.join(".") || "registration"}: ${issue.message}`;
};
/** Resolved compatibility facts; persisted identities and diagnostics intentionally differ. */
export const IDA_COMPATIBILITY_PROFILES = {
legacy: {
@@ -171,11 +185,10 @@ export const readIdaConfiguration = (
const constraints = projectInputIssues(
parsed.error.issues,
registration,
).flatMap((issue) =>
issue.message === undefined
? []
: [`${issue.path.join(".") || "registration"}: ${issue.message}`],
);
).flatMap((issue) => {
const constraint = registrationConstraint(issue);
return constraint === undefined ? [] : [constraint];
});
if (constraints.length === 0)
return err(
idaConfigurationError(
@@ -119,6 +119,17 @@ cliTest.for([
},
constraint: "workspaceRoot must be absolute",
},
...[0, 2_147_483_648, 1.5, "registration-secret"].map((timeoutMs) => ({
name: `invalid timeout ${String(timeoutMs)}`,
registration: { command: "provider-must-not-launch", timeoutMs },
constraint:
"timeoutMs must be an integer from 1 to 2147483647 milliseconds",
})),
...[1, 2_147_483_647].map((timeoutMs) => ({
name: `valid timeout ${String(timeoutMs)}`,
registration: { command: "provider-must-not-launch", timeoutMs },
constraint: undefined,
})),
{
name: "valid registration",
registration: { command: "provider-must-not-launch", args: [] },
@@ -156,5 +167,36 @@ cliTest.for([
]),
});
expect(result.stdout).not.toContain("registration-secret");
if (constraint?.startsWith("timeoutMs") === true) {
const providers = await cli.run({
arguments: ["providers", "--json"],
environment: { HOME: root, REA_IDA_MCP_CONFIG: path },
timeoutMs: 10_000,
});
expect(providers.exitCode, providers.stderr).toBe(0);
expect(providers.json).toMatchObject({
analysis_provider_candidates: expect.arrayContaining([
expect.objectContaining({
provider: expect.objectContaining({ id: "ida" }),
availability: expect.objectContaining({
status: "unavailable",
code: "open_options_invalid",
reason: expect.stringContaining(constraint),
diagnostics: expect.objectContaining({
configuration_details: expect.objectContaining({
settings: expect.arrayContaining([
expect.objectContaining({
setting: "REA_IDA_MCP_CONFIG",
constraint: expect.stringContaining(constraint),
}),
]),
}),
}),
}),
}),
]),
});
expect(providers.stdout).not.toContain("registration-secret");
}
},
);