Conversation
|
Someone is attempting to deploy a commit to the Comp AI - PoC Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
1 issue found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/api/src/google/google-connection.service.ts">
<violation number="1" location="apps/api/src/google/google-connection.service.ts:234">
P3: The new roleOf/toRole code in GoogleConnectionService duplicates the workspace-role resolution already present in WorkspaceService.roleOf/toRole (and inline in SsoService.roleOf). The PR correctly centralizes the authorization predicates (isWorkspaceAdmin/isWorkspaceRole in @crm/auth), but the member lookup query itself is still copy-pasted across three services. Since this is the exact access-control path used to gate a destructive workspace-global operation, keeping three divergent copies is risky — a future change to how workspace membership/roles are resolved could update one service and silently leave suppressDomain (or another gate) out of sync. Consider extracting the role lookup (e.g. resolveWorkspaceRole(userId)) into @crm/auth alongside isWorkspaceAdmin so all role-gated mutations share one implementation.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
| where: { | ||
| organizationId_userId: { organizationId: WORKSPACE_ID, userId }, | ||
| }, | ||
| select: { role: true }, |
There was a problem hiding this comment.
P3: The new roleOf/toRole code in GoogleConnectionService duplicates the workspace-role resolution already present in WorkspaceService.roleOf/toRole (and inline in SsoService.roleOf). The PR correctly centralizes the authorization predicates (isWorkspaceAdmin/isWorkspaceRole in @crm/auth), but the member lookup query itself is still copy-pasted across three services. Since this is the exact access-control path used to gate a destructive workspace-global operation, keeping three divergent copies is risky — a future change to how workspace membership/roles are resolved could update one service and silently leave suppressDomain (or another gate) out of sync. Consider extracting the role lookup (e.g. resolveWorkspaceRole(userId)) into @crm/auth alongside isWorkspaceAdmin so all role-gated mutations share one implementation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/google/google-connection.service.ts, line 234:
<comment>The new roleOf/toRole code in GoogleConnectionService duplicates the workspace-role resolution already present in WorkspaceService.roleOf/toRole (and inline in SsoService.roleOf). The PR correctly centralizes the authorization predicates (isWorkspaceAdmin/isWorkspaceRole in @crm/auth), but the member lookup query itself is still copy-pasted across three services. Since this is the exact access-control path used to gate a destructive workspace-global operation, keeping three divergent copies is risky — a future change to how workspace membership/roles are resolved could update one service and silently leave suppressDomain (or another gate) out of sync. Consider extracting the role lookup (e.g. resolveWorkspaceRole(userId)) into @crm/auth alongside isWorkspaceAdmin so all role-gated mutations share one implementation.</comment>
<file context>
@@ -204,4 +225,19 @@ export class GoogleConnectionService {
+ where: {
+ organizationId_userId: { organizationId: WORKSPACE_ID, userId },
+ },
+ select: { role: true },
+ });
+
</file context>
Why
google.suppressDomainis a destructive, workspace-global mutation: withpurge: trueit hard-deletes every email thread and calendar event for the target company and permanently silences that domain for auto-create/notification matching across the whole workspace. Unlike every other destructive workspace mutation, it had no role check — any signed-in member could call it, deleting data they do not own.Compare the repo's own guard for workspace administration:
workspace.setMemberRoleis gated bycanChangeRole(owner/admin only) inworkspace.service.ts.What
suppressDomainnow takes the caller'suserId, resolves their workspace role, and rejects non-owner/admin callers withForbiddenExceptionbefore touching anything.ctx.user.idthrough.isWorkspaceAdmin+isWorkspaceRolehelpers from@crm/auththat the workspace service already relies on, so the authorization model stays in one place.Tests
New
apps/api/test/google-connection.spec.ts:memberis refusedadminmay suppress without purgingownermay suppress and purge (verifies the delete counts flow through)Verified:
bun run check-types,bunx biome checkon changed files, and the new spec all pass.Summary by cubic
Gated the destructive
google.suppressDomainmutation behind an owner/admin role check to prevent non-admin members from deleting workspace data. Router now passes the calleruserId; non-admins receive aForbiddenException.isWorkspaceAdmin/isWorkspaceRolefrom@crm/authinsuppressDomain.userId, resolves workspace role, and rejects non-owner/admin callers.ctx.user.idto the service.Written for commit 9f36c25. Summary will update on new commits.