fix(sqlite): preserve schema-owned input issue paths

This commit is contained in:
morluto committed 2026-10-26 15:00:30 +08:00
1 parent 23d56e1abd
commit 9e4702b7a7
2 files changed
+33 -13

No files matched your search

+5 -12
View File
@@ -13,7 +13,6 @@ import type {
} from "../domain/analysisErrorBase.js";
import {
AnalysisCancelledError,
AnalysisInputError,
AnalysisOutputError,
AnalysisResourceConstraintError,
} from "../domain/analysisErrorCore.js";
@@ -30,7 +29,7 @@ import {
DEFAULT_SQLITE_WORKER_TIMEOUT_MS,
sqliteInspectionParameters,
} from "../domain/sqlite/sqliteDatabase.js";
import { isAbsolute } from "node:path";
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
import { PrivateRuntimeRoot } from "../process/PrivateRuntimeRoot.js";
import {
OwnedCommandFailure,
@@ -533,14 +532,8 @@ const completedSqliteEvidence = (
const validateSqliteInput = (input: InspectSqliteDatabaseInput): void => {
const parsed = inspectSqliteDatabaseInputSchema.safeParse(input);
if (!parsed.success || !isAbsolute(input.path))
throw new AnalysisInputError(operation, undefined, [
{
path: ["path"],
reason: "invalid_format",
message: parsed.success
? "path must be an absolute local filesystem path"
: parsed.error.message,
},
]);
if (!parsed.success)
throw analysisInputErrorFromIssues(operation, parsed.error.issues, input, {
cause: parsed.error,
});
};
@@ -4,7 +4,8 @@ import { access, lstat, readFile, symlink, writeFile } from "node:fs/promises";
import { DatabaseSync } from "node:sqlite";
import { promisify } from "node:util";
import { fileURLToPath } from "node:url";
import { expect, it as nativeTest, onTestFinished } from "vitest";
import { expect, it as nativeTest, onTestFinished, vi } from "vitest";
import { ZodError } from "zod";
import { projectAnalysisError } from "../../../src/domain/analysisErrorProjection.js";
import { ProviderCleanupError } from "../../../src/domain/providerCleanupError.js";
import { SQLITE_DATABASE_LIMITS } from "../../../src/sqlite/SqliteDatabaseLimits.js";
@@ -54,6 +55,32 @@ const createFixture = async (wal = false) => {
const expectPrivateRootRemoved = (path: string) =>
expect(access(path)).rejects.toMatchObject({ code: "ENOENT" });
nativeTest.each([
{ input: { path: "relative.db" }, field: "path" },
{
input: { path: "/selected.db", table: "records", row_limit: 0 },
field: "row_limit",
},
{ input: { path: "/selected.db", columns: ["id"] }, field: "columns" },
])(
"attributes invalid provider input to its argument before allocating resources: %j",
async ({ input, field }) => {
const createRuntime = vi.fn(async () => {
throw new Error("Invalid input must not allocate a SQLite runtime");
});
const provider = new SqliteDatabaseProvider({}, undefined, createRuntime);
onTestFinished(() => provider.close());
const result = await provider.inspect({ ...input });
if (result.ok) throw new Error("Expected an input rejection");
expect(result.error.cause).toBeInstanceOf(ZodError);
expect(projectAnalysisError(result.error)).toMatchObject({
code: "invalid_request",
details: { issues: [{ path: [field] }] },
});
expect(createRuntime).not.toHaveBeenCalled();
},
);
it("enforces a selected worker budget and completes the corrected same-database retry", async () => {
const { database } = await createFixture();
const original = await readFile(database.path);