From 8bd288a7dbe784c0e1d57afcba85802d4197dd4b Mon Sep 17 00:00:00 2001 From: Jarvis Date: Wed, 24 Jun 2026 16:41:11 -0500 Subject: [PATCH] test(#462): cover native RBAC personal scope intersection --- .../server/__tests__/scope.service.spec.ts | 24 +++++++++++++++++++ .../462-fed-m3-04-scope-service.md | 8 +++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/gateway/src/federation/server/__tests__/scope.service.spec.ts b/apps/gateway/src/federation/server/__tests__/scope.service.spec.ts index 0bbbe65..de3d44d 100644 --- a/apps/gateway/src/federation/server/__tests__/scope.service.spec.ts +++ b/apps/gateway/src/federation/server/__tests__/scope.service.spec.ts @@ -8,6 +8,7 @@ * - invalid requested limit deny * - native RBAC deny as subjectUserId * - scope/native filter intersection for personal and team rows + * - native RBAC personal deny wins over scope include_personal allow/default * - max_rows_per_query cap */ @@ -122,6 +123,29 @@ describe('FederationScopeService', () => { }); }); + it('does not leak personal rows when scope allows personal but native RBAC denies personal', async () => { + const result = await service.evaluateAccess({ + context: makeContext({ + resources: ['tasks'], + filters: { tasks: { include_personal: true } }, + max_rows_per_query: 25, + }), + resource: 'tasks', + nativeRbac: makeNativeRbac({ + allowed: true, + access: { includePersonal: false, teamIds: ['team-1'] }, + }), + }); + + expect(result).toMatchObject({ + allowed: true, + filter: { + includePersonal: false, + teamIds: ['team-1'], + }, + }); + }); + it('does not widen native RBAC when scope includes teams the user cannot access', async () => { const result = await service.evaluateAccess({ context: makeContext({ diff --git a/docs/scratchpads/462-fed-m3-04-scope-service.md b/docs/scratchpads/462-fed-m3-04-scope-service.md index ed5d10c..8fe014a 100644 --- a/docs/scratchpads/462-fed-m3-04-scope-service.md +++ b/docs/scratchpads/462-fed-m3-04-scope-service.md @@ -45,11 +45,11 @@ Implement `apps/gateway/src/federation/server/scope.service.ts` for the M3 inbou ## Verification Evidence -- `pnpm --filter @mosaicstack/gateway test -- src/federation/server/__tests__/scope.service.spec.ts` — pass (10 tests). +- `pnpm --filter @mosaicstack/gateway test -- src/federation/server/__tests__/scope.service.spec.ts` — pass (10 tests before review update; 11 tests after adding include_personal no-leak coverage). - `pnpm build` — pass (23 successful tasks). -- `pnpm typecheck` — pass (41 successful tasks). -- `pnpm lint` — pass (23 successful tasks). -- `pnpm format:check` — pass. +- `pnpm typecheck` — pass (41 successful tasks; re-run after review update). +- `pnpm lint` — pass (23 successful tasks; re-run after review update). +- `pnpm format:check` — pass (re-run after review update). - `pnpm test` — pass after starting local `postgres`/`valkey` and running `pnpm --filter @mosaicstack/db db:push` for the DB-backed cross-user isolation suite (41 successful tasks; gateway 477 passed / 11 skipped). - Code review: `~/.config/mosaic/tools/codex/codex-code-review.sh --uncommitted` — approve, 0 findings. - Security review: `~/.config/mosaic/tools/codex/codex-security-review.sh --uncommitted` — risk none, 0 findings.