fix(cli): reject non-decimal web capture deadlines (#9167)

This commit is contained in:
RRFZ authored and GitHub committed 2026-11-07 01:29:44 +08:00
1 parent 10407fb624
commit d1103beb8d
3 files changed
+31 -4

No files matched your search

+4 -1
View File
@@ -38,6 +38,7 @@ import { inspectWebNetworkCaptureInputSchema } from "../domain/webNetworkCapture
import { withCommandCancellation } from "./commandCancellation.js"; import { withCommandCancellation } from "./commandCancellation.js";
import { finishAnalysisCommand } from "./finishAnalysisCommand.js"; import { finishAnalysisCommand } from "./finishAnalysisCommand.js";
import type { CliInstance } from "./types.js"; import type { CliInstance } from "./types.js";
import { cliDecimalField } from "./options.js";
/** Same envelope label as the other JSON-input commands and `parseCliJsonInput`. */ /** Same envelope label as the other JSON-input commands and `parseCliJsonInput`. */
const cliError = (error: AnalysisError): JsonValue => ({ const cliError = (error: AnalysisError): JsonValue => ({
@@ -512,8 +513,10 @@ const registerBuildCommand = (
.boolean() .boolean()
.default(false) .default(false)
.describe("Run every stage and report, but write nothing"), .describe("Run every stage and report, but write nothing"),
captureTimeoutMs: // Decimal tokens only: numeric coercion would read "0x1" as 1 ms.
captureTimeoutMs: cliDecimalField(
inspectWebNetworkCaptureInputSchema.shape.capture_timeout_ms, inspectWebNetworkCaptureInputSchema.shape.capture_timeout_ms,
),
}), }),
run: ({ args, options }) => run: ({ args, options }) =>
withCommandCancellation((signal) => withCommandCancellation((signal) =>
+4 -2
View File
@@ -8,7 +8,7 @@ import { CLI_COMMANDS } from "../cliCommandNames.js";
import { logCliCommand } from "../cliLogging.js"; import { logCliCommand } from "../cliLogging.js";
import type { Logger } from "pino"; import type { Logger } from "pino";
import type { CliInstance } from "./types.js"; import type { CliInstance } from "./types.js";
import { cliIntegerArgument } from "./options.js"; import { cliDecimalField, cliIntegerArgument } from "./options.js";
import { withCommandCancellation } from "./commandCancellation.js"; import { withCommandCancellation } from "./commandCancellation.js";
import { import {
analysisEvidenceDeliveryOptions, analysisEvidenceDeliveryOptions,
@@ -55,8 +55,10 @@ export const registerWebNetworkCaptureCommands = (
.optional() .optional()
.describe("Zero-based producer ordinals; repeat to select several"), .describe("Zero-based producer ordinals; repeat to select several"),
...explicitSensitiveValueOptions, ...explicitSensitiveValueOptions,
captureTimeoutMs: // Decimal tokens only: numeric coercion would read "0x1" as 1 ms.
captureTimeoutMs: cliDecimalField(
inspectWebNetworkCaptureInputSchema.shape.capture_timeout_ms, inspectWebNetworkCaptureInputSchema.shape.capture_timeout_ms,
),
}), }),
run: ({ args, options }) => run: ({ args, options }) =>
withCommandCancellation((signal) => withCommandCancellation((signal) =>
+23 -1
View File
@@ -152,7 +152,13 @@ cliTest(
const har = join(root, "grafana.har"); const har = join(root, "grafana.har");
await writeFile(har, JSON.stringify(environmentManifestHar())); await writeFile(har, JSON.stringify(environmentManifestHar()));
const planned = await cli.run({ const planned = await cli.run({
arguments: ["environment-build", har, "--dry-run", "--json"], arguments: [
"environment-build",
har,
"--dry-run",
"--capture-timeout-ms=030000",
"--json",
],
timeoutMs: 60_000, timeoutMs: 60_000,
}); });
expect(planned.exitCode, planned.stderr).toBe(0); expect(planned.exitCode, planned.stderr).toBe(0);
@@ -188,6 +194,22 @@ cliTest(
expect(conflicting.exitCode).toBe(1); expect(conflicting.exitCode).toBe(1);
expect(conflicting.json).toMatchObject({ code: "invalid_request" }); expect(conflicting.json).toMatchObject({ code: "invalid_request" });
// Both capture readers share the field. Numeric coercion would read
// "0x1" as a 1 ms capture deadline.
for (const command of [
["environment-build", har, "--dry-run"],
["inspect-web-network-capture", har, "har"],
]) {
const hexDeadline = await cli.run({
arguments: [...command, "--capture-timeout-ms=0x1", "--json"],
});
expect(hexDeadline.exitCode).toBe(1);
expect(hexDeadline.json).toMatchObject({
code: "VALIDATION_ERROR",
fieldErrors: [expect.objectContaining({ path: "captureTimeoutMs" })],
});
}
const noDirectory = await cli.run({ const noDirectory = await cli.run({
arguments: ["environment-build", har, "--json"], arguments: ["environment-build", har, "--json"],
timeoutMs: 60_000, timeoutMs: 60_000,