diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 375c28741c..d5881de0e5 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -120,7 +120,7 @@ function listenerLayer(opts: ListenOptions, port: number) { function startWithPortFallback(opts: ListenOptions) { if (opts.port !== 0) return startListener(opts, opts.port) - // Match the legacy adapter port-resolution behavior: explicit `0` prefers + // Match the legacy listener port-resolution behavior: explicit `0` prefers // 4096 first, then any free port. return startListener(opts, 4096).pipe(Effect.catch(() => startListener(opts, 0))) } diff --git a/packages/opencode/test/server/httpapi-cors.test.ts b/packages/opencode/test/server/httpapi-cors.test.ts index c084fbed5c..4e9680c7ce 100644 --- a/packages/opencode/test/server/httpapi-cors.test.ts +++ b/packages/opencode/test/server/httpapi-cors.test.ts @@ -103,6 +103,20 @@ describe("HttpApi CORS", () => { expect(response.status).toBe(204) expect(response.headers.get("access-control-allow-origin")).toBe("https://custom.example") expect(response.headers.get("access-control-allow-headers")).toBe("authorization") + + const rejected = yield* Effect.promise(() => + fetch(new URL(InstancePaths.path, listener.url), { + method: "OPTIONS", + headers: { + origin: "https://evil.example", + "access-control-request-method": "GET", + "access-control-request-headers": "authorization", + }, + }), + ) + + expect(rejected.status).toBe(204) + expect(rejected.headers.get("access-control-allow-origin")).not.toBe("https://evil.example") }), ) }) diff --git a/packages/opencode/test/server/httpapi-listen.test.ts b/packages/opencode/test/server/httpapi-listen.test.ts index fce942d6f2..065e883fff 100644 --- a/packages/opencode/test/server/httpapi-listen.test.ts +++ b/packages/opencode/test/server/httpapi-listen.test.ts @@ -284,6 +284,24 @@ describe("HttpApi Server.listen", () => { ).rejects.toThrow() }) + test("default in-process handler does not emit Effect HTTP response logs", async () => { + let output = "" + // oxlint-disable-next-line typescript-eslint/unbound-method -- restored in finally after temporarily capturing stderr. + const original = process.stderr.write + process.stderr.write = ((chunk) => { + output += String(chunk) + return true + }) as typeof process.stderr.write + try { + const response = await Server.Default().app.request("/status") + expect(response.status).toBe(200) + } finally { + process.stderr.write = original + } + + expect(output).not.toContain("Sent HTTP response") + }) + testPty("rejects unsafe PTY ticket mint and connect requests", async () => { await using tmp = await tmpdir({ git: true, config: { formatter: false, lsp: false } }) const listener = await startListener() diff --git a/packages/opencode/test/server/httpapi-ui.test.ts b/packages/opencode/test/server/httpapi-ui.test.ts index 851dde034d..17e7a0afcc 100644 --- a/packages/opencode/test/server/httpapi-ui.test.ts +++ b/packages/opencode/test/server/httpapi-ui.test.ts @@ -135,7 +135,7 @@ function responseText(response: Response) { } describe("HttpApi UI fallback", () => { - it.live("serves the web UI through the experimental backend", () => + it.live("serves the web UI through the HTTP API app", () => Effect.gen(function* () { Flag.OPENCODE_DISABLE_EMBEDDED_WEB_UI = true let proxiedUrl: string | undefined