mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-16 01:19:19 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db75770226 |
@@ -1,31 +1,26 @@
|
|||||||
import { afterEach, test, expect } from "bun:test"
|
import { test, expect } from "bun:test"
|
||||||
import os from "os"
|
import os from "os"
|
||||||
import { Cause, Effect, Exit, Fiber, Layer } from "effect"
|
import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
|
||||||
import { Bus } from "../../src/bus"
|
import { Bus } from "../../src/bus"
|
||||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||||
import { Permission } from "../../src/permission"
|
import { Permission } from "../../src/permission"
|
||||||
import { PermissionID } from "../../src/permission/schema"
|
import { PermissionID } from "../../src/permission/schema"
|
||||||
import { Instance } from "../../src/project/instance"
|
import { InstanceBootstrap } from "../../src/project/bootstrap-service"
|
||||||
import { WithInstance } from "../../src/project/with-instance"
|
import { InstanceStore } from "../../src/project/instance-store"
|
||||||
import { InstanceRuntime } from "../../src/project/instance-runtime"
|
import { TestInstance, tmpdirScoped } from "../fixture/fixture"
|
||||||
import {
|
|
||||||
disposeAllInstances,
|
|
||||||
provideInstance,
|
|
||||||
provideTmpdirInstance,
|
|
||||||
reloadTestInstance,
|
|
||||||
tmpdirScoped,
|
|
||||||
} from "../fixture/fixture"
|
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
import { MessageID, SessionID } from "../../src/session/schema"
|
import { MessageID, SessionID } from "../../src/session/schema"
|
||||||
|
|
||||||
const bus = Bus.layer
|
const bus = Bus.layer
|
||||||
const env = Layer.mergeAll(Permission.layer.pipe(Layer.provide(bus)), bus, CrossSpawnSpawner.defaultLayer)
|
const noopBootstrap = Layer.succeed(InstanceBootstrap.Service, InstanceBootstrap.Service.of({ run: Effect.void }))
|
||||||
|
const env = Layer.mergeAll(
|
||||||
|
Permission.layer.pipe(Layer.provide(bus)),
|
||||||
|
bus,
|
||||||
|
CrossSpawnSpawner.defaultLayer,
|
||||||
|
InstanceStore.defaultLayer.pipe(Layer.provide(noopBootstrap)),
|
||||||
|
)
|
||||||
const it = testEffect(env)
|
const it = testEffect(env)
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await disposeAllInstances()
|
|
||||||
})
|
|
||||||
|
|
||||||
const rejectAll = (message?: string) =>
|
const rejectAll = (message?: string) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const permission = yield* Permission.Service
|
const permission = yield* Permission.Service
|
||||||
@@ -41,12 +36,39 @@ const rejectAll = (message?: string) =>
|
|||||||
const waitForPending = (count: number) =>
|
const waitForPending = (count: number) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const permission = yield* Permission.Service
|
const permission = yield* Permission.Service
|
||||||
for (let i = 0; i < 100; i++) {
|
const bus = yield* Bus.Service
|
||||||
|
const waitForChange = Effect.acquireRelease(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const changed = yield* Deferred.make<void>()
|
||||||
|
const asked = yield* bus.subscribeCallback(Permission.Event.Asked, () =>
|
||||||
|
Deferred.doneUnsafe(changed, Effect.void),
|
||||||
|
)
|
||||||
|
const replied = yield* bus.subscribeCallback(Permission.Event.Replied, () =>
|
||||||
|
Deferred.doneUnsafe(changed, Effect.void),
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
changed,
|
||||||
|
unsubscribe: () => {
|
||||||
|
asked()
|
||||||
|
replied()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
({ unsubscribe }) => Effect.sync(unsubscribe),
|
||||||
|
).pipe(Effect.flatMap(({ changed }) => Deferred.await(changed)))
|
||||||
|
|
||||||
|
return yield* Effect.gen(function* () {
|
||||||
|
while (true) {
|
||||||
const list = yield* permission.list()
|
const list = yield* permission.list()
|
||||||
if (list.length === count) return list
|
if (list.length === count) return list
|
||||||
yield* Effect.sleep("10 millis")
|
yield* waitForChange
|
||||||
}
|
}
|
||||||
return yield* Effect.fail(new Error(`timed out waiting for ${count} pending permission request(s)`))
|
}).pipe(
|
||||||
|
Effect.timeoutOrElse({
|
||||||
|
duration: "1 second",
|
||||||
|
orElse: () => Effect.fail(new Error(`timed out waiting for ${count} pending permission request(s)`)),
|
||||||
|
}),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const fail = <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
const fail = <A, E, R>(self: Effect.Effect<A, E, R>) =>
|
||||||
@@ -74,14 +96,6 @@ const list = () =>
|
|||||||
return yield* permission.list()
|
return yield* permission.list()
|
||||||
})
|
})
|
||||||
|
|
||||||
function withDir(options: { git?: boolean } | undefined, self: (dir: string) => Effect.Effect<any, any, any>) {
|
|
||||||
return provideTmpdirInstance(self, options)
|
|
||||||
}
|
|
||||||
|
|
||||||
function withProvided(dir: string) {
|
|
||||||
return <A, E, R>(self: Effect.Effect<A, E, R>) => self.pipe(provideInstance(dir))
|
|
||||||
}
|
|
||||||
|
|
||||||
// fromConfig tests
|
// fromConfig tests
|
||||||
|
|
||||||
test("fromConfig - string value becomes wildcard rule", () => {
|
test("fromConfig - string value becomes wildcard rule", () => {
|
||||||
@@ -563,8 +577,7 @@ test("disabled - specific allow overrides wildcard deny", () => {
|
|||||||
|
|
||||||
// ask tests
|
// ask tests
|
||||||
|
|
||||||
it.live("ask - resolves immediately when action is allow", () =>
|
it.instance("ask - resolves immediately when action is allow", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const result = yield* ask({
|
const result = yield* ask({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
@@ -576,11 +589,10 @@ it.live("ask - resolves immediately when action is allow", () =>
|
|||||||
})
|
})
|
||||||
expect(result).toBeUndefined()
|
expect(result).toBeUndefined()
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - throws DeniedError when action is deny", () =>
|
it.instance("ask - throws DeniedError when action is deny", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const err = yield* fail(
|
const err = yield* fail(
|
||||||
ask({
|
ask({
|
||||||
@@ -594,11 +606,10 @@ it.live("ask - throws DeniedError when action is deny", () =>
|
|||||||
)
|
)
|
||||||
expect(err).toBeInstanceOf(Permission.DeniedError)
|
expect(err).toBeInstanceOf(Permission.DeniedError)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - stays pending when action is ask", () =>
|
it.instance("ask - stays pending when action is ask", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
@@ -613,11 +624,10 @@ it.live("ask - stays pending when action is ask", () =>
|
|||||||
yield* rejectAll()
|
yield* rejectAll()
|
||||||
yield* Fiber.await(fiber)
|
yield* Fiber.await(fiber)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - adds request to pending list", () =>
|
it.instance("ask - adds request to pending list", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
@@ -649,19 +659,18 @@ it.live("ask - adds request to pending list", () =>
|
|||||||
yield* rejectAll()
|
yield* rejectAll()
|
||||||
yield* Fiber.await(fiber)
|
yield* Fiber.await(fiber)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - publishes asked event", () =>
|
it.instance("ask - publishes asked event", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const bus = yield* Bus.Service
|
const bus = yield* Bus.Service
|
||||||
let seen: Permission.Request | undefined
|
const seen = yield* Deferred.make<Permission.Request>()
|
||||||
const unsub = yield* bus.subscribeCallback(Permission.Event.Asked, (event) => {
|
const unsub = yield* bus.subscribeCallback(Permission.Event.Asked, (event) => {
|
||||||
seen = event.properties
|
Deferred.doneUnsafe(seen, Effect.succeed(event.properties))
|
||||||
})
|
})
|
||||||
|
yield* Effect.addFinalizer(() => Effect.sync(unsub))
|
||||||
|
|
||||||
try {
|
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
permission: "bash",
|
permission: "bash",
|
||||||
@@ -676,8 +685,14 @@ it.live("ask - publishes asked event", () =>
|
|||||||
}).pipe(Effect.forkScoped)
|
}).pipe(Effect.forkScoped)
|
||||||
|
|
||||||
expect(yield* waitForPending(1)).toHaveLength(1)
|
expect(yield* waitForPending(1)).toHaveLength(1)
|
||||||
expect(seen).toBeDefined()
|
expect(
|
||||||
expect(seen).toMatchObject({
|
yield* Deferred.await(seen).pipe(
|
||||||
|
Effect.timeoutOrElse({
|
||||||
|
duration: "1 second",
|
||||||
|
orElse: () => Effect.fail(new Error("timed out waiting for permission asked event")),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toMatchObject({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
permission: "bash",
|
permission: "bash",
|
||||||
patterns: ["ls"],
|
patterns: ["ls"],
|
||||||
@@ -685,17 +700,13 @@ it.live("ask - publishes asked event", () =>
|
|||||||
|
|
||||||
yield* rejectAll()
|
yield* rejectAll()
|
||||||
yield* Fiber.await(fiber)
|
yield* Fiber.await(fiber)
|
||||||
} finally {
|
|
||||||
unsub()
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
// reply tests
|
// reply tests
|
||||||
|
|
||||||
it.live("reply - once resolves the pending ask", () =>
|
it.instance("reply - once resolves the pending ask", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_test1"),
|
id: PermissionID.make("per_test1"),
|
||||||
@@ -711,11 +722,10 @@ it.live("reply - once resolves the pending ask", () =>
|
|||||||
yield* reply({ requestID: PermissionID.make("per_test1"), reply: "once" })
|
yield* reply({ requestID: PermissionID.make("per_test1"), reply: "once" })
|
||||||
yield* Fiber.join(fiber)
|
yield* Fiber.join(fiber)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - reject throws RejectedError", () =>
|
it.instance("reply - reject throws RejectedError", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_test2"),
|
id: PermissionID.make("per_test2"),
|
||||||
@@ -734,11 +744,10 @@ it.live("reply - reject throws RejectedError", () =>
|
|||||||
expect(Exit.isFailure(exit)).toBe(true)
|
expect(Exit.isFailure(exit)).toBe(true)
|
||||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - reject with message throws CorrectedError", () =>
|
it.instance("reply - reject with message throws CorrectedError", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_test2b"),
|
id: PermissionID.make("per_test2b"),
|
||||||
@@ -765,13 +774,11 @@ it.live("reply - reject with message throws CorrectedError", () =>
|
|||||||
expect(String(err)).toContain("Use a safer command")
|
expect(String(err)).toContain("Use a safer command")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - always persists approval and resolves", () =>
|
it.instance("reply - always persists approval and resolves", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dir = yield* tmpdirScoped({ git: true })
|
|
||||||
const run = withProvided(dir)
|
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_test3"),
|
id: PermissionID.make("per_test3"),
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
@@ -780,10 +787,10 @@ it.live("reply - always persists approval and resolves", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: ["ls"],
|
always: ["ls"],
|
||||||
ruleset: [],
|
ruleset: [],
|
||||||
}).pipe(run, Effect.forkScoped)
|
}).pipe(Effect.forkScoped)
|
||||||
|
|
||||||
yield* waitForPending(1).pipe(run)
|
yield* waitForPending(1)
|
||||||
yield* reply({ requestID: PermissionID.make("per_test3"), reply: "always" }).pipe(run)
|
yield* reply({ requestID: PermissionID.make("per_test3"), reply: "always" })
|
||||||
yield* Fiber.join(fiber)
|
yield* Fiber.join(fiber)
|
||||||
|
|
||||||
const result = yield* ask({
|
const result = yield* ask({
|
||||||
@@ -793,13 +800,13 @@ it.live("reply - always persists approval and resolves", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: [],
|
always: [],
|
||||||
ruleset: [],
|
ruleset: [],
|
||||||
}).pipe(run)
|
})
|
||||||
expect(result).toBeUndefined()
|
expect(result).toBeUndefined()
|
||||||
}),
|
}),
|
||||||
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - reject cancels all pending for same session", () =>
|
it.instance("reply - reject cancels all pending for same session", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const a = yield* ask({
|
const a = yield* ask({
|
||||||
id: PermissionID.make("per_test4a"),
|
id: PermissionID.make("per_test4a"),
|
||||||
@@ -830,11 +837,10 @@ it.live("reply - reject cancels all pending for same session", () =>
|
|||||||
if (Exit.isFailure(ea)) expect(Cause.squash(ea.cause)).toBeInstanceOf(Permission.RejectedError)
|
if (Exit.isFailure(ea)) expect(Cause.squash(ea.cause)).toBeInstanceOf(Permission.RejectedError)
|
||||||
if (Exit.isFailure(eb)) expect(Cause.squash(eb.cause)).toBeInstanceOf(Permission.RejectedError)
|
if (Exit.isFailure(eb)) expect(Cause.squash(eb.cause)).toBeInstanceOf(Permission.RejectedError)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - always resolves matching pending requests in same session", () =>
|
it.instance("reply - always resolves matching pending requests in same session", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const a = yield* ask({
|
const a = yield* ask({
|
||||||
id: PermissionID.make("per_test5a"),
|
id: PermissionID.make("per_test5a"),
|
||||||
@@ -863,11 +869,10 @@ it.live("reply - always resolves matching pending requests in same session", ()
|
|||||||
yield* Fiber.join(b)
|
yield* Fiber.join(b)
|
||||||
expect(yield* list()).toHaveLength(0)
|
expect(yield* list()).toHaveLength(0)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - always keeps other session pending", () =>
|
it.instance("reply - always keeps other session pending", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const a = yield* ask({
|
const a = yield* ask({
|
||||||
id: PermissionID.make("per_test6a"),
|
id: PermissionID.make("per_test6a"),
|
||||||
@@ -898,24 +903,13 @@ it.live("reply - always keeps other session pending", () =>
|
|||||||
yield* rejectAll()
|
yield* rejectAll()
|
||||||
yield* Fiber.await(b)
|
yield* Fiber.await(b)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - publishes replied event", () =>
|
it.instance("reply - publishes replied event", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const bus = yield* Bus.Service
|
const bus = yield* Bus.Service
|
||||||
let resolve!: (value: { sessionID: SessionID; requestID: PermissionID; reply: Permission.Reply }) => void
|
const seen = yield* Deferred.make<{ sessionID: SessionID; requestID: PermissionID; reply: Permission.Reply }>()
|
||||||
const seen = Effect.promise<{
|
|
||||||
sessionID: SessionID
|
|
||||||
requestID: PermissionID
|
|
||||||
reply: Permission.Reply
|
|
||||||
}>(
|
|
||||||
() =>
|
|
||||||
new Promise((res) => {
|
|
||||||
resolve = res
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_test7"),
|
id: PermissionID.make("per_test7"),
|
||||||
@@ -930,32 +924,38 @@ it.live("reply - publishes replied event", () =>
|
|||||||
yield* waitForPending(1)
|
yield* waitForPending(1)
|
||||||
|
|
||||||
const unsub = yield* bus.subscribeCallback(Permission.Event.Replied, (event) => {
|
const unsub = yield* bus.subscribeCallback(Permission.Event.Replied, (event) => {
|
||||||
resolve(event.properties)
|
Deferred.doneUnsafe(seen, Effect.succeed(event.properties))
|
||||||
})
|
})
|
||||||
|
yield* Effect.addFinalizer(() => Effect.sync(unsub))
|
||||||
|
|
||||||
try {
|
|
||||||
yield* reply({ requestID: PermissionID.make("per_test7"), reply: "once" })
|
yield* reply({ requestID: PermissionID.make("per_test7"), reply: "once" })
|
||||||
yield* Fiber.join(fiber)
|
yield* Fiber.join(fiber)
|
||||||
expect(yield* seen).toEqual({
|
expect(
|
||||||
|
yield* Deferred.await(seen).pipe(
|
||||||
|
Effect.timeoutOrElse({
|
||||||
|
duration: "1 second",
|
||||||
|
orElse: () => Effect.fail(new Error("timed out waiting for permission replied event")),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
requestID: PermissionID.make("per_test7"),
|
requestID: PermissionID.make("per_test7"),
|
||||||
reply: "once",
|
reply: "once",
|
||||||
})
|
})
|
||||||
} finally {
|
|
||||||
unsub()
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("permission requests stay isolated by directory", () =>
|
it.live("permission requests stay isolated by directory", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const one = yield* tmpdirScoped({ git: true })
|
const one = yield* tmpdirScoped({ git: true })
|
||||||
const two = yield* tmpdirScoped({ git: true })
|
const two = yield* tmpdirScoped({ git: true })
|
||||||
const runOne = withProvided(one)
|
const store = yield* InstanceStore.Service
|
||||||
const runTwo = withProvided(two)
|
|
||||||
|
|
||||||
const a = yield* ask({
|
const a = yield* store
|
||||||
|
.provide(
|
||||||
|
{ directory: one },
|
||||||
|
ask({
|
||||||
id: PermissionID.make("per_dir_a"),
|
id: PermissionID.make("per_dir_a"),
|
||||||
sessionID: SessionID.make("session_dir_a"),
|
sessionID: SessionID.make("session_dir_a"),
|
||||||
permission: "bash",
|
permission: "bash",
|
||||||
@@ -963,9 +963,14 @@ it.live("permission requests stay isolated by directory", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: [],
|
always: [],
|
||||||
ruleset: [],
|
ruleset: [],
|
||||||
}).pipe(runOne, Effect.forkScoped)
|
}),
|
||||||
|
)
|
||||||
|
.pipe(Effect.forkScoped)
|
||||||
|
|
||||||
const b = yield* ask({
|
const b = yield* store
|
||||||
|
.provide(
|
||||||
|
{ directory: two },
|
||||||
|
ask({
|
||||||
id: PermissionID.make("per_dir_b"),
|
id: PermissionID.make("per_dir_b"),
|
||||||
sessionID: SessionID.make("session_dir_b"),
|
sessionID: SessionID.make("session_dir_b"),
|
||||||
permission: "bash",
|
permission: "bash",
|
||||||
@@ -973,28 +978,30 @@ it.live("permission requests stay isolated by directory", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: [],
|
always: [],
|
||||||
ruleset: [],
|
ruleset: [],
|
||||||
}).pipe(runTwo, Effect.forkScoped)
|
}),
|
||||||
|
)
|
||||||
|
.pipe(Effect.forkScoped)
|
||||||
|
|
||||||
const onePending = yield* waitForPending(1).pipe(runOne)
|
const onePending = yield* store.provide({ directory: one }, waitForPending(1))
|
||||||
const twoPending = yield* waitForPending(1).pipe(runTwo)
|
const twoPending = yield* store.provide({ directory: two }, waitForPending(1))
|
||||||
|
|
||||||
expect(onePending).toHaveLength(1)
|
expect(onePending).toHaveLength(1)
|
||||||
expect(twoPending).toHaveLength(1)
|
expect(twoPending).toHaveLength(1)
|
||||||
expect(onePending[0].id).toBe(PermissionID.make("per_dir_a"))
|
expect(onePending[0].id).toBe(PermissionID.make("per_dir_a"))
|
||||||
expect(twoPending[0].id).toBe(PermissionID.make("per_dir_b"))
|
expect(twoPending[0].id).toBe(PermissionID.make("per_dir_b"))
|
||||||
|
|
||||||
yield* reply({ requestID: onePending[0].id, reply: "reject" }).pipe(runOne)
|
yield* store.provide({ directory: one }, reply({ requestID: onePending[0].id, reply: "reject" }))
|
||||||
yield* reply({ requestID: twoPending[0].id, reply: "reject" }).pipe(runTwo)
|
yield* store.provide({ directory: two }, reply({ requestID: twoPending[0].id, reply: "reject" }))
|
||||||
|
|
||||||
yield* Fiber.await(a)
|
yield* Fiber.await(a)
|
||||||
yield* Fiber.await(b)
|
yield* Fiber.await(b)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("pending permission rejects on instance dispose", () =>
|
it.instance("pending permission rejects on instance dispose", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dir = yield* tmpdirScoped({ git: true })
|
const test = yield* TestInstance
|
||||||
const run = withProvided(dir)
|
const store = yield* InstanceStore.Service
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_dispose"),
|
id: PermissionID.make("per_dispose"),
|
||||||
sessionID: SessionID.make("session_dispose"),
|
sessionID: SessionID.make("session_dispose"),
|
||||||
@@ -1003,23 +1010,23 @@ it.live("pending permission rejects on instance dispose", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: [],
|
always: [],
|
||||||
ruleset: [],
|
ruleset: [],
|
||||||
}).pipe(run, Effect.forkScoped)
|
}).pipe(Effect.forkScoped)
|
||||||
|
|
||||||
expect(yield* waitForPending(1).pipe(run)).toHaveLength(1)
|
expect(yield* waitForPending(1)).toHaveLength(1)
|
||||||
yield* Effect.promise(() =>
|
const ctx = yield* store.load({ directory: test.directory })
|
||||||
WithInstance.provide({ directory: dir, fn: () => void InstanceRuntime.disposeInstance(Instance.current) }),
|
yield* store.dispose(ctx)
|
||||||
)
|
|
||||||
|
|
||||||
const exit = yield* Fiber.await(fiber)
|
const exit = yield* Fiber.await(fiber)
|
||||||
expect(Exit.isFailure(exit)).toBe(true)
|
expect(Exit.isFailure(exit)).toBe(true)
|
||||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
||||||
}),
|
}),
|
||||||
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("pending permission rejects on instance reload", () =>
|
it.instance("pending permission rejects on instance reload", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dir = yield* tmpdirScoped({ git: true })
|
const test = yield* TestInstance
|
||||||
const run = withProvided(dir)
|
const store = yield* InstanceStore.Service
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_reload"),
|
id: PermissionID.make("per_reload"),
|
||||||
sessionID: SessionID.make("session_reload"),
|
sessionID: SessionID.make("session_reload"),
|
||||||
@@ -1028,28 +1035,27 @@ it.live("pending permission rejects on instance reload", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: [],
|
always: [],
|
||||||
ruleset: [],
|
ruleset: [],
|
||||||
}).pipe(run, Effect.forkScoped)
|
}).pipe(Effect.forkScoped)
|
||||||
|
|
||||||
expect(yield* waitForPending(1).pipe(run)).toHaveLength(1)
|
expect(yield* waitForPending(1)).toHaveLength(1)
|
||||||
yield* Effect.promise(() => reloadTestInstance({ directory: dir }))
|
yield* store.reload({ directory: test.directory })
|
||||||
|
|
||||||
const exit = yield* Fiber.await(fiber)
|
const exit = yield* Fiber.await(fiber)
|
||||||
expect(Exit.isFailure(exit)).toBe(true)
|
expect(Exit.isFailure(exit)).toBe(true)
|
||||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
||||||
}),
|
}),
|
||||||
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("reply - does nothing for unknown requestID", () =>
|
it.instance("reply - does nothing for unknown requestID", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* reply({ requestID: PermissionID.make("per_unknown"), reply: "once" })
|
yield* reply({ requestID: PermissionID.make("per_unknown"), reply: "once" })
|
||||||
expect(yield* list()).toHaveLength(0)
|
expect(yield* list()).toHaveLength(0)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - checks all patterns and stops on first deny", () =>
|
it.instance("ask - checks all patterns and stops on first deny", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const err = yield* fail(
|
const err = yield* fail(
|
||||||
ask({
|
ask({
|
||||||
@@ -1066,11 +1072,10 @@ it.live("ask - checks all patterns and stops on first deny", () =>
|
|||||||
)
|
)
|
||||||
expect(err).toBeInstanceOf(Permission.DeniedError)
|
expect(err).toBeInstanceOf(Permission.DeniedError)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - allows all patterns when all match allow rules", () =>
|
it.instance("ask - allows all patterns when all match allow rules", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const result = yield* ask({
|
const result = yield* ask({
|
||||||
sessionID: SessionID.make("session_test"),
|
sessionID: SessionID.make("session_test"),
|
||||||
@@ -1082,11 +1087,10 @@ it.live("ask - allows all patterns when all match allow rules", () =>
|
|||||||
})
|
})
|
||||||
expect(result).toBeUndefined()
|
expect(result).toBeUndefined()
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - should deny even when an earlier pattern is ask", () =>
|
it.instance("ask - should deny even when an earlier pattern is ask", () =>
|
||||||
withDir({ git: true }, () =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const err = yield* fail(
|
const err = yield* fail(
|
||||||
ask({
|
ask({
|
||||||
@@ -1105,13 +1109,13 @@ it.live("ask - should deny even when an earlier pattern is ask", () =>
|
|||||||
expect(err).toBeInstanceOf(Permission.DeniedError)
|
expect(err).toBeInstanceOf(Permission.DeniedError)
|
||||||
expect(yield* list()).toHaveLength(0)
|
expect(yield* list()).toHaveLength(0)
|
||||||
}),
|
}),
|
||||||
),
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ask - abort should clear pending request", () =>
|
it.instance("ask - abort should clear pending request", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const dir = yield* tmpdirScoped({ git: true })
|
const test = yield* TestInstance
|
||||||
const run = withProvided(dir)
|
const store = yield* InstanceStore.Service
|
||||||
|
|
||||||
const fiber = yield* ask({
|
const fiber = yield* ask({
|
||||||
id: PermissionID.make("per_reload"),
|
id: PermissionID.make("per_reload"),
|
||||||
@@ -1121,14 +1125,15 @@ it.live("ask - abort should clear pending request", () =>
|
|||||||
metadata: {},
|
metadata: {},
|
||||||
always: [],
|
always: [],
|
||||||
ruleset: [{ permission: "bash", pattern: "*", action: "ask" }],
|
ruleset: [{ permission: "bash", pattern: "*", action: "ask" }],
|
||||||
}).pipe(run, Effect.forkScoped)
|
}).pipe(Effect.forkScoped)
|
||||||
|
|
||||||
const pending = yield* waitForPending(1).pipe(run)
|
const pending = yield* waitForPending(1)
|
||||||
expect(pending).toHaveLength(1)
|
expect(pending).toHaveLength(1)
|
||||||
yield* Effect.promise(() => reloadTestInstance({ directory: dir }))
|
yield* store.reload({ directory: test.directory })
|
||||||
|
|
||||||
const exit = yield* Fiber.await(fiber)
|
const exit = yield* Fiber.await(fiber)
|
||||||
expect(Exit.isFailure(exit)).toBe(true)
|
expect(Exit.isFailure(exit)).toBe(true)
|
||||||
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
|
||||||
}),
|
}),
|
||||||
|
{ git: true },
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user