import { describe, test } from 'node:test'; import assert from 'node:assert/strict'; import fc from 'fast-check'; import { Arbiter } from '../../src/core/Arbiter.js'; describe('Fast-check: partial overlay vs union overlays', () => { test('union overlays cannot revoke access', () => { fc.assert( fc.property( fc.integer({ min: 1, max: 5 }), fc.integer({ min: 1, max: 5 }), fc.array( fc.record({ user: fc.integer({ min: 0, max: 4 }), doc: fc.integer({ min: 0, max: 4 }) }), { minLength: 1, maxLength: 20 } ), fc.array( fc.record({ user: fc.integer({ min: 0, max: 4 }), doc: fc.integer({ min: 0, max: 4 }) }), { minLength: 1, maxLength: 20 } ), (userCount, docCount, baseEdges, unionRemovals) => { const arbiter = new Arbiter(); for (let u = 0; u < userCount; u++) arbiter.addNode(`user:${u}`, 'user'); for (let d = 0; d < docCount; d++) arbiter.addNode(`doc:${d}`, 'doc'); arbiter.setRelationConfig('viewer', { type: 'direct' }); const baseSet = new Set(); for (const edge of baseEdges) { const u = edge.user % userCount; const d = edge.doc % docCount; arbiter.addRelation(`user:${u}`, 'viewer', `doc:${d}`, 1.0); baseSet.add(`${u}:${d}`); } const partialGraph = { overlayMode: 'union', relations: unionRemovals.map((edge) => ({ src: `user:${edge.user % userCount}`, relation: 'viewer', dst: `doc:${edge.doc % docCount}`, possibility: 1.0 })) }; for (let u = 0; u < userCount; u++) { for (let d = 0; d < docCount; d++) { const result = arbiter.check(`user:${u}`, 'viewer', `doc:${d}`, { partialGraph }); const key = `${u}:${d}`; if (baseSet.has(key)) { assert.ok(result.possibility > 0, 'Union overlay must not revoke base access'); } } } } ), { numRuns: 30 } ); }); });