chore: generate

This commit is contained in:
opencode-agent[bot]
2026-05-13 02:08:16 +00:00
parent e16f4b6b99
commit 16333b5222
2 changed files with 478 additions and 435 deletions
+474 -434
View File
@@ -556,372 +556,398 @@ test("disabled - specific allow overrides wildcard deny", () => {
// ask tests // ask tests
it.instance("ask - resolves immediately when action is allow", () => it.instance(
Effect.gen(function* () { "ask - resolves immediately when action is allow",
const result = yield* ask({ () =>
sessionID: SessionID.make("session_test"), Effect.gen(function* () {
permission: "bash", const result = yield* ask({
patterns: ["ls"],
metadata: {},
always: [],
ruleset: [{ permission: "bash", pattern: "*", action: "allow" }],
})
expect(result).toBeUndefined()
}),
{ git: true },
)
it.instance("ask - throws DeniedError when action is deny", () =>
Effect.gen(function* () {
const err = yield* fail(
ask({
sessionID: SessionID.make("session_test"), sessionID: SessionID.make("session_test"),
permission: "bash", permission: "bash",
patterns: ["rm -rf /"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [{ permission: "bash", pattern: "*", action: "deny" }], ruleset: [{ permission: "bash", pattern: "*", action: "allow" }],
}), })
) expect(result).toBeUndefined()
expect(err).toBeInstanceOf(Permission.DeniedError) }),
}),
{ git: true }, { git: true },
) )
it.instance("ask - stays pending when action is ask", () => it.instance(
Effect.gen(function* () { "ask - throws DeniedError when action is deny",
const fiber = yield* ask({ () =>
sessionID: SessionID.make("session_test"), Effect.gen(function* () {
permission: "bash", const err = yield* fail(
patterns: ["ls"], ask({
metadata: {}, sessionID: SessionID.make("session_test"),
always: [], permission: "bash",
ruleset: [{ permission: "bash", pattern: "*", action: "ask" }], patterns: ["rm -rf /"],
}).pipe(Effect.forkScoped) metadata: {},
always: [],
expect(yield* waitForPending(1)).toHaveLength(1) ruleset: [{ permission: "bash", pattern: "*", action: "deny" }],
yield* rejectAll()
yield* Fiber.await(fiber)
}),
{ git: true },
)
it.instance("ask - adds request to pending list", () =>
Effect.gen(function* () {
const fiber = yield* ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: { cmd: "ls" },
always: ["ls"],
tool: {
messageID: MessageID.make("msg_test"),
callID: "call_test",
},
ruleset: [],
}).pipe(Effect.forkScoped)
const items = yield* waitForPending(1)
expect(items).toHaveLength(1)
expect(items[0]).toMatchObject({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: { cmd: "ls" },
always: ["ls"],
tool: {
messageID: MessageID.make("msg_test"),
callID: "call_test",
},
})
yield* rejectAll()
yield* Fiber.await(fiber)
}),
{ git: true },
)
it.instance("ask - publishes asked event", () =>
Effect.gen(function* () {
const bus = yield* Bus.Service
const seen = yield* Deferred.make<Permission.Request>()
const unsub = yield* bus.subscribeCallback(Permission.Event.Asked, (event) => {
Deferred.doneUnsafe(seen, Effect.succeed(event.properties))
})
yield* Effect.addFinalizer(() => Effect.sync(unsub))
const fiber = yield* ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: { cmd: "ls" },
always: ["ls"],
tool: {
messageID: MessageID.make("msg_test"),
callID: "call_test",
},
ruleset: [],
}).pipe(Effect.forkScoped)
expect(yield* waitForPending(1)).toHaveLength(1)
expect(
yield* Deferred.await(seen).pipe(
Effect.timeoutOrElse({
duration: "1 second",
orElse: () => Effect.fail(new Error("timed out waiting for permission asked event")),
}), }),
), )
).toMatchObject({ expect(err).toBeInstanceOf(Permission.DeniedError)
sessionID: SessionID.make("session_test"), }),
permission: "bash", { git: true },
patterns: ["ls"], )
})
yield* rejectAll() it.instance(
yield* Fiber.await(fiber) "ask - stays pending when action is ask",
}), () =>
Effect.gen(function* () {
const fiber = yield* ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: {},
always: [],
ruleset: [{ permission: "bash", pattern: "*", action: "ask" }],
}).pipe(Effect.forkScoped)
expect(yield* waitForPending(1)).toHaveLength(1)
yield* rejectAll()
yield* Fiber.await(fiber)
}),
{ git: true },
)
it.instance(
"ask - adds request to pending list",
() =>
Effect.gen(function* () {
const fiber = yield* ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: { cmd: "ls" },
always: ["ls"],
tool: {
messageID: MessageID.make("msg_test"),
callID: "call_test",
},
ruleset: [],
}).pipe(Effect.forkScoped)
const items = yield* waitForPending(1)
expect(items).toHaveLength(1)
expect(items[0]).toMatchObject({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: { cmd: "ls" },
always: ["ls"],
tool: {
messageID: MessageID.make("msg_test"),
callID: "call_test",
},
})
yield* rejectAll()
yield* Fiber.await(fiber)
}),
{ git: true },
)
it.instance(
"ask - publishes asked event",
() =>
Effect.gen(function* () {
const bus = yield* Bus.Service
const seen = yield* Deferred.make<Permission.Request>()
const unsub = yield* bus.subscribeCallback(Permission.Event.Asked, (event) => {
Deferred.doneUnsafe(seen, Effect.succeed(event.properties))
})
yield* Effect.addFinalizer(() => Effect.sync(unsub))
const fiber = yield* ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["ls"],
metadata: { cmd: "ls" },
always: ["ls"],
tool: {
messageID: MessageID.make("msg_test"),
callID: "call_test",
},
ruleset: [],
}).pipe(Effect.forkScoped)
expect(yield* waitForPending(1)).toHaveLength(1)
expect(
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"),
permission: "bash",
patterns: ["ls"],
})
yield* rejectAll()
yield* Fiber.await(fiber)
}),
{ git: true }, { git: true },
) )
// reply tests // reply tests
it.instance("reply - once resolves the pending ask", () => it.instance(
Effect.gen(function* () { "reply - once resolves the pending ask",
const fiber = yield* ask({ () =>
id: PermissionID.make("per_test1"), Effect.gen(function* () {
sessionID: SessionID.make("session_test"), const fiber = yield* ask({
permission: "bash", id: PermissionID.make("per_test1"),
patterns: ["ls"], sessionID: SessionID.make("session_test"),
metadata: {}, permission: "bash",
always: [], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: [],
ruleset: [],
}).pipe(Effect.forkScoped)
yield* waitForPending(1) yield* waitForPending(1)
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 }, { git: true },
) )
it.instance("reply - reject throws RejectedError", () => it.instance(
Effect.gen(function* () { "reply - reject throws RejectedError",
const fiber = yield* ask({ () =>
id: PermissionID.make("per_test2"), Effect.gen(function* () {
sessionID: SessionID.make("session_test"), const fiber = yield* ask({
permission: "bash", id: PermissionID.make("per_test2"),
patterns: ["ls"], sessionID: SessionID.make("session_test"),
metadata: {}, permission: "bash",
always: [], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: [],
ruleset: [],
}).pipe(Effect.forkScoped)
yield* waitForPending(1) yield* waitForPending(1)
yield* reply({ requestID: PermissionID.make("per_test2"), reply: "reject" }) yield* reply({ requestID: PermissionID.make("per_test2"), reply: "reject" })
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 }, { git: true },
) )
it.instance("reply - reject with message throws CorrectedError", () => it.instance(
Effect.gen(function* () { "reply - reject with message throws CorrectedError",
const fiber = yield* ask({ () =>
id: PermissionID.make("per_test2b"), Effect.gen(function* () {
sessionID: SessionID.make("session_test"), const fiber = yield* ask({
permission: "bash", id: PermissionID.make("per_test2b"),
patterns: ["ls"], sessionID: SessionID.make("session_test"),
metadata: {}, permission: "bash",
always: [], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: [],
ruleset: [],
}).pipe(Effect.forkScoped)
yield* waitForPending(1) yield* waitForPending(1)
yield* reply({ yield* reply({
requestID: PermissionID.make("per_test2b"), requestID: PermissionID.make("per_test2b"),
reply: "reject", reply: "reject",
message: "Use a safer command", message: "Use a safer command",
}) })
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)) { if (Exit.isFailure(exit)) {
const err = Cause.squash(exit.cause) const err = Cause.squash(exit.cause)
expect(err).toBeInstanceOf(Permission.CorrectedError) expect(err).toBeInstanceOf(Permission.CorrectedError)
expect(String(err)).toContain("Use a safer command") expect(String(err)).toContain("Use a safer command")
} }
}), }),
{ git: true }, { git: true },
) )
it.instance("reply - always persists approval and resolves", () => it.instance(
Effect.gen(function* () { "reply - always persists approval and resolves",
const fiber = yield* ask({ () =>
id: PermissionID.make("per_test3"), Effect.gen(function* () {
sessionID: SessionID.make("session_test"), const fiber = yield* ask({
permission: "bash", id: PermissionID.make("per_test3"),
patterns: ["ls"], sessionID: SessionID.make("session_test"),
metadata: {}, permission: "bash",
always: ["ls"], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: ["ls"],
ruleset: [],
}).pipe(Effect.forkScoped)
yield* waitForPending(1) yield* waitForPending(1)
yield* reply({ requestID: PermissionID.make("per_test3"), reply: "always" }) 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({
sessionID: SessionID.make("session_test2"), sessionID: SessionID.make("session_test2"),
permission: "bash", permission: "bash",
patterns: ["ls"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [], ruleset: [],
}) })
expect(result).toBeUndefined() expect(result).toBeUndefined()
}), }),
{ git: true }, { git: true },
) )
it.instance("reply - reject cancels all pending for same session", () => it.instance(
Effect.gen(function* () { "reply - reject cancels all pending for same session",
const a = yield* ask({ () =>
id: PermissionID.make("per_test4a"), Effect.gen(function* () {
sessionID: SessionID.make("session_same"), const a = yield* ask({
permission: "bash", id: PermissionID.make("per_test4a"),
patterns: ["ls"], sessionID: SessionID.make("session_same"),
metadata: {}, permission: "bash",
always: [], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: [],
ruleset: [],
}).pipe(Effect.forkScoped)
const b = yield* ask({ const b = yield* ask({
id: PermissionID.make("per_test4b"), id: PermissionID.make("per_test4b"),
sessionID: SessionID.make("session_same"), sessionID: SessionID.make("session_same"),
permission: "edit", permission: "edit",
patterns: ["foo.ts"], patterns: ["foo.ts"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [], ruleset: [],
}).pipe(Effect.forkScoped) }).pipe(Effect.forkScoped)
yield* waitForPending(2) yield* waitForPending(2)
yield* reply({ requestID: PermissionID.make("per_test4a"), reply: "reject" }) yield* reply({ requestID: PermissionID.make("per_test4a"), reply: "reject" })
const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)]) const [ea, eb] = yield* Effect.all([Fiber.await(a), Fiber.await(b)])
expect(Exit.isFailure(ea)).toBe(true) expect(Exit.isFailure(ea)).toBe(true)
expect(Exit.isFailure(eb)).toBe(true) expect(Exit.isFailure(eb)).toBe(true)
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 }, { git: true },
) )
it.instance("reply - always resolves matching pending requests in same session", () => it.instance(
Effect.gen(function* () { "reply - always resolves matching pending requests in same session",
const a = yield* ask({ () =>
id: PermissionID.make("per_test5a"), Effect.gen(function* () {
sessionID: SessionID.make("session_same"), const a = yield* ask({
permission: "bash", id: PermissionID.make("per_test5a"),
patterns: ["ls"], sessionID: SessionID.make("session_same"),
metadata: {}, permission: "bash",
always: ["ls"], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: ["ls"],
ruleset: [],
}).pipe(Effect.forkScoped)
const b = yield* ask({ const b = yield* ask({
id: PermissionID.make("per_test5b"), id: PermissionID.make("per_test5b"),
sessionID: SessionID.make("session_same"), sessionID: SessionID.make("session_same"),
permission: "bash", permission: "bash",
patterns: ["ls"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [], ruleset: [],
}).pipe(Effect.forkScoped) }).pipe(Effect.forkScoped)
yield* waitForPending(2) yield* waitForPending(2)
yield* reply({ requestID: PermissionID.make("per_test5a"), reply: "always" }) yield* reply({ requestID: PermissionID.make("per_test5a"), reply: "always" })
yield* Fiber.join(a) yield* Fiber.join(a)
yield* Fiber.join(b) yield* Fiber.join(b)
expect(yield* list()).toHaveLength(0) expect(yield* list()).toHaveLength(0)
}), }),
{ git: true }, { git: true },
) )
it.instance("reply - always keeps other session pending", () => it.instance(
Effect.gen(function* () { "reply - always keeps other session pending",
const a = yield* ask({ () =>
id: PermissionID.make("per_test6a"), Effect.gen(function* () {
sessionID: SessionID.make("session_a"), const a = yield* ask({
permission: "bash", id: PermissionID.make("per_test6a"),
patterns: ["ls"], sessionID: SessionID.make("session_a"),
metadata: {}, permission: "bash",
always: ["ls"], patterns: ["ls"],
ruleset: [], metadata: {},
}).pipe(Effect.forkScoped) always: ["ls"],
ruleset: [],
}).pipe(Effect.forkScoped)
const b = yield* ask({ const b = yield* ask({
id: PermissionID.make("per_test6b"), id: PermissionID.make("per_test6b"),
sessionID: SessionID.make("session_b"), sessionID: SessionID.make("session_b"),
permission: "bash", permission: "bash",
patterns: ["ls"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [], ruleset: [],
}).pipe(Effect.forkScoped) }).pipe(Effect.forkScoped)
yield* waitForPending(2) yield* waitForPending(2)
yield* reply({ requestID: PermissionID.make("per_test6a"), reply: "always" }) yield* reply({ requestID: PermissionID.make("per_test6a"), reply: "always" })
yield* Fiber.join(a) yield* Fiber.join(a)
expect((yield* list()).map((item) => item.id)).toEqual([PermissionID.make("per_test6b")]) expect((yield* list()).map((item) => item.id)).toEqual([PermissionID.make("per_test6b")])
yield* rejectAll() yield* rejectAll()
yield* Fiber.await(b) yield* Fiber.await(b)
}), }),
{ git: true }, { git: true },
) )
it.instance("reply - publishes replied event", () => it.instance(
Effect.gen(function* () { "reply - publishes replied event",
const bus = yield* Bus.Service () =>
const seen = yield* Deferred.make<{ sessionID: SessionID; requestID: PermissionID; reply: Permission.Reply }>() Effect.gen(function* () {
const bus = yield* Bus.Service
const seen = yield* Deferred.make<{ sessionID: SessionID; requestID: PermissionID; reply: Permission.Reply }>()
const fiber = yield* ask({ const fiber = yield* ask({
id: PermissionID.make("per_test7"), id: PermissionID.make("per_test7"),
sessionID: SessionID.make("session_test"), sessionID: SessionID.make("session_test"),
permission: "bash", permission: "bash",
patterns: ["ls"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [], ruleset: [],
}).pipe(Effect.forkScoped) }).pipe(Effect.forkScoped)
yield* waitForPending(1) yield* waitForPending(1)
const unsub = yield* bus.subscribeCallback(Permission.Event.Replied, (event) => { const unsub = yield* bus.subscribeCallback(Permission.Event.Replied, (event) => {
Deferred.doneUnsafe(seen, Effect.succeed(event.properties)) Deferred.doneUnsafe(seen, Effect.succeed(event.properties))
}) })
yield* Effect.addFinalizer(() => Effect.sync(unsub)) yield* Effect.addFinalizer(() => Effect.sync(unsub))
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( expect(
yield* Deferred.await(seen).pipe( yield* Deferred.await(seen).pipe(
Effect.timeoutOrElse({ Effect.timeoutOrElse({
duration: "1 second", duration: "1 second",
orElse: () => Effect.fail(new Error("timed out waiting for permission replied event")), orElse: () => Effect.fail(new Error("timed out waiting for permission replied event")),
}), }),
), ),
).toEqual({ ).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",
}) })
}), }),
{ git: true }, { git: true },
) )
@@ -977,142 +1003,156 @@ it.live("permission requests stay isolated by directory", () =>
}), }),
) )
it.instance("pending permission rejects on instance dispose", () => it.instance(
Effect.gen(function* () { "pending permission rejects on instance dispose",
const test = yield* TestInstance () =>
const store = yield* InstanceStore.Service Effect.gen(function* () {
const fiber = yield* ask({ const test = yield* TestInstance
id: PermissionID.make("per_dispose"), const store = yield* InstanceStore.Service
sessionID: SessionID.make("session_dispose"), const fiber = yield* ask({
permission: "bash", id: PermissionID.make("per_dispose"),
patterns: ["ls"], sessionID: SessionID.make("session_dispose"),
metadata: {},
always: [],
ruleset: [],
}).pipe(Effect.forkScoped)
expect(yield* waitForPending(1)).toHaveLength(1)
const ctx = yield* store.load({ directory: test.directory })
yield* store.dispose(ctx)
const exit = yield* Fiber.await(fiber)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
}),
{ git: true },
)
it.instance("pending permission rejects on instance reload", () =>
Effect.gen(function* () {
const test = yield* TestInstance
const store = yield* InstanceStore.Service
const fiber = yield* ask({
id: PermissionID.make("per_reload"),
sessionID: SessionID.make("session_reload"),
permission: "bash",
patterns: ["ls"],
metadata: {},
always: [],
ruleset: [],
}).pipe(Effect.forkScoped)
expect(yield* waitForPending(1)).toHaveLength(1)
yield* store.reload({ directory: test.directory })
const exit = yield* Fiber.await(fiber)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
}),
{ git: true },
)
it.instance("reply - does nothing for unknown requestID", () =>
Effect.gen(function* () {
yield* reply({ requestID: PermissionID.make("per_unknown"), reply: "once" })
expect(yield* list()).toHaveLength(0)
}),
{ git: true },
)
it.instance("ask - checks all patterns and stops on first deny", () =>
Effect.gen(function* () {
const err = yield* fail(
ask({
sessionID: SessionID.make("session_test"),
permission: "bash", permission: "bash",
patterns: ["echo hello", "rm -rf /"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [ ruleset: [],
{ permission: "bash", pattern: "*", action: "allow" }, }).pipe(Effect.forkScoped)
{ permission: "bash", pattern: "rm *", action: "deny" },
], expect(yield* waitForPending(1)).toHaveLength(1)
}), const ctx = yield* store.load({ directory: test.directory })
) yield* store.dispose(ctx)
expect(err).toBeInstanceOf(Permission.DeniedError)
}), const exit = yield* Fiber.await(fiber)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
}),
{ git: true }, { git: true },
) )
it.instance("ask - allows all patterns when all match allow rules", () => it.instance(
Effect.gen(function* () { "pending permission rejects on instance reload",
const result = yield* ask({ () =>
sessionID: SessionID.make("session_test"), Effect.gen(function* () {
permission: "bash", const test = yield* TestInstance
patterns: ["echo hello", "ls -la", "pwd"], const store = yield* InstanceStore.Service
metadata: {}, const fiber = yield* ask({
always: [], id: PermissionID.make("per_reload"),
ruleset: [{ permission: "bash", pattern: "*", action: "allow" }], sessionID: SessionID.make("session_reload"),
})
expect(result).toBeUndefined()
}),
{ git: true },
)
it.instance("ask - should deny even when an earlier pattern is ask", () =>
Effect.gen(function* () {
const err = yield* fail(
ask({
sessionID: SessionID.make("session_test"),
permission: "bash", permission: "bash",
patterns: ["echo hello", "rm -rf /"], patterns: ["ls"],
metadata: {}, metadata: {},
always: [], always: [],
ruleset: [ ruleset: [],
{ permission: "bash", pattern: "echo *", action: "ask" }, }).pipe(Effect.forkScoped)
{ permission: "bash", pattern: "rm *", action: "deny" },
],
}),
)
expect(err).toBeInstanceOf(Permission.DeniedError) expect(yield* waitForPending(1)).toHaveLength(1)
expect(yield* list()).toHaveLength(0) yield* store.reload({ directory: test.directory })
}),
const exit = yield* Fiber.await(fiber)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
}),
{ git: true }, { git: true },
) )
it.instance("ask - abort should clear pending request", () => it.instance(
Effect.gen(function* () { "reply - does nothing for unknown requestID",
const test = yield* TestInstance () =>
const store = yield* InstanceStore.Service Effect.gen(function* () {
yield* reply({ requestID: PermissionID.make("per_unknown"), reply: "once" })
const fiber = yield* ask({ expect(yield* list()).toHaveLength(0)
id: PermissionID.make("per_reload"), }),
sessionID: SessionID.make("session_reload"), { git: true },
permission: "bash", )
patterns: ["ls"],
metadata: {}, it.instance(
always: [], "ask - checks all patterns and stops on first deny",
ruleset: [{ permission: "bash", pattern: "*", action: "ask" }], () =>
}).pipe(Effect.forkScoped) Effect.gen(function* () {
const err = yield* fail(
const pending = yield* waitForPending(1) ask({
expect(pending).toHaveLength(1) sessionID: SessionID.make("session_test"),
yield* store.reload({ directory: test.directory }) permission: "bash",
patterns: ["echo hello", "rm -rf /"],
const exit = yield* Fiber.await(fiber) metadata: {},
expect(Exit.isFailure(exit)).toBe(true) always: [],
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError) ruleset: [
}), { permission: "bash", pattern: "*", action: "allow" },
{ permission: "bash", pattern: "rm *", action: "deny" },
],
}),
)
expect(err).toBeInstanceOf(Permission.DeniedError)
}),
{ git: true },
)
it.instance(
"ask - allows all patterns when all match allow rules",
() =>
Effect.gen(function* () {
const result = yield* ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["echo hello", "ls -la", "pwd"],
metadata: {},
always: [],
ruleset: [{ permission: "bash", pattern: "*", action: "allow" }],
})
expect(result).toBeUndefined()
}),
{ git: true },
)
it.instance(
"ask - should deny even when an earlier pattern is ask",
() =>
Effect.gen(function* () {
const err = yield* fail(
ask({
sessionID: SessionID.make("session_test"),
permission: "bash",
patterns: ["echo hello", "rm -rf /"],
metadata: {},
always: [],
ruleset: [
{ permission: "bash", pattern: "echo *", action: "ask" },
{ permission: "bash", pattern: "rm *", action: "deny" },
],
}),
)
expect(err).toBeInstanceOf(Permission.DeniedError)
expect(yield* list()).toHaveLength(0)
}),
{ git: true },
)
it.instance(
"ask - abort should clear pending request",
() =>
Effect.gen(function* () {
const test = yield* TestInstance
const store = yield* InstanceStore.Service
const fiber = yield* ask({
id: PermissionID.make("per_reload"),
sessionID: SessionID.make("session_reload"),
permission: "bash",
patterns: ["ls"],
metadata: {},
always: [],
ruleset: [{ permission: "bash", pattern: "*", action: "ask" }],
}).pipe(Effect.forkScoped)
const pending = yield* waitForPending(1)
expect(pending).toHaveLength(1)
yield* store.reload({ directory: test.directory })
const exit = yield* Fiber.await(fiber)
expect(Exit.isFailure(exit)).toBe(true)
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toBeInstanceOf(Permission.RejectedError)
}),
{ git: true }, { git: true },
) )
@@ -31,7 +31,10 @@ const setBootstrap = (run: Effect.Effect<void>) =>
) )
const registerDisposerScoped = (disposer: (directory: string) => Promise<void>) => const registerDisposerScoped = (disposer: (directory: string) => Promise<void>) =>
Effect.acquireRelease(Effect.sync(() => registerDisposer(disposer)), (off) => Effect.sync(off)) Effect.acquireRelease(
Effect.sync(() => registerDisposer(disposer)),
(off) => Effect.sync(off),
)
describe("InstanceStore", () => { describe("InstanceStore", () => {
it.live("loads instance context without installing ALS for the caller", () => it.live("loads instance context without installing ALS for the caller", () =>