opencode/packages/core/test/network-guard.test.ts
2026-10-09 01:36:06 -07:00

73 lines
3.1 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { Effect, Layer } from "effect"
import { FetchHttpClient, HttpClient, HttpClientResponse } from "effect/http"
import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder"
import { LayerNodePlatform } from "@opencode/util/effect/app-node-platform"
import { it, refuseNetwork } from "./lib/effect"
describe("test harness network guard", () => {
test("refuses requests to hosts other than loopback", async () => {
const violations: string[] = []
const refused = refuseNetwork(violations)
await expect(refused("https://models.opencode.ai/api.json")).rejects.toThrow(
"test attempted network request: GET https://models.opencode.ai/api.json — provide an explicit HttpClient or disable the fetch",
)
await expect(refused(new Request("https://example.invalid/", { method: "POST" }))).rejects.toThrow(
"test attempted network request: POST https://example.invalid/",
)
expect(violations).toHaveLength(2)
})
it.live("the default http client node requests through the harness fetch", () =>
Effect.gen(function* () {
const seen: string[] = []
const response = yield* HttpClient.get("https://example.invalid/catalog").pipe(
Effect.flatMap((response) => response.text),
Effect.provide(AppNodeBuilder.build(LayerNodePlatform.httpClient)),
Effect.provideService(
FetchHttpClient.Fetch,
Object.assign(
(input: string | URL | Request) => {
seen.push(typeof input === "string" ? input : input instanceof URL ? input.href : input.url)
return Promise.resolve(new Response("from fetch"))
},
{ preconnect: fetch.preconnect },
),
),
)
expect(response).toBe("from fetch")
expect(seen).toEqual(["https://example.invalid/catalog"])
}),
)
it.live("an explicit HttpClient replacement is what the node sees", () =>
Effect.gen(function* () {
const mock = HttpClient.make((request) =>
Effect.succeed(HttpClientResponse.fromWeb(request, new Response("from mock"))),
)
const response = yield* HttpClient.get("https://example.invalid/catalog").pipe(
Effect.flatMap((response) => response.text),
Effect.provide(
AppNodeBuilder.build(LayerNodePlatform.httpClient, [
LayerNodePlatform.httpClient.replace(Layer.succeed(HttpClient.HttpClient, mock)),
]),
),
)
expect(response).toBe("from mock")
}),
)
it.live("loopback requests pass through to the real fetch", () =>
Effect.gen(function* () {
const server = yield* Effect.acquireRelease(
Effect.sync(() => Bun.serve({ hostname: "127.0.0.1", port: 0, fetch: () => new Response("local") })),
(server) => Effect.promise(() => server.stop(true)),
)
const response = yield* HttpClient.get(`http://127.0.0.1:${server.port}/`).pipe(
Effect.flatMap((response) => response.text),
Effect.provide(AppNodeBuilder.build(LayerNodePlatform.httpClient)),
)
expect(response).toBe("local")
}),
)
})