Showing the changes to apps/server/src/workspace/WorkspaceFileSystem.test.ts (1 of 26 files). Show all
Unified · Split
| @@ -1,3 +1,6 @@ | ||
| 1 | +// @effect-diagnostics nodeBuiltinImport:off - FileSystem cannot create a FIFO. | |
| 2 | +import * as NodeChildProcess from "node:child_process"; | |
| 3 | + | |
| 1 | 4 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 2 | 5 | import { it, describe, expect } from "@effect/vitest"; |
| 3 | 6 | import * as Effect from "effect/Effect"; |
| @@ -73,6 +76,53 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 69 unmodified lines | ||
| 73 | 76 | }), |
| 74 | 77 | ); |
| 75 | 78 | |
| 79 | + it.effect("reads host files outside the workspace root by absolute path", () => | |
| 80 | + Effect.gen(function* () { | |
| 81 | + const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; | |
| 82 | + const path = yield* Path.Path; | |
| 83 | + const cwd = yield* makeTempDir; | |
| 84 | + const outsideDir = yield* makeTempDir; | |
| 85 | + yield* writeTextFile(outsideDir, "cleanup-report.md", "# Report\n"); | |
| 86 | + const absolutePath = path.join(outsideDir, "cleanup-report.md"); | |
| 87 | + | |
| 88 | + const result = yield* workspaceFileSystem.readFile({ | |
| 89 | + cwd, | |
| 90 | + relativePath: absolutePath, | |
| 91 | + }); | |
| 92 | + | |
| 93 | + expect(result).toEqual({ | |
| 94 | + relativePath: absolutePath, | |
| 95 | + contents: "# Report\n", | |
| 96 | + byteLength: 9, | |
| 97 | + truncated: false, | |
| 98 | + }); | |
| 99 | + }), | |
| 100 | + ); | |
| 101 | + | |
| 102 | + it.effect("rejects a FIFO without blocking on open", () => | |
| 103 | + Effect.gen(function* () { | |
| 104 | + const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; | |
| 105 | + const path = yield* Path.Path; | |
| 106 | + const cwd = yield* makeTempDir; | |
| 107 | + const outsideDir = yield* makeTempDir; | |
| 108 | + const fifoPath = path.join(outsideDir, "pipe"); | |
| 109 | + yield* Effect.promise( | |
| 110 | + () => | |
| 111 | + new Promise<void>((resolve, reject) => | |
| 112 | + NodeChildProcess.execFile("mkfifo", [fifoPath], (error) => | |
| 113 | + error ? reject(error) : resolve(), | |
| 114 | + ), | |
| 115 | + ), | |
| 116 | + ); | |
| 117 | + | |
| 118 | + const error = yield* workspaceFileSystem | |
| 119 | + .readFile({ cwd, relativePath: fifoPath }) | |
| 120 | + .pipe(Effect.flip); | |
| 121 | + | |
| 122 | + expect(error).toBeInstanceOf(WorkspaceFileSystem.WorkspacePathNotFileError); | |
| 123 | + }), | |
| 124 | + ); | |
| 125 | + | |
| 76 | 126 | it.effect("rejects reads outside the workspace root", () => |
| 77 | 127 | Effect.gen(function* () { |
| 78 | 128 | const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; |
| @@ -212,6 +262,22 @@ it.layer(TestLayer, { excludeTestServices: true })("WorkspaceFileSystemLive", (i · 133 unmodified lines | ||
| 212 | 262 | }), |
| 213 | 263 | ); |
| 214 | 264 | |
| 265 | + it.effect("rejects writes by absolute path", () => | |
| 266 | + Effect.gen(function* () { | |
| 267 | + const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; | |
| 268 | + const path = yield* Path.Path; | |
| 269 | + const cwd = yield* makeTempDir; | |
| 270 | + const outsideDir = yield* makeTempDir; | |
| 271 | + const absolutePath = path.join(outsideDir, "cleanup-report.md"); | |
| 272 | + | |
| 273 | + const error = yield* workspaceFileSystem | |
| 274 | + .writeFile({ cwd, relativePath: absolutePath, contents: "# Edited\n" }) | |
| 275 | + .pipe(Effect.flip); | |
| 276 | + | |
| 277 | + expect(error).toBeInstanceOf(WorkspacePaths.WorkspacePathOutsideRootError); | |
| 278 | + }), | |
| 279 | + ); | |
| 280 | + | |
| 215 | 281 | it.effect("invalidates workspace entry search cache after writes", () => |
| 216 | 282 | Effect.gen(function* () { |
| 217 | 283 | const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries; |