mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-10 20:36:09 +00:00
114 lines
4.4 KiB
TypeScript
114 lines
4.4 KiB
TypeScript
// Covers security scan path normalization and exclusion behavior.
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
extensionUsesSkippedScannerPath,
|
|
isPathInside,
|
|
isPathInsideWithRealpath,
|
|
} from "./scan-paths.js";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// isPathInside
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("isPathInside", () => {
|
|
it("returns true for same directory", () => {
|
|
const base = "/home/user/project";
|
|
expect(isPathInside(base, base)).toBe(true);
|
|
});
|
|
|
|
it("returns true for a direct child", () => {
|
|
expect(isPathInside("/home/user/project", "/home/user/project/src/file.ts")).toBe(true);
|
|
});
|
|
|
|
it("returns false when candidate escapes base with ..", () => {
|
|
expect(isPathInside("/home/user/project", "/home/user/other")).toBe(false);
|
|
});
|
|
|
|
it("returns false for absolute path outside base", () => {
|
|
expect(isPathInside("/home/user/project", "/etc/passwd")).toBe(false);
|
|
});
|
|
|
|
it("returns false for a sibling directory", () => {
|
|
expect(isPathInside("/home/user/a", "/home/user/b")).toBe(false);
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// isPathInsideWithRealpath
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("isPathInsideWithRealpath", () => {
|
|
const tmpDir = os.tmpdir();
|
|
|
|
it("returns true when both paths exist and candidate is inside base", () => {
|
|
// os.tmpdir() and itself both exist on disk
|
|
const result = isPathInsideWithRealpath(tmpDir, tmpDir);
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("returns false (line 25) when candidate is outside base without realpath check needed", () => {
|
|
// /etc is outside os.tmpdir() — isPathInside returns false immediately
|
|
const result = isPathInsideWithRealpath(tmpDir, "/etc");
|
|
expect(result).toBe(false); // covers line 25: return false
|
|
});
|
|
|
|
it("returns false (safe default) when realpath fails for non-existent candidate", () => {
|
|
// Non-existent path causes safeRealpathSync to return null (covers line 15)
|
|
// New safe default (requireRealpath not set): returns false — secure by default
|
|
const nonExistent = path.join(tmpDir, "__does_not_exist_clawin_test__");
|
|
const result = isPathInsideWithRealpath(tmpDir, nonExistent);
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it("returns false when requireRealpath is true and realpath fails", () => {
|
|
const nonExistent = path.join(tmpDir, "__does_not_exist_clawin_test__");
|
|
const result = isPathInsideWithRealpath(tmpDir, nonExistent, { requireRealpath: true });
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it("returns true (explicit opt-out) when requireRealpath is false and realpath fails", () => {
|
|
const nonExistent = path.join(tmpDir, "__does_not_exist_clawin_test__");
|
|
const result = isPathInsideWithRealpath(tmpDir, nonExistent, { requireRealpath: false });
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it("returns false (safe default) when realpath fails for base path", () => {
|
|
const nonExistentBase = path.join(tmpDir, "__nonexistent_base__");
|
|
const child = path.join(nonExistentBase, "child.ts");
|
|
const result = isPathInsideWithRealpath(nonExistentBase, child);
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// extensionUsesSkippedScannerPath
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe("extensionUsesSkippedScannerPath", () => {
|
|
it("returns true for node_modules segment", () => {
|
|
expect(extensionUsesSkippedScannerPath("src/node_modules/pkg/index.js")).toBe(true);
|
|
});
|
|
|
|
it("returns true for hidden directory (.hidden)", () => {
|
|
expect(extensionUsesSkippedScannerPath("src/.hidden/file.ts")).toBe(true);
|
|
});
|
|
|
|
it("returns false for normal paths", () => {
|
|
expect(extensionUsesSkippedScannerPath("src/utils/helpers.ts")).toBe(false);
|
|
});
|
|
|
|
it("returns false for a single . segment (current dir)", () => {
|
|
expect(extensionUsesSkippedScannerPath("./src/file.ts")).toBe(false);
|
|
});
|
|
|
|
it("returns false for a .. segment (parent dir)", () => {
|
|
expect(extensionUsesSkippedScannerPath("../src/file.ts")).toBe(false);
|
|
});
|
|
|
|
it("returns true for Windows-style paths with node_modules", () => {
|
|
expect(extensionUsesSkippedScannerPath("src\\node_modules\\pkg\\index.js")).toBe(true);
|
|
});
|
|
});
|