mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-20 03:23:20 +00:00
refactor(server): clarify HttpApi route auth layers (#26372)
This commit is contained in:
@@ -20,13 +20,17 @@ import { SyncApi } from "./groups/sync"
|
||||
import { TuiApi } from "./groups/tui"
|
||||
import { WorkspaceApi } from "./groups/workspace"
|
||||
import { V2Api } from "./groups/v2"
|
||||
import { Authorization } from "./middleware/authorization"
|
||||
|
||||
// SSE event schemas built from the same BusEvent/SyncEvent registries that
|
||||
// the Hono spec uses, so both specs emit identical Event/SyncEvent components.
|
||||
const EventSchema = Schema.Union(BusEvent.effectPayloads()).annotate({ identifier: "Event" })
|
||||
const SyncEventSchemas = SyncEvent.effectPayloads()
|
||||
|
||||
export const RootHttpApi = HttpApi.make("opencode-root").addHttpApi(ControlApi).addHttpApi(GlobalApi)
|
||||
export const RootHttpApi = HttpApi.make("opencode-root")
|
||||
.addHttpApi(ControlApi)
|
||||
.addHttpApi(GlobalApi)
|
||||
.middleware(Authorization)
|
||||
|
||||
export const InstanceHttpApi = HttpApi.make("opencode-instance")
|
||||
.addHttpApi(ConfigApi)
|
||||
|
||||
@@ -96,9 +96,16 @@ const cors = (corsOptions?: CorsOptions) =>
|
||||
{ global: true },
|
||||
)
|
||||
|
||||
// Route tree:
|
||||
// - rootApiRoutes: typed /global/* and control routes; auth is declared by RootHttpApi.
|
||||
// - eventApiRoutes/rawInstanceRoutes: raw instance routes; auth and workspace routing happen as router middleware.
|
||||
// - instanceApiRoutes: schema routes; auth is declared on each group and workspace context is provided below.
|
||||
// - uiRoute: raw catch-all fallback; auth is router middleware so public static assets can bypass it.
|
||||
const authOnlyRouterLayer = authorizationRouterMiddleware.layer.pipe(Layer.provide(ServerAuth.Config.defaultLayer))
|
||||
const httpApiAuthLayer = authorizationLayer.pipe(Layer.provide(ServerAuth.Config.defaultLayer))
|
||||
const rootApiRoutes = HttpApiBuilder.layer(RootHttpApi).pipe(
|
||||
Layer.provide([controlHandlers, globalHandlers]),
|
||||
Layer.provide(authorizationRouterMiddleware.layer.pipe(Layer.provide(ServerAuth.Config.defaultLayer))),
|
||||
Layer.provide(httpApiAuthLayer),
|
||||
)
|
||||
const instanceRouterLayer = authorizationRouterMiddleware
|
||||
.combine(instanceRouterMiddleware)
|
||||
@@ -131,7 +138,7 @@ const instanceApiRoutes = HttpApiBuilder.layer(InstanceHttpApi).pipe(
|
||||
const rawInstanceRoutes = Layer.mergeAll(ptyConnectRoute).pipe(Layer.provide(instanceRouterLayer))
|
||||
const instanceRoutes = Layer.mergeAll(rawInstanceRoutes, instanceApiRoutes).pipe(
|
||||
Layer.provide([
|
||||
authorizationLayer.pipe(Layer.provide(ServerAuth.Config.defaultLayer)),
|
||||
httpApiAuthLayer,
|
||||
workspaceRoutingLayer.pipe(Layer.provide(Socket.layerWebSocketConstructorGlobal)),
|
||||
instanceContextLayer,
|
||||
]),
|
||||
@@ -143,7 +150,7 @@ const uiRoute = HttpRouter.use((router) =>
|
||||
const client = yield* HttpClient.HttpClient
|
||||
yield* router.add("*", "/*", (request) => serveUIEffect(request, { fs, client }))
|
||||
}),
|
||||
).pipe(Layer.provide(authorizationRouterMiddleware.layer.pipe(Layer.provide(ServerAuth.Config.defaultLayer))))
|
||||
).pipe(Layer.provide(authOnlyRouterLayer))
|
||||
|
||||
export function createRoutes(corsOptions?: CorsOptions) {
|
||||
return Layer.mergeAll(rootApiRoutes, eventApiRoutes, instanceRoutes, uiRoute).pipe(
|
||||
|
||||
@@ -363,12 +363,16 @@ describe("HttpApi server", () => {
|
||||
const auth = { authorization: authorization("opencode", "secret") }
|
||||
const wrongAuth = { authorization: authorization("opencode", "wrong") }
|
||||
|
||||
const [missingConfig, wrongConfig, goodConfig] = await Promise.all([
|
||||
const [missingHealth, goodHealth, missingConfig, wrongConfig, goodConfig] = await Promise.all([
|
||||
server.request(GlobalPaths.health),
|
||||
server.request(GlobalPaths.health, { headers: auth }),
|
||||
server.request(GlobalPaths.config),
|
||||
server.request(GlobalPaths.config, { headers: wrongAuth }),
|
||||
server.request(GlobalPaths.config, { headers: auth }),
|
||||
])
|
||||
|
||||
expect(missingHealth.status).toBe(401)
|
||||
expect(goodHealth.status).toBe(200)
|
||||
expect(missingConfig.status).toBe(401)
|
||||
expect(wrongConfig.status).toBe(401)
|
||||
expect(goodConfig.status).toBe(200)
|
||||
|
||||
Reference in New Issue
Block a user