refactor(core): move v1 schemas into core (#30473)
This commit is contained in:
parent
0543fd29c8
commit
83452558f7
129 changed files with 1578 additions and 1227 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { PermissionLegacy } from "@opencode-ai/core/permission/legacy"
|
||||
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
|
||||
import { test, expect } from "bun:test"
|
||||
import os from "os"
|
||||
import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
|
||||
|
|
@ -261,8 +261,8 @@ test("merge - preserves rule order", () => {
|
|||
})
|
||||
|
||||
test("merge - config permission overrides default ask", () => {
|
||||
const defaults: PermissionLegacy.Ruleset = [{ permission: "*", pattern: "*", action: "ask" }]
|
||||
const config: PermissionLegacy.Ruleset = [{ permission: "bash", pattern: "*", action: "allow" }]
|
||||
const defaults: PermissionV1.Ruleset = [{ permission: "*", pattern: "*", action: "ask" }]
|
||||
const config: PermissionV1.Ruleset = [{ permission: "bash", pattern: "*", action: "allow" }]
|
||||
const merged = Permission.merge(defaults, config)
|
||||
|
||||
expect(Permission.evaluate("bash", "ls", merged).action).toBe("allow")
|
||||
|
|
@ -270,8 +270,8 @@ test("merge - config permission overrides default ask", () => {
|
|||
})
|
||||
|
||||
test("merge - config ask overrides default allow", () => {
|
||||
const defaults: PermissionLegacy.Ruleset = [{ permission: "bash", pattern: "*", action: "allow" }]
|
||||
const config: PermissionLegacy.Ruleset = [{ permission: "bash", pattern: "*", action: "ask" }]
|
||||
const defaults: PermissionV1.Ruleset = [{ permission: "bash", pattern: "*", action: "allow" }]
|
||||
const config: PermissionV1.Ruleset = [{ permission: "bash", pattern: "*", action: "ask" }]
|
||||
const merged = Permission.merge(defaults, config)
|
||||
|
||||
expect(Permission.evaluate("bash", "ls", merged).action).toBe("ask")
|
||||
|
|
@ -443,8 +443,8 @@ test("evaluate - later wildcard permission can override earlier specific permiss
|
|||
})
|
||||
|
||||
test("evaluate - merges multiple rulesets", () => {
|
||||
const config: PermissionLegacy.Ruleset = [{ permission: "bash", pattern: "*", action: "allow" }]
|
||||
const approved: PermissionLegacy.Ruleset = [{ permission: "bash", pattern: "rm", action: "deny" }]
|
||||
const config: PermissionV1.Ruleset = [{ permission: "bash", pattern: "*", action: "allow" }]
|
||||
const approved: PermissionV1.Ruleset = [{ permission: "bash", pattern: "rm", action: "deny" }]
|
||||
const result = Permission.evaluate("bash", "rm", config, approved)
|
||||
expect(result.action).toBe("deny")
|
||||
})
|
||||
|
|
@ -588,7 +588,7 @@ it.instance(
|
|||
ruleset: [{ permission: "bash", pattern: "*", action: "deny" }],
|
||||
}),
|
||||
)
|
||||
expect(err).toBeInstanceOf(PermissionLegacy.DeniedError)
|
||||
expect(err).toBeInstanceOf(PermissionV1.DeniedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
@ -655,10 +655,10 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2Bridge.Service
|
||||
const seen = yield* Deferred.make<PermissionLegacy.Request>()
|
||||
const seen = yield* Deferred.make<PermissionV1.Request>()
|
||||
const unsub = yield* events.listen((event) => {
|
||||
if (event.type === Permission.Event.Asked.type)
|
||||
Deferred.doneUnsafe(seen, Effect.succeed(event.data as PermissionLegacy.Request))
|
||||
Deferred.doneUnsafe(seen, Effect.succeed(event.data as PermissionV1.Request))
|
||||
return Effect.void
|
||||
})
|
||||
yield* Effect.addFinalizer(() => unsub)
|
||||
|
|
@ -703,7 +703,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test1"),
|
||||
id: PermissionV1.ID.make("per_test1"),
|
||||
sessionID: SessionID.make("session_test"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -713,7 +713,7 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
yield* waitForPending(1)
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test1"), reply: "once" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test1"), reply: "once" })
|
||||
yield* Fiber.join(fiber)
|
||||
}),
|
||||
{ git: true },
|
||||
|
|
@ -724,7 +724,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test2"),
|
||||
id: PermissionV1.ID.make("per_test2"),
|
||||
sessionID: SessionID.make("session_test"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -734,11 +734,11 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
yield* waitForPending(1)
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test2"), reply: "reject" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test2"), reply: "reject" })
|
||||
|
||||
const exit = yield* Fiber.await(fiber)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionLegacy.RejectedError)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionV1.RejectedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
@ -748,7 +748,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test2b"),
|
||||
id: PermissionV1.ID.make("per_test2b"),
|
||||
sessionID: SessionID.make("session_test"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -759,7 +759,7 @@ it.instance(
|
|||
|
||||
yield* waitForPending(1)
|
||||
yield* reply({
|
||||
requestID: PermissionLegacy.ID.make("per_test2b"),
|
||||
requestID: PermissionV1.ID.make("per_test2b"),
|
||||
reply: "reject",
|
||||
message: "Use a safer command",
|
||||
})
|
||||
|
|
@ -768,7 +768,7 @@ it.instance(
|
|||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) {
|
||||
const err = Cause.squash(exit.cause)
|
||||
expect(err).toBeInstanceOf(PermissionLegacy.CorrectedError)
|
||||
expect(err).toBeInstanceOf(PermissionV1.CorrectedError)
|
||||
expect(String(err)).toContain("Use a safer command")
|
||||
}
|
||||
}),
|
||||
|
|
@ -780,7 +780,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test3"),
|
||||
id: PermissionV1.ID.make("per_test3"),
|
||||
sessionID: SessionID.make("session_test"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -790,7 +790,7 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
yield* waitForPending(1)
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test3"), reply: "always" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test3"), reply: "always" })
|
||||
yield* Fiber.join(fiber)
|
||||
|
||||
const result = yield* ask({
|
||||
|
|
@ -811,7 +811,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const a = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test4a"),
|
||||
id: PermissionV1.ID.make("per_test4a"),
|
||||
sessionID: SessionID.make("session_same"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -821,7 +821,7 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
const b = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test4b"),
|
||||
id: PermissionV1.ID.make("per_test4b"),
|
||||
sessionID: SessionID.make("session_same"),
|
||||
permission: "edit",
|
||||
patterns: ["foo.ts"],
|
||||
|
|
@ -831,13 +831,13 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
yield* waitForPending(2)
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test4a"), reply: "reject" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test4a"), reply: "reject" })
|
||||
|
||||
const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)])
|
||||
expect(Exit.isFailure(ea)).toBe(true)
|
||||
expect(Exit.isFailure(eb)).toBe(true)
|
||||
if (Exit.isFailure(ea)) expect(Cause.squash(ea.cause)).toBeInstanceOf(PermissionLegacy.RejectedError)
|
||||
if (Exit.isFailure(eb)) expect(Cause.squash(eb.cause)).toBeInstanceOf(PermissionLegacy.RejectedError)
|
||||
if (Exit.isFailure(ea)) expect(Cause.squash(ea.cause)).toBeInstanceOf(PermissionV1.RejectedError)
|
||||
if (Exit.isFailure(eb)) expect(Cause.squash(eb.cause)).toBeInstanceOf(PermissionV1.RejectedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
@ -847,7 +847,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const a = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test5a"),
|
||||
id: PermissionV1.ID.make("per_test5a"),
|
||||
sessionID: SessionID.make("session_same"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -857,7 +857,7 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
const b = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test5b"),
|
||||
id: PermissionV1.ID.make("per_test5b"),
|
||||
sessionID: SessionID.make("session_same"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -867,7 +867,7 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
yield* waitForPending(2)
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test5a"), reply: "always" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test5a"), reply: "always" })
|
||||
|
||||
yield* Fiber.join(a)
|
||||
yield* Fiber.join(b)
|
||||
|
|
@ -881,7 +881,7 @@ it.instance(
|
|||
() =>
|
||||
Effect.gen(function* () {
|
||||
const a = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test6a"),
|
||||
id: PermissionV1.ID.make("per_test6a"),
|
||||
sessionID: SessionID.make("session_a"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -891,7 +891,7 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
const b = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test6b"),
|
||||
id: PermissionV1.ID.make("per_test6b"),
|
||||
sessionID: SessionID.make("session_b"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -901,10 +901,10 @@ it.instance(
|
|||
}).pipe(Effect.forkScoped)
|
||||
|
||||
yield* waitForPending(2)
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test6a"), reply: "always" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test6a"), reply: "always" })
|
||||
|
||||
yield* Fiber.join(a)
|
||||
expect((yield* list()).map((item) => item.id)).toEqual([PermissionLegacy.ID.make("per_test6b")])
|
||||
expect((yield* list()).map((item) => item.id)).toEqual([PermissionV1.ID.make("per_test6b")])
|
||||
|
||||
yield* rejectAll()
|
||||
yield* Fiber.await(b)
|
||||
|
|
@ -919,12 +919,12 @@ it.instance(
|
|||
const events = yield* EventV2Bridge.Service
|
||||
const seen = yield* Deferred.make<{
|
||||
sessionID: SessionID
|
||||
requestID: PermissionLegacy.ID
|
||||
reply: PermissionLegacy.Reply
|
||||
requestID: PermissionV1.ID
|
||||
reply: PermissionV1.Reply
|
||||
}>()
|
||||
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_test7"),
|
||||
id: PermissionV1.ID.make("per_test7"),
|
||||
sessionID: SessionID.make("session_test"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -940,14 +940,14 @@ it.instance(
|
|||
Deferred.doneUnsafe(
|
||||
seen,
|
||||
Effect.succeed(
|
||||
event.data as { sessionID: SessionID; requestID: PermissionLegacy.ID; reply: PermissionLegacy.Reply },
|
||||
event.data as { sessionID: SessionID; requestID: PermissionV1.ID; reply: PermissionV1.Reply },
|
||||
),
|
||||
)
|
||||
return Effect.void
|
||||
})
|
||||
yield* Effect.addFinalizer(() => unsub)
|
||||
|
||||
yield* reply({ requestID: PermissionLegacy.ID.make("per_test7"), reply: "once" })
|
||||
yield* reply({ requestID: PermissionV1.ID.make("per_test7"), reply: "once" })
|
||||
yield* Fiber.join(fiber)
|
||||
expect(
|
||||
yield* Deferred.await(seen).pipe(
|
||||
|
|
@ -958,7 +958,7 @@ it.instance(
|
|||
),
|
||||
).toEqual({
|
||||
sessionID: SessionID.make("session_test"),
|
||||
requestID: PermissionLegacy.ID.make("per_test7"),
|
||||
requestID: PermissionV1.ID.make("per_test7"),
|
||||
reply: "once",
|
||||
})
|
||||
}),
|
||||
|
|
@ -975,7 +975,7 @@ it.live("permission requests stay isolated by directory", () =>
|
|||
.provide(
|
||||
{ directory: one },
|
||||
ask({
|
||||
id: PermissionLegacy.ID.make("per_dir_a"),
|
||||
id: PermissionV1.ID.make("per_dir_a"),
|
||||
sessionID: SessionID.make("session_dir_a"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -990,7 +990,7 @@ it.live("permission requests stay isolated by directory", () =>
|
|||
.provide(
|
||||
{ directory: two },
|
||||
ask({
|
||||
id: PermissionLegacy.ID.make("per_dir_b"),
|
||||
id: PermissionV1.ID.make("per_dir_b"),
|
||||
sessionID: SessionID.make("session_dir_b"),
|
||||
permission: "bash",
|
||||
patterns: ["pwd"],
|
||||
|
|
@ -1006,8 +1006,8 @@ it.live("permission requests stay isolated by directory", () =>
|
|||
|
||||
expect(onePending).toHaveLength(1)
|
||||
expect(twoPending).toHaveLength(1)
|
||||
expect(onePending[0].id).toBe(PermissionLegacy.ID.make("per_dir_a"))
|
||||
expect(twoPending[0].id).toBe(PermissionLegacy.ID.make("per_dir_b"))
|
||||
expect(onePending[0].id).toBe(PermissionV1.ID.make("per_dir_a"))
|
||||
expect(twoPending[0].id).toBe(PermissionV1.ID.make("per_dir_b"))
|
||||
|
||||
yield* store.provide({ directory: one }, reply({ requestID: onePending[0].id, reply: "reject" }))
|
||||
yield* store.provide({ directory: two }, reply({ requestID: twoPending[0].id, reply: "reject" }))
|
||||
|
|
@ -1024,7 +1024,7 @@ it.instance(
|
|||
const test = yield* TestInstance
|
||||
const store = yield* InstanceStore.Service
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_dispose"),
|
||||
id: PermissionV1.ID.make("per_dispose"),
|
||||
sessionID: SessionID.make("session_dispose"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -1039,7 +1039,7 @@ it.instance(
|
|||
|
||||
const exit = yield* Fiber.await(fiber)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionLegacy.RejectedError)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionV1.RejectedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
@ -1051,7 +1051,7 @@ it.instance(
|
|||
const test = yield* TestInstance
|
||||
const store = yield* InstanceStore.Service
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_reload"),
|
||||
id: PermissionV1.ID.make("per_reload"),
|
||||
sessionID: SessionID.make("session_reload"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -1065,7 +1065,7 @@ it.instance(
|
|||
|
||||
const exit = yield* Fiber.await(fiber)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionLegacy.RejectedError)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionV1.RejectedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
@ -1074,7 +1074,7 @@ it.instance(
|
|||
"reply - fails for unknown requestID",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const exit = yield* reply({ requestID: PermissionLegacy.ID.make("per_unknown"), reply: "once" }).pipe(Effect.exit)
|
||||
const exit = yield* reply({ requestID: PermissionV1.ID.make("per_unknown"), reply: "once" }).pipe(Effect.exit)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) {
|
||||
expect(Cause.squash(exit.cause)).toMatchObject({ _tag: "Permission.NotFoundError", requestID: "per_unknown" })
|
||||
|
|
@ -1101,7 +1101,7 @@ it.instance(
|
|||
],
|
||||
}),
|
||||
)
|
||||
expect(err).toBeInstanceOf(PermissionLegacy.DeniedError)
|
||||
expect(err).toBeInstanceOf(PermissionV1.DeniedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
@ -1141,7 +1141,7 @@ it.instance(
|
|||
}),
|
||||
)
|
||||
|
||||
expect(err).toBeInstanceOf(PermissionLegacy.DeniedError)
|
||||
expect(err).toBeInstanceOf(PermissionV1.DeniedError)
|
||||
expect(yield* list()).toHaveLength(0)
|
||||
}),
|
||||
{ git: true },
|
||||
|
|
@ -1155,7 +1155,7 @@ it.instance(
|
|||
const store = yield* InstanceStore.Service
|
||||
|
||||
const fiber = yield* ask({
|
||||
id: PermissionLegacy.ID.make("per_reload"),
|
||||
id: PermissionV1.ID.make("per_reload"),
|
||||
sessionID: SessionID.make("session_reload"),
|
||||
permission: "bash",
|
||||
patterns: ["ls"],
|
||||
|
|
@ -1170,7 +1170,7 @@ it.instance(
|
|||
|
||||
const exit = yield* Fiber.await(fiber)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionLegacy.RejectedError)
|
||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(PermissionV1.RejectedError)
|
||||
}),
|
||||
{ git: true },
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue