Skip to content

Commit 13b3117

Browse files
fix(server): require auth for effect root routes (#26361)
Co-authored-by: Rajvardhan Patil <243567420+RajvardhanPatil07@users.noreply.github.com>
1 parent 83bb216 commit 13b3117

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

packages/opencode/src/server/routes/instance/httpapi/server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ const cors = (corsOptions?: CorsOptions) =>
9696
{ global: true },
9797
)
9898

99-
const rootApiRoutes = HttpApiBuilder.layer(RootHttpApi).pipe(Layer.provide([controlHandlers, globalHandlers]))
99+
const rootApiRoutes = HttpApiBuilder.layer(RootHttpApi).pipe(
100+
Layer.provide([controlHandlers, globalHandlers]),
101+
Layer.provide(authorizationRouterMiddleware.layer.pipe(Layer.provide(ServerAuth.Config.defaultLayer))),
102+
)
100103
const instanceRouterLayer = authorizationRouterMiddleware
101104
.combine(instanceRouterMiddleware)
102105
.combine(workspaceRouterMiddleware)

packages/opencode/test/server/httpapi-bridge.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,60 @@ describe("HttpApi server", () => {
358358
expect(good.status).toBe(200)
359359
})
360360

361+
test("requires credentials for root routes when auth is enabled", async () => {
362+
const server = app({ password: "secret" })
363+
const auth = { authorization: authorization("opencode", "secret") }
364+
const wrongAuth = { authorization: authorization("opencode", "wrong") }
365+
366+
const [missingConfig, wrongConfig, goodConfig] = await Promise.all([
367+
server.request(GlobalPaths.config),
368+
server.request(GlobalPaths.config, { headers: wrongAuth }),
369+
server.request(GlobalPaths.config, { headers: auth }),
370+
])
371+
372+
expect(missingConfig.status).toBe(401)
373+
expect(wrongConfig.status).toBe(401)
374+
expect(goodConfig.status).toBe(200)
375+
376+
const missingDispose = await server.request(GlobalPaths.dispose, { method: "POST" })
377+
expect(missingDispose.status).toBe(401)
378+
379+
const missingUpgrade = await server.request(GlobalPaths.upgrade, {
380+
method: "POST",
381+
headers: { "content-type": "application/json" },
382+
body: "not-json",
383+
})
384+
expect(missingUpgrade.status).toBe(401)
385+
386+
const invalidUpgrade = await server.request(GlobalPaths.upgrade, {
387+
method: "POST",
388+
headers: { ...auth, "content-type": "application/json" },
389+
body: "not-json",
390+
})
391+
expect(invalidUpgrade.status).toBe(400)
392+
393+
const missingLog = await server.request(ControlPaths.log, {
394+
method: "POST",
395+
headers: { "content-type": "application/json" },
396+
body: JSON.stringify({ service: "httpapi-auth-test", level: "info", message: "hello" }),
397+
})
398+
expect(missingLog.status).toBe(401)
399+
400+
const missingAuth = await server.request(ControlPaths.auth.replace(":providerID", "test"), {
401+
method: "PUT",
402+
headers: { "content-type": "application/json" },
403+
body: JSON.stringify({ type: "api", key: "secret" }),
404+
})
405+
expect(missingAuth.status).toBe(401)
406+
407+
const invalidAuth = await server.request(ControlPaths.auth.replace(":providerID", "test"), {
408+
method: "PUT",
409+
headers: { ...auth, "content-type": "application/json" },
410+
body: JSON.stringify({ type: "api" }),
411+
})
412+
expect(invalidAuth.status).toBe(400)
413+
})
414+
361415
test("accepts auth_token query credentials", async () => {
362416
await using tmp = await tmpdir({ git: true })
363417
await Bun.write(`${tmp.path}/hello.txt`, "hello")

0 commit comments

Comments
 (0)