mirror of
https://github.com/morluto/rea.git
synced 2026-11-13 18:22:42 +00:00
fix(javascript): classify application input selection failures by cause
analyze_javascript_application reported every input-selection problem as an artifact fault: - a missing input path: "Artifact could not be read or written", with no path or reason; - an unreadable selected directory: the same generic io failure; - a regular file that is neither a directory nor an .asar, and a --artifact-format that contradicts the selection: "Artifact is invalid or has changed. Get a fresh copy and try again." Report a missing path as an invalid input_path, an unreadable selection as access_denied, a non-directory non-.asar file as unsupported_target with the accepted inputs as remediation, and a contradicting format as an invalid format with the observed kind as expected value. Failures inside a selected artifact keep their existing classification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f4c99ab8a5
commit
0a14bbbf05
7 files changed
+186
-18
No files matched your search
@@ -0,0 +1,102 @@
|
||||
import { chmod, mkdir, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { describe, expect, it, onTestFinished } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
|
||||
import { analyzeJavaScriptApplication } from "../../../src/application/javascript/JavaScriptApplicationService.js";
|
||||
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
|
||||
|
||||
const analyzeFailure = async (input: Record<string, unknown>) => {
|
||||
const result = await analyzeJavaScriptApplication(input);
|
||||
if (result.ok) throw new Error("Expected the selection to be refused");
|
||||
return projectAnalysisError(result.error);
|
||||
};
|
||||
|
||||
const application = async () => {
|
||||
const root = await createTestTempDirectory("rea-javascript-selection-");
|
||||
const directory = join(root, "app");
|
||||
await mkdir(directory);
|
||||
await writeFile(join(directory, "index.js"), "module.exports = 1;\n");
|
||||
return { root, directory };
|
||||
};
|
||||
|
||||
describe("JavaScript application input selection", () => {
|
||||
it("reports a missing input path as invalid input, not an artifact read failure", async () => {
|
||||
const { root } = await application();
|
||||
const missing = join(root, "missing");
|
||||
|
||||
expect(await analyzeFailure({ input_path: missing })).toMatchObject({
|
||||
code: "invalid_request",
|
||||
category: "invalid_input",
|
||||
details: {
|
||||
issues: [
|
||||
{
|
||||
path: ["input_path"],
|
||||
reason: "invalid_value",
|
||||
message: expect.stringContaining(missing),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("reports a file that is neither a directory nor an .asar as an unsupported target", async () => {
|
||||
const { root } = await application();
|
||||
const binary = join(root, "program");
|
||||
await writeFile(binary, Buffer.from([0xcf, 0xfa, 0xed, 0xfe]));
|
||||
|
||||
expect(await analyzeFailure({ input_path: binary })).toMatchObject({
|
||||
code: "unsupported_target",
|
||||
category: "unsupported_target",
|
||||
remediation: { action: expect.stringContaining(".asar") },
|
||||
details: {
|
||||
operation: "analyze_javascript_application",
|
||||
path: binary,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
["a directory", "directory", "asar"],
|
||||
["an .asar file", "asar", "directory"],
|
||||
] as const)(
|
||||
"reports %s selected with a contradicting format as an invalid request",
|
||||
async (_label, observed, format) => {
|
||||
const { root, directory } = await application();
|
||||
const selected =
|
||||
observed === "directory" ? directory : join(root, "app.asar");
|
||||
if (observed === "asar") await writeFile(selected, "not inspected");
|
||||
|
||||
expect(
|
||||
await analyzeFailure({ input_path: selected, format }),
|
||||
).toMatchObject({
|
||||
code: "invalid_request",
|
||||
details: {
|
||||
issues: [
|
||||
{
|
||||
path: ["format"],
|
||||
reason: "invalid_value",
|
||||
expected: ["auto", observed],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
|
||||
"reports an unreadable selected directory as a host access denial",
|
||||
async () => {
|
||||
const { directory } = await application();
|
||||
await chmod(directory, 0o000);
|
||||
onTestFinished(() => chmod(directory, 0o700));
|
||||
|
||||
expect(await analyzeFailure({ input_path: directory })).toMatchObject({
|
||||
code: "access_denied",
|
||||
details: { path: directory, system_code: "EACCES" },
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user