import { describe, expect, it } from "@suaveplan/testing/runner"; import * as fc from "fast-check"; import { GrantManager, InMemoryPartitionStore, KeyRing, mergePolicies, PartitionManager, partitionId, TokenManager, userId, } from "../src/index.js"; describe("property — grant expiry", () => { it("grant check returns allowed false after advancing clock beyond TTL", { timeout: 30000, }, () => { fc.assert( fc.property( fc.integer({ min: 1, max: 100_000 }), fc.integer({ min: 1, max: 100 }), (ttl, offset) => { let now = 0; const m = new GrantManager({ clock: () => now }); const grant = m.create({ grantorId: userId("a"), granteeId: userId("b"), partitionId: partitionId("p"), permissions: ["read"], expiresAt: ttl, }); now = ttl + offset; const r = m.check(grant.id, userId("b"), "read"); expect(r.allowed).toBe(false); } ), { numRuns: 50 } ); }); }); describe("property — token revocation finality", () => { it("revoked token validate always returns valid false", { timeout: 30000, }, () => { fc.assert( fc.property(fc.integer({ min: 1, max: 100 }), (validateCount) => { const m = new TokenManager({ clock: () => 0, masterKey: new Uint8Array(32).fill(0xee), }); const t = m.create({ partitionId: partitionId("p"), createdBy: userId("a"), permissions: ["read"], }); m.revoke(t.id); for (let i = 0; i < validateCount; i += 1) { const r = m.validate(t.id); expect(r.valid).toBe(false); } }), { numRuns: 30 } ); }); }); describe("property — policy merge commutativity", () => { it("mergePolicies on disjoint allowedActions yields union", { timeout: 30000, }, () => { fc.assert( fc.property( fc.uniqueArray(fc.constantFrom("read", "write" as const), { minLength: 0, maxLength: 2, }), fc.uniqueArray(fc.constantFrom("delete", "share" as const), { minLength: 0, maxLength: 2, }), (a, b) => { const aP = { encryption: true, reauthRequired: [], allowedActions: a, }; const bP = { encryption: true, reauthRequired: [], allowedActions: b, }; const ab = mergePolicies(aP, bP); const ba = mergePolicies(bP, aP); // Same set, order may differ. expect(new Set(ab.allowedActions)).toEqual( new Set(ba.allowedActions) ); expect(new Set(ab.allowedActions)).toEqual( new Set([...a, ...b]) ); } ), { numRuns: 50 } ); }); }); describe("property — partition member invariant", () => { it("addMember then removeMember restores member count", { timeout: 30000, }, async () => { await fc.assert( fc.asyncProperty( fc.string({ minLength: 1, maxLength: 16 }), async (name) => { const manager = new PartitionManager({ store: new InMemoryPartitionStore(), keyRing: new KeyRing(), }); const p = await manager.create({ name, type: "shared", ownerId: userId("alice"), }); const before = p.members.length; const after1 = await manager.addMember(p.id, userId("bob")); const after2 = await manager.removeMember( after1.id, userId("bob") ); expect(after2.members.length).toBe(before); } ), { numRuns: 25 } ); }); });