From 9a4fd9a948d80f1ee6513f96aad6b7af2c92d31b Mon Sep 17 00:00:00 2001 From: NotWrench Date: Tue, 5 May 2026 08:40:39 +0530 Subject: [PATCH 1/2] fix: update file path handling in RegexScannerDriver to use POSIX format. This change ensures consistent path representation across different operating systems. --- packages/scanner/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/scanner/src/index.ts b/packages/scanner/src/index.ts index 6923b8f..db3e1e9 100644 --- a/packages/scanner/src/index.ts +++ b/packages/scanner/src/index.ts @@ -112,7 +112,8 @@ export class RegexScannerDriver implements ScannerDriver { nodir: true, absolute: false, }); - globCache.set(key, files); + const posixPaths = files.map((p) => p.replace(/\\/g, "/")); + globCache.set(key, posixPaths); yield { type: "matcher_done" as const, message: `Found ${files.length} files`, From 63d5a2c08b8d5921ca695ec7a72b17c84c04ac89 Mon Sep 17 00:00:00 2001 From: NotWrench Date: Tue, 5 May 2026 09:02:32 +0530 Subject: [PATCH 2/2] feat: enhance E2E testing setup and unify path handling across OS. Added global setup for E2E tests and updated path functions to use POSIX format for consistent behavior across different operating systems. --- e2e/global-setup.ts | 11 ++++++++ e2e/vitest.config.ts | 1 + knip.json | 1 + packages/core/src/paths.ts | 25 +++++++++++-------- packages/deepsec/src/commands/init-project.ts | 4 ++- 5 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 e2e/global-setup.ts diff --git a/e2e/global-setup.ts b/e2e/global-setup.ts new file mode 100644 index 0000000..cca86d5 --- /dev/null +++ b/e2e/global-setup.ts @@ -0,0 +1,11 @@ +import { execSync } from "node:child_process"; +import path from "node:path"; + +/** + * Bundle e2e runs `packages/deepsec/dist/cli.mjs`. Always rebuild before the + * e2e project so tests never execute a stale dist/ from an older checkout. + */ +export default function globalSetup(): void { + const root = path.resolve(import.meta.dirname, ".."); + execSync("pnpm bundle", { cwd: root, stdio: "inherit", env: process.env }); +} diff --git a/e2e/vitest.config.ts b/e2e/vitest.config.ts index af08b25..8164d51 100644 --- a/e2e/vitest.config.ts +++ b/e2e/vitest.config.ts @@ -3,6 +3,7 @@ import { defineConfig } from "vitest/config"; export default defineConfig({ test: { name: "e2e", + globalSetup: ["./global-setup.ts"], include: ["**/*.test.ts"], testTimeout: 30_000, // The live-sandbox test spawns the bundled CLI for ~5+ minutes diff --git a/knip.json b/knip.json index 990c602..66d385e 100644 --- a/knip.json +++ b/knip.json @@ -7,6 +7,7 @@ "e2e/bundle.test.ts", "e2e/pipeline.test.ts", "e2e/pipeline-sandbox.test.ts", + "e2e/global-setup.ts", "e2e/vitest.config.ts" ] }, diff --git a/packages/core/src/paths.ts b/packages/core/src/paths.ts index 64692d3..fd33ac1 100644 --- a/packages/core/src/paths.ts +++ b/packages/core/src/paths.ts @@ -4,6 +4,11 @@ export function getDataRoot(): string { return process.env.DEEPSEC_DATA_ROOT || "data"; } +/** Root segment for joining per-project paths; normalize `\` so posix.join is stable on Windows. */ +function dataRootPosix(): string { + return getDataRoot().replace(/\\/g, "/"); +} + // Reject empty, '.', '..', absolute paths, null bytes, and any path // separator. Used at every entry point that joins user-supplied segments // onto a per-project mirror so a `../`-laced projectId/runId can't escape @@ -53,55 +58,55 @@ export function assertSafeFilePath(filePath: string): void { export function dataDir(projectId: string): string { assertSafeSegment(projectId, "projectId"); - return path.join(getDataRoot(), projectId); + return path.posix.join(dataRootPosix(), projectId); } export function projectConfigPath(projectId: string): string { - return path.join(dataDir(projectId), "project.json"); + return path.posix.join(dataDir(projectId), "project.json"); } // --- File records (permanent per-file mirror) --- export function filesDir(projectId: string): string { - return path.join(dataDir(projectId), "files"); + return path.posix.join(dataDir(projectId), "files"); } export function fileRecordPath(projectId: string, filePath: string): string { assertSafeFilePath(filePath); - return path.join(filesDir(projectId), filePath + ".json"); + return path.posix.join(filesDir(projectId), filePath + ".json"); } // --- Runs (lightweight metadata) --- export function runsDir(projectId: string): string { - return path.join(dataDir(projectId), "runs"); + return path.posix.join(dataDir(projectId), "runs"); } export function runMetaPath(projectId: string, runId: string): string { assertSafeSegment(runId, "runId"); - return path.join(runsDir(projectId), runId + ".json"); + return path.posix.join(runsDir(projectId), runId + ".json"); } // --- Reports --- export function reportsDir(projectId: string): string { - return path.join(dataDir(projectId), "reports"); + return path.posix.join(dataDir(projectId), "reports"); } export function reportJsonPath(projectId: string, runId?: string): string { if (runId !== undefined) assertSafeSegment(runId, "runId"); const name = runId ? `report-${runId}.json` : "report.json"; - return path.join(reportsDir(projectId), name); + return path.posix.join(reportsDir(projectId), name); } export function reportMdPath(projectId: string, runId?: string): string { if (runId !== undefined) assertSafeSegment(runId, "runId"); const name = runId ? `report-${runId}.md` : "report.md"; - return path.join(reportsDir(projectId), name); + return path.posix.join(reportsDir(projectId), name); } export function reportCsvPath(projectId: string, runId?: string): string { if (runId !== undefined) assertSafeSegment(runId, "runId"); const name = runId ? `report-${runId}.csv` : "report.csv"; - return path.join(reportsDir(projectId), name); + return path.posix.join(reportsDir(projectId), name); } diff --git a/packages/deepsec/src/commands/init-project.ts b/packages/deepsec/src/commands/init-project.ts index 8a722b9..17e52c2 100644 --- a/packages/deepsec/src/commands/init-project.ts +++ b/packages/deepsec/src/commands/init-project.ts @@ -56,7 +56,9 @@ export function registerProject(opts: { const workspaceDir = fs.realpathSync(path.resolve(opts.workspaceDir)); const targetAbs = requireExistingDir(opts.targetRoot, ""); const id = validateProjectId(opts.id ?? path.basename(targetAbs)); - const targetRel = path.relative(workspaceDir, targetAbs); + // Always POSIX `root:` in deepsec.config.ts so scaffolds match across OS + // and tools that consume the file see a single separator convention. + const targetRel = path.relative(workspaceDir, targetAbs).split(path.sep).join("/"); const configPath = findConfigInWorkspace(workspaceDir); if (!configPath) {