fix(process): resolve POSIX backslash basenames through PATH (#2471)
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
parent
0ca70e121c
commit
03ab521db3
|
|
@ -17,6 +17,28 @@ import {
|
|||
resolveProcessScenarioRuntimePaths,
|
||||
} from "./ProcessScenarioRuntimeValidation.js";
|
||||
import { parseProcessScenario } from "../../domain/process/processScenario.js";
|
||||
import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js";
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
"resolves a literal backslash in a POSIX executable basename through PATH",
|
||||
async () => {
|
||||
const root = await createTestTempDirectory("rea-process-posix-basename-");
|
||||
const bin = join(root, "bin");
|
||||
await mkdir(bin);
|
||||
const command = "selected\\node";
|
||||
const selected = join(bin, command);
|
||||
await symlink(process.execPath, selected);
|
||||
await expect(resolveExecutable(command, root, bin)).resolves.toBe(selected);
|
||||
const resolved = await resolveProcessScenarioRuntimePaths(
|
||||
parseProcessScenario({
|
||||
executable: command,
|
||||
working_directory: root,
|
||||
environment: { PATH: bin },
|
||||
}),
|
||||
);
|
||||
expect(resolved.executable).toBe(selected);
|
||||
},
|
||||
);
|
||||
|
||||
it("preserves the caller-selected executable symlink for process invocation", async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), "rea-process-executable-alias-"));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { constants as fsConstants } from "node:fs";
|
||||
import { access, realpath, stat } from "node:fs/promises";
|
||||
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
||||
import { delimiter, isAbsolute, join, resolve, sep } from "node:path";
|
||||
|
||||
import type { ProcessScenario } from "../../domain/process/processScenario.js";
|
||||
import { AnalysisInputError } from "../../domain/analysisErrorCore.js";
|
||||
|
|
@ -71,7 +71,9 @@ export const resolveExecutable = async (
|
|||
: resolve(workingDirectory, directory),
|
||||
);
|
||||
const candidates =
|
||||
isAbsolute(command) || command.includes("/") || command.includes("\\")
|
||||
isAbsolute(command) ||
|
||||
command.includes("/") ||
|
||||
(sep === "\\" && command.includes("\\"))
|
||||
? [resolve(workingDirectory, command)]
|
||||
: directories.map((directory) => join(directory, command));
|
||||
const failures: string[] = [];
|
||||
|
|
|
|||
|
|
@ -28,6 +28,35 @@ const identitySchema = z.object({
|
|||
const itWithLinuxCaptureCapability =
|
||||
process.platform === "linux" ? itWithCaptureCapability : it.skip;
|
||||
|
||||
itWithCaptureCapability(
|
||||
"captures a POSIX PATH executable with a literal backslash in its basename",
|
||||
async () => {
|
||||
const root = await createTestTempDirectory("rea-process-backslash-name-");
|
||||
const bin = join(root, "bin");
|
||||
await mkdir(bin);
|
||||
const command = "selected\\node";
|
||||
const selected = join(bin, command);
|
||||
await symlink(process.execPath, selected);
|
||||
const scenario = parseProcessScenario({
|
||||
executable: command,
|
||||
working_directory: root,
|
||||
environment: { PATH: bin },
|
||||
arguments: ["-e", 'process.stdout.write("selected executable")'],
|
||||
settle_ms: 100,
|
||||
});
|
||||
const result = await captureProcessScenario(scenario);
|
||||
if (!result.ok) throw result.error;
|
||||
expect(result.value.frames.map(({ data }) => data).join("")).toBe(
|
||||
"selected executable",
|
||||
);
|
||||
expect(result.value.exit).toMatchObject({ code: 0, reason: "exited" });
|
||||
expect(result.value.cleanup).toMatchObject({
|
||||
owned_process_group: "verified",
|
||||
temporary_root: "removed",
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
itWithCaptureCapability(
|
||||
"preserves numeric reports and original normalized PTY text in Evidence",
|
||||
async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue