diff --git a/docs/plans/2026-08-04-authz-permissions-implementation.md b/docs/plans/2026-08-04-authz-permissions-implementation.md index d2915789..ea1c93ae 100644 --- a/docs/plans/2026-08-04-authz-permissions-implementation.md +++ b/docs/plans/2026-08-04-authz-permissions-implementation.md @@ -623,17 +623,25 @@ export function runStoreConformance(name: string, makeStore: () => Promise { - // A store that wraps one method in a transaction on a shared connection - // will roll back this unrelated write and still resolve successfully. + test("a rejected write leaves unrelated state intact", async () => { await store.assignRole("victim", "admin"); - await Promise.all([ - store.revokeRole("victim", "admin"), - store.grant("other", "post:read", "allow").catch(() => undefined), - ]); - expect((await store.assignmentsFor("victim")).roles).toEqual([]); + await store.grant("victim", "post:read", "allow"); + // An invalid effect must be refused without disturbing anything else. + await expect(store.grant("victim", "post:write", "bogus" as never)).rejects.toThrow(); + const assignments = await store.assignmentsFor("victim"); + expect(assignments.roles).toEqual(["admin"]); + expect(assignments.grants).toEqual(["post:read"]); }); + // NOTE: the shared-connection rollback hazard - where one method's open + // transaction sweeps in a concurrent bare write from another method and + // discards it, so a revoke resolves successfully while the role survives - + // is prevented STRUCTURALLY, by the store using no transactions at all. + // It is deliberately not covered here: reproducing it needs the bare write + // to land inside the open transaction, which a single-process Promise.all + // does not reliably arrange, so any such test would pass against the + // defective implementation and give false assurance. + test("listSubjects with no scope returns global assignees only", async () => { await store.assignRole("g1", "viewer"); await store.assignRole("s1", "editor", { tenantId: "t1" });