Skip to content

fix: allow team managers to create Google Sheets syncs (NES-1489)#8909

Open
jianwei1 wants to merge 4 commits intomainfrom
jianweichong/nes-1489-google-sync-only-works-for-team-creator-not-for-other
Open

fix: allow team managers to create Google Sheets syncs (NES-1489)#8909
jianwei1 wants to merge 4 commits intomainfrom
jianweichong/nes-1489-google-sync-only-works-for-team-creator-not-for-other

Conversation

@jianwei1
Copy link
Copy Markdown
Contributor

@jianwei1 jianwei1 commented Mar 25, 2026

Summary

  • Bug: googleSheetsSyncCreate mutation only allowed the integration creator to create syncs, blocking all other team members including managers
  • Root cause: isIntegrationOwner was used as a hard withAuth guard, rejecting non-creators before the resolver even ran
  • Fix: Replaced with isAuthenticated guard + resolver-level isIntegrationOwner || isTeamManager check, matching the pattern already used by googleSheetsSyncDelete and googleSheetsSyncBackfill

Permission Model After Fix

User Role Can Create Sync?
Integration owner Yes
Team manager (non-owner) Yes
Team member (non-manager) No (Forbidden)
Unauthenticated No (Not authorized)

Test Plan

  • Integration owner can create sync (existing, updated)
  • Team manager (non-owner) can create sync (new test)
  • Neither owner nor manager → Forbidden (new test)
  • Team member (non-manager) → Forbidden (new test)
  • Unauthenticated → Not authorized (existing)
  • Journey not found → error (existing)
  • Integration not found → error (existing)
  • Export permission denied → Forbidden (existing)
  • folderId included when provided (existing)
  • All 540 tests pass

Post-Deploy Monitoring & Validation

No additional operational monitoring required: this is a permission-model fix that aligns one mutation with the existing pattern used by sibling mutations. No new infrastructure, no new API surface.

Closes NES-1489

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) [email protected]

Summary by CodeRabbit

  • Bug Fixes
    • Refined authorization for Google Sheets sync creation to allow team managers alongside integration owners.
    • Improved error handling with explicit "Forbidden" responses for unauthorized access attempts.

Replace isIntegrationOwner withAuth guard with isAuthenticated + resolver-level
permission check (isIntegrationOwner || isTeamManager), matching the pattern
used by googleSheetsSyncDelete and googleSheetsSyncBackfill.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@stage-branch-merger
Copy link
Copy Markdown

I see you added the "on stage" label, I'll get this merged to the stage branch!

@linear
Copy link
Copy Markdown

linear bot commented Mar 25, 2026

@jianwei1 jianwei1 self-assigned this Mar 25, 2026
@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Mar 25, 2026

View your CI Pipeline Execution ↗ for commit 3735098

Command Status Duration Result
nx affected --target=subgraph-check --base=40c9... ✅ Succeeded 1s View ↗
nx affected --target=extract-translations --bas... ✅ Succeeded <1s View ↗
nx affected --target=lint --base=40c9509dfb848b... ✅ Succeeded 1s View ↗
nx affected --target=type-check --base=40c9509d... ✅ Succeeded 1s View ↗
nx run-many --target=codegen --all --parallel=3 ✅ Succeeded 2s View ↗
nx run-many --target=prisma-generate --all --pa... ✅ Succeeded 4s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-30 01:12:12 UTC

@jianwei1 jianwei1 requested a review from mikeallisonJS March 25, 2026 20:23
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

Walkthrough

Authorization checks for Google Sheets sync creation are refactored from middleware-level constraints to explicit resolver logic. The resolver now permits access if the user is either the integration owner or a team manager, with comprehensive test coverage for each authorization scenario.

Changes

Cohort / File(s) Summary
Authorization Logic Refactoring
apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.ts
Shifted authorization enforcement from middleware (t.withAuth()) to resolver; added inline checks for isIntegrationOwner and isTeamManager roles, with explicit Forbidden error for unauthorized access.
Authorization Test Expansion
apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.spec.ts
Replaced default mock setup with per-test authorization scenarios; added four distinct test cases covering integration owner, team manager, team member, and non-owner roles; updated error expectations to Forbidden.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: allowing team managers to create Google Sheets syncs, which is the primary fix in this pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jianweichong/nes-1489-google-sync-only-works-for-team-creator-not-for-other

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.ts (1)

44-57: Consider extracting the manager-or-owner check into a shared helper.

This permission block now mirrors the same logic used in the other Google Sheets sync mutations, so centralizing it would make future auth changes less likely to drift between create/delete/backfill.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.ts`
around lines 44 - 57, Extract the duplicated permission check into a shared
helper (e.g., isManagerOrOwner(userId, journey, googleIntegration)) that returns
a boolean; replace the inline logic that computes
isTeamManager/isIntegrationOwner in googleSheetsSyncCreate (and mirror in other
Google Sheets sync mutations) with a call to that helper, and keep the same
GraphQLError('Forbidden', { extensions: { code: 'FORBIDDEN' } }) throw when the
helper returns false; ensure the helper checks journey.team?.userTeams for a
userTeam with matching userId and role === 'manager' and verifies
googleIntegration.userId === userId so behavior of the existing variables
(isTeamManager, isIntegrationOwner) is preserved.
apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.spec.ts (1)

243-300: Consider adding a manager-without-export-permission case.

The new branch introduced here is “team manager but not integration owner,” but the existing export-denied test still only exercises the owner path. Adding the same manager fixture with mockAbility.mockReturnValue(false) would lock down that the new branch still respects the export gate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.spec.ts`
around lines 243 - 300, Add a new test that covers the "manager without export
permission" path: reuse the same mockJourney and mockIntegration fixtures from
the existing case but set mockAbility.mockReturnValue(false) (or
mockReturnValueOnce) to simulate export permission denied, invoke authClient
with GOOGLE_SHEETS_SYNC_CREATE_MUTATION and the same variables, then assert the
mutation is rejected (e.g., data.googleSheetsSyncCreate is null and errors
contain the permission/authorization message) and verify
prismaMock.googleSheetsSync.create was not called; this ensures the code paths
in the googleSheetsSyncCreate resolver enforce the export gate for managers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.spec.ts`:
- Around line 243-300: Add a new test that covers the "manager without export
permission" path: reuse the same mockJourney and mockIntegration fixtures from
the existing case but set mockAbility.mockReturnValue(false) (or
mockReturnValueOnce) to simulate export permission denied, invoke authClient
with GOOGLE_SHEETS_SYNC_CREATE_MUTATION and the same variables, then assert the
mutation is rejected (e.g., data.googleSheetsSyncCreate is null and errors
contain the permission/authorization message) and verify
prismaMock.googleSheetsSync.create was not called; this ensures the code paths
in the googleSheetsSyncCreate resolver enforce the export gate for managers.

In
`@apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.ts`:
- Around line 44-57: Extract the duplicated permission check into a shared
helper (e.g., isManagerOrOwner(userId, journey, googleIntegration)) that returns
a boolean; replace the inline logic that computes
isTeamManager/isIntegrationOwner in googleSheetsSyncCreate (and mirror in other
Google Sheets sync mutations) with a call to that helper, and keep the same
GraphQLError('Forbidden', { extensions: { code: 'FORBIDDEN' } }) throw when the
helper returns false; ensure the helper checks journey.team?.userTeams for a
userTeam with matching userId and role === 'manager' and verifies
googleIntegration.userId === userId so behavior of the existing variables
(isTeamManager, isIntegrationOwner) is preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 250abc16-e81c-4e45-b48b-0245ff2027b4

📥 Commits

Reviewing files that changed from the base of the PR and between 2e47fe9 and 78af4de.

📒 Files selected for processing (2)
  • apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.spec.ts
  • apis/api-journeys-modern/src/schema/googleSheetsSync/googleSheetsSyncCreate.mutation.ts

@stage-branch-merger
Copy link
Copy Markdown

Merge conflict attempting to merge this into stage. Please fix manually.

stage-branch-merger bot added a commit that referenced this pull request Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant