Selaa lähdekoodia

fix(server): validate permission and question ids (#26456)

Kit Langton 3 kuukautta sitten
vanhempi
sitoutus
dc978cb889

+ 1 - 1
packages/opencode/src/permission/schema.ts

@@ -6,7 +6,7 @@ import { Newtype } from "@/util/schema"
 
 export class PermissionID extends Newtype<PermissionID>()(
   "PermissionID",
-  Schema.String.annotate({ [ZodOverride]: Identifier.schema("permission") }),
+  Schema.String.check(Schema.isStartsWith("per")).annotate({ [ZodOverride]: Identifier.schema("permission") }),
 ) {
   static ascending(id?: string): PermissionID {
     return this.make(Identifier.ascending("permission", id))

+ 1 - 1
packages/opencode/src/question/schema.ts

@@ -6,7 +6,7 @@ import { Newtype } from "@/util/schema"
 
 export class QuestionID extends Newtype<QuestionID>()(
   "QuestionID",
-  Schema.String.annotate({ [ZodOverride]: Identifier.schema("question") }),
+  Schema.String.check(Schema.isStartsWith("que")).annotate({ [ZodOverride]: Identifier.schema("question") }),
 ) {
   static ascending(id?: string): QuestionID {
     return this.make(Identifier.ascending("question", id))

+ 30 - 1
packages/opencode/test/server/httpapi-instance.test.ts

@@ -1,7 +1,7 @@
 import { NodeHttpServer, NodeServices } from "@effect/platform-node"
 import { Flag } from "@opencode-ai/core/flag/flag"
 import { describe, expect } from "bun:test"
-import { Config, Effect, FileSystem, Layer, Path } from "effect"
+import { Config, Context, Effect, FileSystem, Layer, Path } from "effect"
 import { HttpClient, HttpClientRequest, HttpRouter, HttpServer } from "effect/unstable/http"
 import * as Socket from "effect/unstable/socket/Socket"
 import { WorkspaceID } from "../../src/control-plane/schema"
@@ -53,6 +53,7 @@ const httpApiServerLayer = servedRoutes.pipe(
 )
 
 const it = testEffect(Layer.mergeAll(testStateLayer, httpApiServerLayer))
+const handlerContext = Context.empty() as Context.Context<unknown>
 
 const directoryHeader = (dir: string) => HttpClientRequest.setHeader("x-opencode-directory", dir)
 
@@ -121,6 +122,34 @@ describe("instance HttpApi", () => {
     }),
   )
 
+  it.live("rejects malformed permission and question request ids", () =>
+    Effect.gen(function* () {
+      const dir = yield* tmpdirScoped({ git: true })
+      const request = (path: string, init?: RequestInit) =>
+        Effect.promise(() =>
+          ExperimentalHttpApiServer.webHandler().handler(
+            new Request(`http://localhost${path}`, {
+              ...init,
+              headers: { "x-opencode-directory": dir, "content-type": "application/json", ...init?.headers },
+            }),
+            handlerContext,
+          ),
+        )
+      const [permission, questionReply, questionReject] = yield* Effect.all(
+        [
+          request("/permission/invalid-permission-id/reply", { method: "POST", body: JSON.stringify({ reply: "once" }) }),
+          request("/question/invalid-question-id/reply", { method: "POST", body: JSON.stringify({ answers: [["Yes"]] }) }),
+          request("/question/invalid-question-id/reject", { method: "POST" }),
+        ],
+        { concurrency: "unbounded" },
+      )
+
+      expect(permission.status).toBe(400)
+      expect(questionReply.status).toBe(400)
+      expect(questionReject.status).toBe(400)
+    }),
+  )
+
   it.live("serves path and VCS read endpoints", () =>
     Effect.gen(function* () {
       const dir = yield* tmpdirScoped({ git: true })