config.test.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import fs from "node:fs/promises"
  2. import path from "node:path"
  3. import { expect } from "bun:test"
  4. import { Config } from "@opencode-ai/schema/config"
  5. import { Effect, Schema } from "effect"
  6. import { HttpServer } from "effect/unstable/http"
  7. import { tmpdir } from "../../core/test/fixture/tmpdir"
  8. import { it } from "../../core/test/lib/effect"
  9. import { ServerProcess } from "../src/process"
  10. it.live("returns ordered config entries for the requested directory", () =>
  11. Effect.acquireUseRelease(
  12. Effect.promise(() => tmpdir("opencode-config-endpoint-")),
  13. (tmp) =>
  14. Effect.gen(function* () {
  15. const global = path.join(tmp.path, "global")
  16. const project = path.join(tmp.path, "project")
  17. const config = path.join(project, "opencode.json")
  18. yield* Effect.promise(() => Promise.all([fs.mkdir(global, { recursive: true }), fs.mkdir(project, { recursive: true })]))
  19. yield* Effect.promise(() =>
  20. fs.writeFile(
  21. config,
  22. JSON.stringify({
  23. permissions: [
  24. { action: "shell", resource: "*", effect: "ask" },
  25. { action: "shell", resource: "git status", effect: "allow" },
  26. ],
  27. }),
  28. ),
  29. )
  30. const server = yield* ServerProcess.start<never, never>({
  31. hostname: "127.0.0.1",
  32. port: 0,
  33. password: "secret",
  34. app: { version: "test-version" },
  35. database: { path: ":memory:" },
  36. config: { directory: global },
  37. fs: { filewatcher: false },
  38. })
  39. const url = new URL("/api/config", HttpServer.formatAddress(server.address))
  40. url.searchParams.set("location[directory]", project)
  41. const response = yield* Effect.promise(() =>
  42. fetch(url, { headers: { authorization: `Basic ${btoa("opencode:secret")}` } }),
  43. )
  44. const entries = Schema.decodeUnknownSync(Schema.Array(Config.Entry))(
  45. yield* Effect.promise(() => response.json()),
  46. )
  47. expect(response.status).toBe(200)
  48. expect(Array.isArray(entries)).toBe(true)
  49. const document = entries.find(
  50. (entry): entry is Config.Document => entry.type === "document" && entry.path === config,
  51. )
  52. expect(document?.info.permissions).toEqual([
  53. { action: "shell", resource: "*", effect: "ask" },
  54. { action: "shell", resource: "git status", effect: "allow" },
  55. ])
  56. expect(entries.some((entry) => entry.type === "file" && entry.path === config)).toBe(true)
  57. }),
  58. (tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
  59. ),
  60. )