From 8dfee385721d5a0d613803da430e7b2276fadec5 Mon Sep 17 00:00:00 2001 From: Furox <177975472+Furox-Art@users.noreply.github.com> Date: Sun, 11 Oct 2026 09:38:03 +0300 Subject: [PATCH] fix(server): a directory no longer resolves as the resource monitor binary (#16838) Co-authored-by: Yash Singh --- .../ResourceMonitorBinary.test.ts | 22 +++++++++++++++++++ .../ResourceMonitorBinary.ts | 11 +++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts index d53e1a091f47d6ef0fcad4734892ec9fbf338066..1f30be9477188dd0c91e4229d9ecee5eafe44bb7 100644 --- a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts +++ b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.test.ts @@ -115,6 +115,28 @@ describe("ResourceMonitorBinary", () => { }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), ); + it.effect("rejects a directory override", () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const baseDir = yield* fileSystem.makeTempDirectoryScoped({ + prefix: "t3-resource-monitor-binary-", + }); + + const service = yield* ResourceMonitorBinary.make().pipe( + Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), + Effect.provideService(HostProcess.Platform, "win32"), + Effect.provideService(HostProcess.Architecture, "arm64"), + Effect.provideService(HostProcess.Environment, { + T3CODE_RESOURCE_MONITOR_PATH: baseDir, + }), + ); + const error = yield* Effect.flip(service.resolve); + + assert.instanceOf(error, ResourceMonitorBinary.ResourceMonitorBinaryNotExecutable); + assert.equal(error.path, baseDir); + }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), + ); + it.effect("rejects unsupported platform and architecture pairs", () => Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; diff --git a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts index 035a9364a4978ff2ba2cd7c77516f688c68772de..c7f69f5668c2f5e363a69856eea7d0dd7c6dfb61 100644 --- a/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts +++ b/apps/server/src/resourceTelemetry/ResourceMonitorBinary.ts @@ -196,9 +196,14 @@ export const make = Effect.fn("resourceTelemetry.resourceMonitorBinary.make")(fu const exists = yield* fileSystem.exists(candidate).pipe(Effect.orElseSucceed(() => false)); if (!exists) continue; - if (platform !== "win32") { - const stat = yield* fileSystem.stat(candidate).pipe(Effect.option); - if (Option.isSome(stat) && (stat.value.mode & 0o111) === 0) { + const stat = yield* fileSystem.stat(candidate).pipe(Effect.option); + if (Option.isSome(stat)) { + // Directories are executable-looking on win32, where the exec-bit test + // below is skipped, and only fail later at spawn. + const unusable = + stat.value.type === "Directory" || + (platform !== "win32" && (stat.value.mode & 0o111) === 0); + if (unusable) { return yield* new ResourceMonitorBinaryNotExecutable({ path: candidate, mode: stat.value.mode, -- 2.54.0