policy.test.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Layer } from "effect"
  3. import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
  4. import { Location } from "@opencode-ai/core/location"
  5. import { Policy } from "@opencode-ai/core/policy"
  6. import { AbsolutePath } from "@opencode-ai/core/schema"
  7. import { location } from "./fixture/location"
  8. import { testEffect } from "./lib/effect"
  9. const it = testEffect(
  10. AppNodeBuilder.build(Policy.node, [
  11. [
  12. Location.node,
  13. Layer.succeed(Location.Service, Location.Service.of(location({ directory: AbsolutePath.make("test") }))),
  14. ],
  15. ]),
  16. )
  17. describe("Policy", () => {
  18. it.effect("returns the caller's fallback when no statement matches", () =>
  19. Effect.gen(function* () {
  20. const policy = yield* Policy.Service
  21. expect(yield* policy.evaluate("provider.use", "anthropic", "allow")).toBe("allow")
  22. expect(yield* policy.evaluate("provider.use", "anthropic", "deny")).toBe("deny")
  23. }),
  24. )
  25. it.effect("evaluates wildcard provider rules in written order", () =>
  26. Effect.gen(function* () {
  27. const policy = yield* Policy.Service
  28. yield* policy.load([
  29. new Policy.Info({
  30. effect: "deny",
  31. action: "provider.*",
  32. resource: "*",
  33. }),
  34. new Policy.Info({
  35. effect: "allow",
  36. action: "provider.use",
  37. resource: "anthropic",
  38. }),
  39. ])
  40. expect(yield* policy.evaluate("provider.use", "anthropic", "allow")).toBe("allow")
  41. expect(yield* policy.evaluate("provider.use", "openai", "allow")).toBe("deny")
  42. }),
  43. )
  44. it.effect("matches action and resource independently", () =>
  45. Effect.gen(function* () {
  46. const policy = yield* Policy.Service
  47. yield* policy.load([
  48. new Policy.Info({
  49. effect: "deny",
  50. action: "provider.*",
  51. resource: "company-*",
  52. }),
  53. ])
  54. expect(yield* policy.evaluate("provider.use", "company-stable", "allow")).toBe("deny")
  55. expect(yield* policy.evaluate("plugin.load", "company-stable", "allow")).toBe("allow")
  56. }),
  57. )
  58. it.effect("uses the last matching loaded statement", () =>
  59. Effect.gen(function* () {
  60. const policy = yield* Policy.Service
  61. yield* policy.load([
  62. new Policy.Info({
  63. effect: "allow",
  64. action: "provider.use",
  65. resource: "openai",
  66. }),
  67. new Policy.Info({
  68. effect: "deny",
  69. action: "provider.use",
  70. resource: "openai",
  71. }),
  72. ])
  73. expect(yield* policy.evaluate("provider.use", "openai", "allow")).toBe("deny")
  74. }),
  75. )
  76. })