From a74ce4512c9cdb6a3dd33c1cf8ddcae41be2e0f6 Mon Sep 17 00:00:00 2001 From: RRFZ <247457381+Plastic-time@users.noreply.github.com> Date: Fri, 6 Nov 2026 01:34:07 -0500 Subject: [PATCH] fix(cli): reject non-decimal desktop application limits (#9061) inspect-desktop-application took --max_entries and --max_probe_bytes through Number(), so 0x1 examined one entry and 1e1 ten. Admit decimal text only and keep the shared fields' bounds and defaults. --- src/cli/desktopApplicationCommands.ts | 19 ++++---- .../cli/desktopApplicationCli.test.ts | 48 +++++++++++++++++++ 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/cli/desktopApplicationCommands.ts b/src/cli/desktopApplicationCommands.ts index cc0fd32456..7a90547237 100644 --- a/src/cli/desktopApplicationCommands.ts +++ b/src/cli/desktopApplicationCommands.ts @@ -12,6 +12,7 @@ import { absoluteCallerPath } from "../filesystem/callerPath.js"; import { CLI_COMMANDS } from "../cliCommandNames.js"; import { logCliCommand } from "../cliLogging.js"; import { withCommandCancellation } from "./commandCancellation.js"; +import { cliDecimalField } from "./options.js"; /** One-shot complete Evidence can be saved and queried with inspect-analysis-view. */ export const registerDesktopApplicationCommands = ( @@ -25,15 +26,17 @@ export const registerDesktopApplicationCommands = ( path: localPathStringSchema.describe("Local installation directory"), }), options: z.object({ - max_entries: - inspectDesktopApplicationInputSchema.shape.max_entries.describe( - "Maximum directory entries to examine; exhaustion leaves partial coverage", - ), + // Decimal tokens only: numeric coercion would read "0x1" as 1 and + // "1e1" as 10. The shared fields keep their bounds and defaults. + max_entries: cliDecimalField( + inspectDesktopApplicationInputSchema.shape.max_entries, + ).describe( + "Maximum directory entries to examine; exhaustion leaves partial coverage", + ), ...analysisEvidenceDeliveryOptions, - max_probe_bytes: - inspectDesktopApplicationInputSchema.shape.max_probe_bytes.describe( - "Maximum total bytes read from selected file ranges", - ), + max_probe_bytes: cliDecimalField( + inspectDesktopApplicationInputSchema.shape.max_probe_bytes, + ).describe("Maximum total bytes read from selected file ranges"), }), run: ({ args, options }) => withCommandCancellation((signal) => diff --git a/tests/boundary/cli/desktopApplicationCli.test.ts b/tests/boundary/cli/desktopApplicationCli.test.ts index 92020943af..1fd42fa3ea 100644 --- a/tests/boundary/cli/desktopApplicationCli.test.ts +++ b/tests/boundary/cli/desktopApplicationCli.test.ts @@ -193,3 +193,51 @@ cliTest.skipIf(process.platform === "win32" || process.getuid?.() === 0)( } }, ); + +// Numeric coercion admits each spelling within the field's bounds: +// "0x1" as 1 entry, "1e1" as 10 entries and "0x1000" as 4096 bytes. +cliTest.for([ + ["max_entries", "0x1"], + ["max_entries", "1e1"], + ["max_probe_bytes", "0x1000"], +] as const)( + "rejects %s %s as a non-decimal desktop limit", + async ([field, value], { cli }) => { + const root = await createTestTempDirectory("rea-desktop-limit-"); + const result = await cli.run({ + arguments: [ + "inspect-desktop-application", + root, + `--${field}=${value}`, + "--json", + ], + }); + expect(result.exitCode).toBe(1); + expect(result.json).toMatchObject({ + code: "VALIDATION_ERROR", + fieldErrors: [expect.objectContaining({ path: field })], + }); + }, +); + +cliTest("keeps a decimal desktop entry limit", async ({ cli }) => { + const root = await createTestTempDirectory("rea-desktop-limit-"); + await writeFile(join(root, "a.txt"), "a"); + await writeFile(join(root, "b.txt"), "b"); + const result = await cli.run({ + arguments: [ + "inspect-desktop-application", + root, + "--max_entries=01", + "--json", + ], + }); + expect(result.exitCode, result.stderr).toBe(0); + expect(parseEvidence(result.json).normalized_result).toMatchObject({ + coverage: { + status: "partial", + entries_examined: 1, + limits: { max_entries: 1 }, + }, + }); +});