Repository navigation
Show restricted members only their own calls in the audit API - #1665
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second step of member visibility (after #1664). In a workspace set to
restricted, a member who is not an admin now gets only the tool calls they made themselves from every audit read route. Admins and open workspaces keep today's code path and today's queries.Cloud and self-hosted: identical, off by default. No workspace has the setting yet, so nothing changes on deploy.
Changes
AuditController: each GET route asksMemberVisibilityService.scopeFor(req.user)first. Not restricted: today's call, unchanged (same arguments, same arity). Restricted: the same call plus the caller's user id.GET /api/audit/invocations: only rows withuserId = caller. Rows without a user are hidden. Same response shape.toolId,connectorId,mcpServerId,search,status,limit,offsetcombine with the user filter (AND).GET /api/audit/stats: the four counters count only the caller's calls.GET /api/audit/analytics:AND ti.user_id = $ninanalyticsQuery.GET /api/audit/tool-performance:AND ti.user_id = $nintoolPerformanceQuery, both in the grouped page and in the latest-error lookup. Without the second one, another member's newer error text on the same tool would show aslastError.GET /api/audit/breakdowns: every list and total counts only the caller's calls;byUserholds only their own row.AuditService/tool-performance.query.ts: optionalonlyUserId. Prismawhereor a bound SQL value, never string concatenation. TheorganizationIdfilter stays in every query. Absent on the open path; when present it is always applied, so an empty value matches nothing.MemberVisibilityService, from Add the member visibility setting and the service that decides it #1664).AuditModuleimportsMemberVisibilityModule(notSettingsModule, which the File Search worker loads without roles and audit).packages/cli/src/generated/operations.tsdoes not change (it carries no descriptions).Type
Testing
New specs:
audit.controller.spec.ts: matrix for every GET route, ADMIN / EDITOR / VIEWER x open / never set / restricted, with and without a tool whitelist. Asserts exact AuditService arguments. Includes a route coverage check (fails if a GET route has no rule) and fail-closed cases.audit.member-visibility.spec.ts: Prismawhereand SQL text/values with and without the user filter; injection attempt stays a bound value.audit.member-visibility.integration.spec.ts(real migrated PostgreSQL,AUDIT_TEST_DATABASE_URL, as in CI): HTTP to the five routes with real memberships, realorg_settingsmode and the realRolesService. Open: everyone sees all. Restricted: admin sees all; viewer and editor see only their rows; no filter parameter returns another member's row; stats, analytics, tool performance (includinglastError) and breakdowns hold only own calls; 500 when the role lookup throws. Cleans up its rows.audit.module.spec.ts: AuditController gets the realMemberVisibilityServicethroughMemberVisibilityModule.Existing specs: no expectation changed.
tool-performance.integration.spec.tsgot one provider in its setup (MemberVisibilityServicereturning open), because the controller now injects it.Commands, run after rebasing on
mainwith #1664 merged (inpackages/backend, local PostgreSQL 17 on port 5433, database migrated withnpx prisma migrate deploy):AUDIT_TEST_DATABASE_URL=... npx jest src/audit src/settings src/roles --maxWorkers=4: 31 suites passed, 1 failed; 1531 tests passed, 1 failed.tool-performance.integration.spec.ts"weights ERROR and TIMEOUT counts" expects285and gets284.99999999999994from local PostgreSQL 17.11 on arm64. It fails the same way on the base branch without this change.AUDIT_TEST_DATABASE_URL=... npx jest src/audit/audit.member-visibility.integration --maxWorkers=4: 16 passed.npx jest src/audit --maxWorkers=4(no database): 16 suites passed, 2 skipped (the PostgreSQL specs); 293 tests passed, 25 skipped.npx eslint <changed files>: no findings.npx tsc --noEmit -p tsconfig.json: no errors.node scripts/generate-cli-operations.mjs(repo root): no diff.Checklist
npm test) (ran the audit, settings and roles suites; one baseline failure above)Related Issues
Relates to #1664