diff --git a/src/application/WebScriptExportService.ts b/src/application/WebScriptExportService.ts index c0a52b351a..d0cd45ea31 100644 --- a/src/application/WebScriptExportService.ts +++ b/src/application/WebScriptExportService.ts @@ -85,16 +85,20 @@ export const exportWebScriptsValidated = async ( resources: ArtifactResourceScope, options: ExecutionOptions = {}, ): Promise> => { - if (!isAbsolute(input.capture_path) || !isAbsolute(input.output_directory)) + const invalidPaths = (["capture_path", "output_directory"] as const).filter( + (field) => !isAbsolute(input[field]), + ); + if (invalidPaths.length > 0) return err( - new AnalysisInputError(OPERATION, undefined, [ - { - path: [], - reason: "invalid_format", - message: - "capture_path and output_directory must be absolute filesystem paths on this host.", - }, - ]), + new AnalysisInputError( + OPERATION, + undefined, + invalidPaths.map((field) => ({ + path: [field], + reason: "invalid_format" as const, + message: `${field} must be an absolute filesystem path on this host.`, + })), + ), ); try { if (options.signal?.aborted) diff --git a/tests/boundary/filesystem/webScriptExport.test.ts b/tests/boundary/filesystem/webScriptExport.test.ts index 24fd34ad11..942ca7ae3a 100644 --- a/tests/boundary/filesystem/webScriptExport.test.ts +++ b/tests/boundary/filesystem/webScriptExport.test.ts @@ -761,7 +761,9 @@ describe("captured script final commit cancellation", () => { }); }, ); +}); +describe("captured script path validation", () => { it("identifies a missing capture file and rejected host path syntax", async () => { const { input, resources } = await setup(); const missing = await exportWebScripts( @@ -784,15 +786,67 @@ describe("captured script final commit cancellation", () => { ], }, }); - const relative = await exportWebScripts( + const relativeCapture = await exportWebScripts( { ...input, capture_path: "capture.json", }, resources, ); - if (relative.ok) throw new Error("Expected host path error"); - expect(relative.error._tag).toBe("AnalysisInputError"); + if (relativeCapture.ok) throw new Error("Expected host path error"); + expect(relativeCapture.error).toMatchObject({ + _tag: "AnalysisInputError", + issues: [ + { + path: ["capture_path"], + reason: "invalid_format", + message: + "capture_path must be an absolute filesystem path on this host.", + }, + ], + }); + + const relativeOutput = await exportWebScripts( + { + ...input, + output_directory: "dist", + }, + resources, + ); + if (relativeOutput.ok) throw new Error("Expected host path error"); + expect(relativeOutput.error).toMatchObject({ + _tag: "AnalysisInputError", + issues: [ + { + path: ["output_directory"], + reason: "invalid_format", + message: + "output_directory must be an absolute filesystem path on this host.", + }, + ], + }); + + const bothRelative = await exportWebScripts( + { + capture_path: "capture.json", + output_directory: "dist", + }, + resources, + ); + if (bothRelative.ok) throw new Error("Expected host path error"); + expect(bothRelative.error).toMatchObject({ + _tag: "AnalysisInputError", + issues: [ + { + path: ["capture_path"], + reason: "invalid_format", + }, + { + path: ["output_directory"], + reason: "invalid_format", + }, + ], + }); }); });