import * as NodeServices from "@effect/platform-node/NodeServices"; import { assert, it } from "@effect/vitest"; import * as Cause from "effect/Cause"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as Ref from "effect/Ref"; import * as PlatformError from "effect/PlatformError"; import * as ServerConfig from "../config.ts"; import * as ServerSecretStore from "./ServerSecretStore.ts"; const makeServerConfigLayer = () => ServerConfig.layerTest(process.cwd(), { prefix: "t3-secret-store-test-" }); const makeServerSecretStoreLayer = () => Layer.provide(ServerSecretStore.layer, makeServerConfigLayer()); const PermissionDeniedFileSystemLayer = Layer.effect( FileSystem.FileSystem, Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; return { ...fileSystem, readFile: (path) => Effect.fail( PlatformError.systemError({ _tag: "PermissionDenied", module: "FileSystem", method: "readFile", pathOrDescriptor: path, description: "Permission denied while reading secret file.", }), ), } satisfies FileSystem.FileSystem; }), ).pipe(Layer.provide(NodeServices.layer)); const makePermissionDeniedSecretStoreLayer = () => ServerSecretStore.layer.pipe( Layer.provide(makeServerConfigLayer()), Layer.provideMerge(PermissionDeniedFileSystemLayer), ); const RenameFailureFileSystemLayer = Layer.effect( FileSystem.FileSystem, Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; return { ...fileSystem, rename: (from, to) => Effect.fail( PlatformError.systemError({ _tag: "PermissionDenied", module: "FileSystem", method: "rename", pathOrDescriptor: `${String(from)} -> ${String(to)}`, description: "Permission denied while persisting secret file.", }), ), } satisfies FileSystem.FileSystem; }), ).pipe(Layer.provide(NodeServices.layer)); const makeRenameFailureSecretStoreLayer = () => ServerSecretStore.layer.pipe( Layer.provide(makeServerConfigLayer()), Layer.provideMerge(RenameFailureFileSystemLayer), ); const RemoveFailureFileSystemLayer = Layer.effect( FileSystem.FileSystem, Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; return { ...fileSystem, remove: (path, options) => Effect.fail( PlatformError.systemError({ _tag: "PermissionDenied", module: "FileSystem", method: "remove", pathOrDescriptor: String(path), description: `Permission denied while removing secret file.${options ? " options-set" : ""}`, }), ), } satisfies FileSystem.FileSystem; }), ).pipe(Layer.provide(NodeServices.layer)); const makeRemoveFailureSecretStoreLayer = () => ServerSecretStore.layer.pipe( Layer.provide(makeServerConfigLayer()), Layer.provideMerge(RemoveFailureFileSystemLayer), ); const ConcurrentReadMissFileSystemLayer = Layer.effect( FileSystem.FileSystem, Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const readCountRef = yield* Ref.make(0); const readBarrier = yield* Deferred.make(); return { ...fileSystem, readFile: (path) => String(path).endsWith("/session-signing-key.bin") ? Ref.updateAndGet(readCountRef, (count) => count + 1).pipe( Effect.flatMap((count) => { if (count > 2) { return fileSystem.readFile(path); } return Effect.gen(function* () { if (count === 2) { yield* Deferred.succeed(readBarrier, void 0); } yield* Deferred.await(readBarrier); return yield* Effect.failCause( Cause.fail( PlatformError.systemError({ _tag: "NotFound", module: "FileSystem", method: "readFile", pathOrDescriptor: String(path), description: "Secret file does not exist yet.", }), ), ); }); }), ) : fileSystem.readFile(path), } satisfies FileSystem.FileSystem; }), ).pipe(Layer.provide(NodeServices.layer)); const makeConcurrentCreateSecretStoreLayer = () => ServerSecretStore.layer.pipe( Layer.provide(makeServerConfigLayer()), Layer.provideMerge(ConcurrentReadMissFileSystemLayer), ); it.layer(NodeServices.layer)("ServerSecretStore.layer", (it) => { it.effect("returns Option.none when a secret file does not exist", () => Effect.gen(function* () { const secretStore = yield* ServerSecretStore.ServerSecretStore; const secret = yield* secretStore.get("missing-secret"); assert.isTrue(Option.isNone(secret)); }).pipe(Effect.provide(makeServerSecretStoreLayer())), ); it.effect("reuses an existing secret instead of regenerating it", () => Effect.gen(function* () { const secretStore = yield* ServerSecretStore.ServerSecretStore; const first = yield* secretStore.getOrCreateRandom("session-signing-key", 32); const second = yield* secretStore.getOrCreateRandom("session-signing-key", 32); assert.deepEqual(Array.from(second), Array.from(first)); }).pipe(Effect.provide(makeServerSecretStoreLayer())), ); it.effect("returns the persisted secret when concurrent creators race", () => Effect.gen(function* () { const secretStore = yield* ServerSecretStore.ServerSecretStore; const [first, second] = yield* Effect.all( [ secretStore.getOrCreateRandom("session-signing-key", 32), secretStore.getOrCreateRandom("session-signing-key", 32), ], { concurrency: "unbounded" }, ); const persisted = yield* secretStore.get("session-signing-key"); const persistedBytes = Option.getOrThrow(persisted); assert.deepEqual(Array.from(first), Array.from(persistedBytes)); assert.deepEqual(Array.from(second), Array.from(persistedBytes)); }).pipe(Effect.provide(makeConcurrentCreateSecretStoreLayer())), ); it.effect("uses restrictive permissions for the secret directory and files", () => Effect.gen(function* () { const chmodCalls: Array<{ readonly path: string; readonly mode: number }> = []; const recordingFileSystemLayer = Layer.effect( FileSystem.FileSystem, Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; return { ...fileSystem, makeDirectory: () => Effect.void, writeFile: () => Effect.void, rename: () => Effect.void, chmod: (path, mode) => Effect.sync(() => { chmodCalls.push({ path: String(path), mode }); }), } satisfies FileSystem.FileSystem; }), ).pipe(Layer.provide(NodeServices.layer)); const secretStore = yield* Effect.service(ServerSecretStore.ServerSecretStore).pipe( Effect.provide( ServerSecretStore.layer.pipe( Layer.provide(makeServerConfigLayer()), Layer.provideMerge(recordingFileSystemLayer), ), ), ); yield* secretStore.set("session-signing-key", Uint8Array.from([1, 2, 3])); assert.isTrue( chmodCalls.some((call) => call.mode === 0o700 && call.path.endsWith("/secrets")), ); assert.isAtLeast(chmodCalls.filter((call) => call.mode === 0o600).length, 2); }).pipe(Effect.provide(NodeServices.layer)), ); it.effect("propagates read failures other than missing-file errors", () => Effect.gen(function* () { const secretStore = yield* ServerSecretStore.ServerSecretStore; const error = yield* Effect.flip(secretStore.getOrCreateRandom("session-signing-key", 32)); assert.instanceOf(error, ServerSecretStore.SecretStoreReadError); assert.include(error.message, "Failed to read secret session-signing-key."); assert.instanceOf(error.cause, PlatformError.PlatformError); assert.equal((error.cause as PlatformError.PlatformError).reason._tag, "PermissionDenied"); }).pipe(Effect.provide(makePermissionDeniedSecretStoreLayer())), ); it.effect("propagates write failures instead of treating them as success", () => Effect.gen(function* () { const secretStore = yield* ServerSecretStore.ServerSecretStore; const error = yield* Effect.flip( secretStore.set("session-signing-key", Uint8Array.from([1, 2, 3])), ); assert.instanceOf(error, ServerSecretStore.SecretStorePersistError); assert.include(error.message, "Failed to persist secret session-signing-key."); assert.instanceOf(error.cause, PlatformError.PlatformError); assert.equal((error.cause as PlatformError.PlatformError).reason._tag, "PermissionDenied"); }).pipe(Effect.provide(makeRenameFailureSecretStoreLayer())), ); it.effect("propagates remove failures other than missing-file errors", () => Effect.gen(function* () { const secretStore = yield* ServerSecretStore.ServerSecretStore; const error = yield* Effect.flip(secretStore.remove("session-signing-key")); assert.instanceOf(error, ServerSecretStore.SecretStoreRemoveError); assert.include(error.message, "Failed to remove secret session-signing-key."); assert.instanceOf(error.cause, PlatformError.PlatformError); assert.equal((error.cause as PlatformError.PlatformError).reason._tag, "PermissionDenied"); }).pipe(Effect.provide(makeRemoveFailureSecretStoreLayer())), ); });