feat(gmail): define Relayfile control contract - #262
Conversation
|
Warning Review limit reached
Next review available in: 50 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a pure, exported ChangesGmail control contract
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
packages/gmail/src/google-mail-relayfile-contract.ts (1)
291-292: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse
GOOGLE_MAIL_RELAYFILE_ROOTin the target regexes.Line 285 builds canonical paths from
GOOGLE_MAIL_RELAYFILE_ROOT, but Lines 291-292 hardcode/gmail. IfGMAIL_PATH_ROOTchanges, the parser and the emitter diverge silently. Build the patterns from the constant.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/gmail/src/google-mail-relayfile-contract.ts` around lines 291 - 292, Update the regexes in the path-parsing logic around canonicalMatch and aliasMatch to use GOOGLE_MAIL_RELAYFILE_ROOT instead of hardcoding /gmail, preserving the existing endpoint and identifier matching behavior so parsing stays aligned with emitted paths.packages/gmail/src/__tests__/google-mail-relayfile-contract.test.ts (3)
36-57: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a case for a send-as address with a draft-like local part.
The suite resolves
alias+agent@example.comandalias@example.test, but no case uses a local part that starts withnew,temp,draft,create, ortmp.isDraftLikematches those prefixes, so such an address resolves tokind: 'draft'. See the related comment onpackages/gmail/src/google-mail-relayfile-contract.tsLines 267-269.Add a case that asserts
/gmail/send-as/new-hire@example.com.jsonresolves tokind: 'canonical'and that an upsert on it maps toupdate_send_as.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/gmail/src/__tests__/google-mail-relayfile-contract.test.ts` around lines 36 - 57, Extend the Google Mail Relayfile contract tests with /gmail/send-as/new-hire@example.com.json, asserting it resolves as kind: 'canonical' rather than draft-like and that an upsert for this target maps to update_send_as. Reuse the existing resolveGoogleMailRelayfileTarget and upsert mapping test patterns.
350-363: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover padded base64url input.
isBase64Urlcontains non-trivial padding logic inpackages/gmail/src/google-mail-relayfile-contract.tsLines 586-592, but the suite only uses unpadded values. Add a case for a padded value such asVGVzdA==and a case for an invalid padding such asVGVzdA=to pin that behavior.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/gmail/src/__tests__/google-mail-relayfile-contract.test.ts` around lines 350 - 363, Extend the base64url validation tests around normalizeGoogleMailRelayfileWriteback with a valid padded value such as VGVzdA== and an invalid single-padding value such as VGVzdA=. Assert the padded input is accepted and the invalid padding is rejected, preserving the existing unpadded and non-base64 coverage.
245-252: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert that the case table covers every declared action.
The suite claims it resolves "every reviewed action", but nothing links
casestoGOOGLE_MAIL_RELAYFILE_ACTIONS. If a new action is added to the contract, this test still passes without a matching case.♻️ Proposed addition
] as const; + assert.deepEqual( + [...new Set(cases.map(({ action }) => action))].sort(), + GOOGLE_MAIL_RELAYFILE_ACTIONS.map(({ action }) => action).slice().sort(), + ); const settingsActions: ReadonlySet<string> = new Set([🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/gmail/src/__tests__/google-mail-relayfile-contract.test.ts` around lines 245 - 252, Update the test around the `cases` table and `GOOGLE_MAIL_RELAYFILE_ACTIONS` to assert that every declared relay-file action has a corresponding case, and that no case uses an undeclared action. Preserve the existing per-case assertions while making the coverage check fail when the contract action set changes without updating `cases`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/gmail/src/google-mail-relayfile-contract.ts`:
- Around line 267-269: Update isDraftLike and its caller in
google-mail-relayfile-contract.ts so the resource is available and send-as ids
containing “@” return false, preventing email aliases from being classified as
drafts. In packages/gmail/src/__tests__/google-mail-relayfile-contract.test.ts
lines 36-57, add coverage for /gmail/send-as/new-hire@example.com.json resolving
to kind: 'canonical' and mapping upsert to update_send_as.
- Around line 621-623: Before merging changes to
resolveGoogleMailRelayfileWriteback, run the full repository verification
command npx turbo build typecheck test and address any failures, including
generated files, declarations, or Gmail package tests.
---
Nitpick comments:
In `@packages/gmail/src/__tests__/google-mail-relayfile-contract.test.ts`:
- Around line 36-57: Extend the Google Mail Relayfile contract tests with
/gmail/send-as/new-hire@example.com.json, asserting it resolves as kind:
'canonical' rather than draft-like and that an upsert for this target maps to
update_send_as. Reuse the existing resolveGoogleMailRelayfileTarget and upsert
mapping test patterns.
- Around line 350-363: Extend the base64url validation tests around
normalizeGoogleMailRelayfileWriteback with a valid padded value such as VGVzdA==
and an invalid single-padding value such as VGVzdA=. Assert the padded input is
accepted and the invalid padding is rejected, preserving the existing unpadded
and non-base64 coverage.
- Around line 245-252: Update the test around the `cases` table and
`GOOGLE_MAIL_RELAYFILE_ACTIONS` to assert that every declared relay-file action
has a corresponding case, and that no case uses an undeclared action. Preserve
the existing per-case assertions while making the coverage check fail when the
contract action set changes without updating `cases`.
In `@packages/gmail/src/google-mail-relayfile-contract.ts`:
- Around line 291-292: Update the regexes in the path-parsing logic around
canonicalMatch and aliasMatch to use GOOGLE_MAIL_RELAYFILE_ROOT instead of
hardcoding /gmail, preserving the existing endpoint and identifier matching
behavior so parsing stays aligned with emitted paths.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 66773c3e-2e95-4a2b-bb81-dd667467b998
📒 Files selected for processing (6)
CHANGELOG.mddocs/writeback-spec-coverage.mdpackages/gmail/package.jsonpackages/gmail/src/__tests__/google-mail-relayfile-contract.test.tspackages/gmail/src/google-mail-relayfile-contract.tspackages/gmail/src/index.ts
|
Addressed the review feedback in 6d0d1f1: canonical-root regexes now use the contract constant; send-as aliases with draft-like local parts stay canonical; padded base64url acceptance/rejection is covered; and the exact-request matrix is asserted against the declared action catalog. |
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
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="packages/gmail/src/google-mail-relayfile-contract.ts">
<violation number="1" location="packages/gmail/src/google-mail-relayfile-contract.ts:270">
P2: Malformed draft-shaped send-as IDs such as `new-hire@` are classified as canonical because this checks only for `@`, allowing writeback to construct an update request for an invalid Gmail ID. Validating the email-shaped ID before returning `false` would preserve draft-like aliases while rejecting malformed targets.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| function isDraftLike(resource: GoogleMailRelayfileResource, id: string): boolean { | ||
| // Send-as creation uses a draft filename, but a canonical send-as id is an | ||
| // email address and may legitimately start with `new`, `draft`, or `temp`. | ||
| if (resource === 'send-as' && id.includes('@')) return false; |
There was a problem hiding this comment.
P2: Malformed draft-shaped send-as IDs such as new-hire@ are classified as canonical because this checks only for @, allowing writeback to construct an update request for an invalid Gmail ID. Validating the email-shaped ID before returning false would preserve draft-like aliases while rejecting malformed targets.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/gmail/src/google-mail-relayfile-contract.ts, line 270:
<comment>Malformed draft-shaped send-as IDs such as `new-hire@` are classified as canonical because this checks only for `@`, allowing writeback to construct an update request for an invalid Gmail ID. Validating the email-shaped ID before returning `false` would preserve draft-like aliases while rejecting malformed targets.</comment>
<file context>
@@ -264,7 +264,10 @@ function isMutableUserLabelId(id: string): boolean {
+function isDraftLike(resource: GoogleMailRelayfileResource, id: string): boolean {
+ // Send-as creation uses a draft filename, but a canonical send-as id is an
+ // email address and may legitimately start with `new`, `draft`, or `temp`.
+ if (resource === 'send-as' && id.includes('@')) return false;
return DRAFT_FILE_RE.test(id);
}
</file context>
| if (resource === 'send-as' && id.includes('@')) return false; | |
| if (resource === 'send-as' && id.includes('@')) { | |
| validEmail(id, 'Google Mail send-as target id'); | |
| return false; | |
| } |
Summary
/gmailwrite targets and fail closed on legacy/google-mailmountsVerification
tsc -p packages/core/tsconfig.jsontsc --noEmit -p packages/gmail/tsconfig.jsontsx --test "packages/gmail/src/**/*.test.ts"(36 passing)prettier --checkon changed filesgit diff --checkReview notes
npx turbo build typecheck testwas not run because this isolated worktree has no installed Turbo binary; the changed adapter package and its dependency typecheck are green.Downstream
After merge and release, Cloud must bump
@relayfile/gmailbefore consuming@relayfile/gmail/google-mail-relayfile-contract. This PR does not enable Gmail writes or alter Nango.