@sweny-ai/core 0.1.56 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* - Security: no auth token leakage, URL validation
|
|
11
11
|
*/
|
|
12
12
|
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
13
|
+
import { randomBytes } from "node:crypto";
|
|
13
14
|
import { tmpdir } from "node:os";
|
|
14
15
|
import * as path from "node:path";
|
|
15
16
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
16
17
|
import { classifySource, sourceZ, hashContent, resolveSource, resolveSources, } from "./sources.js";
|
|
17
|
-
const fileTmp = path.join(tmpdir(),
|
|
18
|
+
const fileTmp = path.join(tmpdir(), `sweny-sources-validation-test-${randomBytes(4).toString("hex")}`);
|
|
18
19
|
const baseCtx = () => ({
|
|
19
20
|
cwd: "/tmp",
|
|
20
21
|
env: {},
|
|
@@ -253,6 +254,24 @@ describe("error messages include actionable information", () => {
|
|
|
253
254
|
expect(e.message).toContain("--offline");
|
|
254
255
|
}
|
|
255
256
|
});
|
|
257
|
+
it("SOURCE_FILE_READ_FAILED on permission denied", async () => {
|
|
258
|
+
const unreadable = path.join(fileTmp, "unreadable.md");
|
|
259
|
+
writeFileSync(unreadable, "secret");
|
|
260
|
+
const { chmodSync } = await import("node:fs");
|
|
261
|
+
chmodSync(unreadable, 0o000);
|
|
262
|
+
try {
|
|
263
|
+
await resolveSource("./unreadable.md", "context[0]", { ...baseCtx(), cwd: fileTmp });
|
|
264
|
+
expect.unreachable("should have thrown");
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
expect(e.message).toContain("SOURCE_FILE_READ_FAILED");
|
|
268
|
+
expect(e.message).toContain("unreadable.md");
|
|
269
|
+
expect(e.message).toContain("context[0]");
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
chmodSync(unreadable, 0o644);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
256
275
|
it("SOURCE_OFFLINE_REQUIRES_FETCH includes the URL and field path", async () => {
|
|
257
276
|
try {
|
|
258
277
|
await resolveSource("https://example.com/rules.md", "rules[1]", { ...baseCtx(), offline: true });
|