fix(cli): validate selected local paths before resolution

Reuse the nonempty NUL-free local path contract before normalization in artifact commands, auxiliary inputs, and output destinations. Empty selections now fail at parsing instead of selecting the working directory; explicit relative paths preserve their target.

Public CLI checks cover primary and auxiliary empty paths, exact relative-file digest, explicit current-directory selection, symlink parent semantics, and environment export inputs. Correct the desktop fixture to assert the existing CLI validation envelope.
This commit is contained in:
morluto committed 2026-10-24 07:28:09 +08:00
1 parent 231e458246
commit 9d7779d365
20 files changed
+229 -58

No files matched your search

+20 -9
View File
@@ -22,6 +22,7 @@ import { inspectNativeExportsInputSchema } from "../domain/native/nativeExports.
import { inspectElfNotesInputSchema } from "../domain/native/elfNotes.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { finishAnalysisCommand } from "./finishAnalysisCommand.js";
import { localPathStringSchema } from "../domain/localPath.js";
import { absoluteCallerPath } from "../filesystem/callerPath.js";
import {
analysisEvidenceDeliveryOptions,
@@ -37,7 +38,9 @@ export const registerBinaryDiagnosticsCommands = (
cli.command(CLI_COMMANDS.inspectElfNotes, {
description:
"Inspect ELF PT_NOTE and SHT_NOTE identities without executing the image",
args: z.object({ path: z.string().describe("Local ELF32/ELF64 image") }),
args: z.object({
path: localPathStringSchema.describe("Local ELF32/ELF64 image"),
}),
options: z.object({
maxFileBytes: inspectElfNotesInputSchema.shape.max_file_bytes,
maxEntries: inspectElfNotesInputSchema.shape.max_entries,
@@ -71,7 +74,7 @@ export const registerBinaryDiagnosticsCommands = (
cli.command(CLI_COMMANDS.inspectByteEntropy, {
description:
"Inspect file-wide and block byte entropy without executing the file",
args: z.object({ path: z.string().describe("Local file") }),
args: z.object({ path: localPathStringSchema.describe("Local file") }),
options: z.object({
blockSize: inspectByteEntropyInputSchema.shape.block_size.describe(
"Power-of-two block size from 256 to 65536 bytes (default 4096)",
@@ -108,7 +111,9 @@ export const registerBinaryDiagnosticsCommands = (
cli.command(CLI_COMMANDS.inspectPeCertificates, {
description:
"Inspect PE Authenticode certificate table identities without verifying signatures",
args: z.object({ path: z.string().describe("Local PE32/PE32+ image") }),
args: z.object({
path: localPathStringSchema.describe("Local PE32/PE32+ image"),
}),
options: z.object({
maxFileBytes: inspectPeCertificatesInputSchema.shape.max_file_bytes,
maxEntries: inspectPeCertificatesInputSchema.shape.max_entries,
@@ -141,7 +146,9 @@ export const registerBinaryDiagnosticsCommands = (
cli.command(CLI_COMMANDS.inspectPeResources, {
description:
"Inspect PE resource identities, payload ranges, hashes and icon-group relationships",
args: z.object({ path: z.string().describe("Local PE32/PE32+ image") }),
args: z.object({
path: localPathStringSchema.describe("Local PE32/PE32+ image"),
}),
options: z.object({
maxFileBytes: inspectPeResourcesInputSchema.shape.max_file_bytes,
maxEntries: inspectPeResourcesInputSchema.shape.max_entries,
@@ -174,7 +181,9 @@ export const registerBinaryDiagnosticsCommands = (
cli.command(CLI_COMMANDS.inspectNativeExports, {
description:
"Inspect a PE or ELF image's export table without executing it",
args: z.object({ path: z.string().describe("Local PE or ELF image") }),
args: z.object({
path: localPathStringSchema.describe("Local PE or ELF image"),
}),
options: z.object({
maxFileBytes: inspectNativeExportsInputSchema.shape.max_file_bytes,
...analysisEvidenceDeliveryOptions,
@@ -210,7 +219,9 @@ export const registerBinaryDiagnosticsCommands = (
description:
"Inspect binary file/linked layout without executing the selected object",
args: z.object({
path: z.string().describe("Local ELF binary or relocatable object"),
path: localPathStringSchema.describe(
"Local ELF binary or relocatable object",
),
}),
options: z.object({
pwntoolsTimeoutMs:
@@ -237,9 +248,9 @@ export const registerBinaryDiagnosticsCommands = (
description:
"Inspect supplied core registers/signals and optional debugger mapping evidence",
args: z.object({
path: z
.string()
.describe("Local Linux ELF64 amd64 or AArch64 little-endian core"),
path: localPathStringSchema.describe(
"Local Linux ELF64 amd64 or AArch64 little-endian core",
),
}),
options: z.object({
debuggerContext: z