feat(nodes): add Gmail tool node (RR-1055)#1333
Conversation
… (RR-1055) Extends the GMAIL spec so the Gmail node can support permanent delete: a 'full' tier granting https://mail.google.com/ and the allowHardDelete flag that gates it. can_write stays scope-derived. Prereq for tool_gmail. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Full Gmail v1 surface as agent tools, modeled on tool_github and gated by the shared GMAIL resolver: - Reads/sync: message_list/get/search, thread_get/list, label_list, draft_list/get, attachment_get, history_list. - Organize (write tier): message_modify, message_batch_modify, label_apply/ remove/create/update/delete. Read-state via the UNREAD label. - Write: message_send (reply-in-thread sets In-Reply-To/References), message_trash/untrash, draft_create/update/send/delete. Send requires the send or full tier. - Permanent delete (gated): message_delete, messages_batchDelete — require allowHardDelete + the full tier; explicit id lists only, capped at 1000. Auth branches on google.authType (service account w/ domain delegation, or user OAuth). Outputs are cleaned shapes, not raw API JSON. Adds a Google SDK mock for ROCKETRIDE_MOCK and unit tests covering each function, gating, reply threading, batch caps, and the services.json field contract. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…-1055) The Google/Microsoft/Slack login button widgets rendered the raw key (e.g. ADDSOURCE.FORMSTEP.LOGINWITHGOOGLEBUTTON) — uppercased by MUI and overflowing — when the addSource.* namespace isn't loaded (as in the VS Code config panel, where the Gmail node first surfaced it). Add a defaultValue to each t() so the label is correct regardless of i18n state, and set textTransform:'none' so it renders in sentence case without clipping. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…nset
defaultValue is ignored because no i18next instance is initialized in the
webview hosts — t() returns the raw key. Detect the key echo and substitute a
literal ('Login with Google'/Microsoft/Slack, 'Authenticated') so the buttons
never render a raw i18n key. Supersedes the prior defaultValue attempt.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a new ChangesGmail Tool Node
Login Button i18n Fallback Fix
Sequence Diagram(s)sequenceDiagram
participant Agent
participant IInstance
participant gmail_client
participant GmailAPI
Agent->>IInstance: message_send(args)
IInstance->>IInstance: _require_write() + _require_send()
alt threadId provided
IInstance->>gmail_client: execute(threads.get metadata)
gmail_client->>GmailAPI: users.threads.get(threadId, format=metadata)
GmailAPI-->>gmail_client: thread with message headers
gmail_client-->>IInstance: In-Reply-To, References headers
end
IInstance->>gmail_client: build_raw_message(to, subject, body, in_reply_to, references)
gmail_client-->>IInstance: base64url raw MIME
IInstance->>gmail_client: execute(messages.send(raw, threadId))
gmail_client->>GmailAPI: users.messages.send(userId=me, body)
GmailAPI-->>gmail_client: sent message
gmail_client-->>IInstance: cleaned message dict
IInstance-->>Agent: result
sequenceDiagram
participant Agent
participant IInstance
participant gmail_client
participant GmailAPI
Agent->>IInstance: message_delete(args)
IInstance->>IInstance: _require_hard_delete()
Note over IInstance: checks allowHardDelete flag AND full tier
IInstance->>gmail_client: execute(messages.delete(messageId))
gmail_client->>GmailAPI: users.messages.delete(userId=me, id=messageId)
GmailAPI-->>gmail_client: 204 empty response
gmail_client-->>IInstance: {}
IInstance-->>Agent: {deleted: messageId}
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
🤖 Internal: Discord sync markerAuto-managed by the Discord notification workflow. Stores the linked Discord message ID. Do not edit or delete. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@nodes/src/nodes/tool_gmail/IInstance.py`:
- Around line 93-101: The _id_list method validates that IDs contain only
non-empty trimmed strings by checking i.strip() in the validation condition, but
returns the original unstripped ids list. This allows whitespace-padded message
IDs to pass validation and then fail downstream in Gmail API calls. Modify the
return statement to strip whitespace from each ID in the list before returning,
ensuring that the returned IDs match what was validated.
In `@nodes/src/nodes/tool_gmail/requirements.txt`:
- Around line 1-4: The requirements.txt file for the tool_gmail node contains
unpinned dependencies (google-api-python-client, google-auth,
google-auth-oauthlib, google-auth-httplib2) which allow vulnerable transitive
versions of idna and protobuf to be installed. Pin these dependencies to tested
versions that resolve the security vulnerabilities: add version constraints to
require idna>=3.15 to fix CVE-2024-3651, and require protobuf>=4.25.8 (or
>=5.29.5 or >=6.31.1 depending on your base version) to fix CVE-2025-4565.
Update each package line in requirements.txt to include the appropriate version
specifier using the format package-name>=version.
In
`@packages/shared-ui/src/components/canvas/components/rjsf-widgets/social-buttons/LoginWithGoogleButton.tsx`:
- Around line 100-108: The label helper function in LoginWithGoogleButton that
handles i18n fallback logic (the function that takes a key and fallback string
and returns the resolved translation or the fallback) is duplicated across
multiple social login button components (Google, Microsoft, Slack). Extract this
label function into a shared utility file or custom hook that can be imported by
all social login button components, then replace the duplicate implementations
with imports from this shared location to ensure consistent fallback behavior
across all providers.
🪄 Autofix (Beta)
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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: fa6ae1e6-9e44-4f3c-8159-b8db4c6b271a
⛔ Files ignored due to path filters (1)
nodes/src/nodes/tool_gmail/gmail.svgis excluded by!**/*.svg
📒 Files selected for processing (19)
nodes/src/nodes/core/google_access.pynodes/src/nodes/tool_gmail/IGlobal.pynodes/src/nodes/tool_gmail/IInstance.pynodes/src/nodes/tool_gmail/README.mdnodes/src/nodes/tool_gmail/__init__.pynodes/src/nodes/tool_gmail/gmail_client.pynodes/src/nodes/tool_gmail/requirements.txtnodes/src/nodes/tool_gmail/services.jsonnodes/test/core/test_google_access.pynodes/test/mocks/google/oauth2/__init__.pynodes/test/mocks/google/oauth2/credentials.pynodes/test/mocks/google/oauth2/service_account.pynodes/test/mocks/googleapiclient/__init__.pynodes/test/mocks/googleapiclient/discovery.pynodes/test/tool_gmail/__init__.pynodes/test/tool_gmail/test_gmail.pypackages/shared-ui/src/components/canvas/components/rjsf-widgets/social-buttons/LoginWithGoogleButton.tsxpackages/shared-ui/src/components/canvas/components/rjsf-widgets/social-buttons/LoginWithMicrosoftButton.tsxpackages/shared-ui/src/components/canvas/components/rjsf-widgets/social-buttons/LoginWithSlackButton.tsx
| def _id_list(args: dict, key: str, op: str) -> list[str]: | ||
| ids = args.get(key) | ||
| if not isinstance(ids, list) or not ids: | ||
| raise ValueError(f'{op}: "{key}" must be a non-empty list of message ids') | ||
| if not all(isinstance(i, str) and i.strip() for i in ids): | ||
| raise ValueError(f'{op}: "{key}" must contain only message-id strings') | ||
| if len(ids) > MAX_BATCH: | ||
| raise ValueError(f'{op}: at most {MAX_BATCH} ids per call (got {len(ids)})') | ||
| return ids |
There was a problem hiding this comment.
Trim IDs before returning from _id_list.
Validation uses i.strip() but the method returns original values, so whitespace-padded IDs pass checks and then fail downstream Gmail calls.
Suggested fix
def _id_list(args: dict, key: str, op: str) -> list[str]:
ids = args.get(key)
if not isinstance(ids, list) or not ids:
raise ValueError(f'{op}: "{key}" must be a non-empty list of message ids')
if not all(isinstance(i, str) and i.strip() for i in ids):
raise ValueError(f'{op}: "{key}" must contain only message-id strings')
+ ids = [i.strip() for i in ids]
if len(ids) > MAX_BATCH:
raise ValueError(f'{op}: at most {MAX_BATCH} ids per call (got {len(ids)})')
return ids🤖 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 `@nodes/src/nodes/tool_gmail/IInstance.py` around lines 93 - 101, The _id_list
method validates that IDs contain only non-empty trimmed strings by checking
i.strip() in the validation condition, but returns the original unstripped ids
list. This allows whitespace-padded message IDs to pass validation and then fail
downstream in Gmail API calls. Modify the return statement to strip whitespace
from each ID in the list before returning, ensuring that the returned IDs match
what was validated.
| google-api-python-client | ||
| google-auth | ||
| google-auth-oauthlib | ||
| google-auth-httplib2 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify current resolved vulnerabilities for this requirements file
python -m pip install -q pip-audit
pip-audit -r nodes/src/nodes/tool_gmail/requirements.txt
# Inspect available versions for flagged transitives
python -m pip index versions idna | sed -n '1,25p'
python -m pip index versions protobuf | sed -n '1,25p'Repository: rocketride-org/rocketride-server
Length of output: 556
🏁 Script executed:
cat -n nodes/src/nodes/tool_gmail/requirements.txtRepository: rocketride-org/rocketride-server
Length of output: 183
🌐 Web query:
google-auth google-api-python-client security vulnerabilities CVE 2024 2025
💡 Result:
Summary (CVE-focused, 2024–2025): 1) google-auth and google-api-python-client do not appear to have widely reported, product-specific CVEs in 2024–2025 in the sources found here. - For google-api-python-client, the only CVE-like item surfaced in results was CVE-2023-34298, which is outside your requested 2024–2025 window and is not clearly tied to the upstream Google library’s security fixes (it appears in a third-party issue tracker context) [1]. - For google-auth, the results found a CVE entry (CVE-2024-26130) for “product=google-auth” via a third-party CVE tracker, but the snippet describes a NULL pointer dereference in cryptography (not a direct, google-auth logic flaw), and the tracker indicates the fix is “resolved in cryptography … 42.0.4” [2]. 2) google-api-python-client / google-auth-library-python have frequent changes (mostly bug/security related) in their official changelogs, but the changelog extracts shown do not enumerate CVE IDs tied specifically to 2024–2025 for these libraries [3][4][5][6]. What you should do in practice (grounded guidance from the sources): - Treat underlying dependencies as the most likely CVE source for this ecosystem. Example: CVE-2024-26130 is reported in a tracker as involving “product=google-auth” but the technical description attributes the bug to cryptography’s PKCS#12 serialization behavior and says it’s resolved in cryptography 42.0.4 [2]. - Keep google-auth-library-python and google-api-python-client updated to the latest patch releases; their projects release frequently and are explicitly positioned as maintained/with security issue handling [7][8]. - Use your own dependency-CVE tooling (SCA) against your exact installed versions; one result for google-api-python-client@2.197.0 showed “No known vulnerabilities detected” by that scanner at scan time, underscoring that the answer is version-dependent [9]. References found in this research (representative): - CVE-2024-26130 tracker entry describing a cryptography NULL pointer dereference (resolved in cryptography 42.0.4) [2]. - Official google-auth-library-python changelog activity in 2024–2025 timeframe (no CVE IDs visible in the provided excerpts) [3][4]. - Official google-api-python-client repository status/maintenance and frequent releases [7][8]. - An external listing for google-api-python-client@2.197.0 reporting no known vulnerabilities at scan time [9].
Citations:
- 1: https://gitee.com/src-openeuler/google-api-python-client/issues/I9LGOF
- 2: https://tuxcare.com/cve-tracker/cve/details/cve-2024-26130/?context=3-0-0-dev0&product=google-auth
- 3: https://github.com/googleapis/google-auth-library-python/blob/main/CHANGELOG.md
- 4: https://github.com/googleapis/google-auth-library-python/blob/HEAD/CHANGELOG.md
- 5: https://github.com/googleapis/google-cloud-python/blob/main/packages/google-auth/CHANGELOG.md
- 6: https://github.com/googleapis/google-auth-library-python/blob/v2.45.0/CHANGELOG.md
- 7: https://github.com/googleapis/google-api-python-client?tab=readme-ov-file
- 8: https://googleapis.github.io/google-api-python-client/
- 9: https://secure.software/pypi/packages/google-api-python-client/vulnerabilities/2.197.0
🌐 Web query:
idna protobuf security vulnerabilities known issues 2024 2025
💡 Result:
In 2024 and 2025, security vulnerabilities were identified in both the Protocol Buffers (protobuf) library and libraries handling Internationalized Domain Names in Applications (IDNA). These issues primarily involve Denial of Service (DoS) and potential logic flaws. Protocol Buffers (protobuf) Vulnerabilities: - CVE-2025-4565: A high-severity DoS vulnerability in the protobuf-python pure-Python backend. Parsing untrusted data containing excessive recursive groups, recursive messages, or SGROUP tags can exceed the Python recursion limit, leading to a crash [1][2]. It affects versions prior to 4.25.8, 5.29.5, and 6.31.1 [1]. - CVE-2024-7254: A high-severity DoS vulnerability in protobuf-java, protobuf-javalite, and protobuf-kotlin. Similar to the Python issue, parsing nested groups as unknown fields, or against map fields, can cause unbounded recursion and stack overflow [3][4]. This affects versions prior to 3.25.5, 4.27.5, and 4.28.2 [3]. - CVE-2024-2410: A critical-severity Use-After-Free (UAF) vulnerability in the C++ implementation of protobuf. It occurs in the JsonToBinaryStream function when parsing JSON from a stream split into specific chunks, potentially leading to arbitrary code execution or crash [5]. It affects versions 4.22.0 through 4.24.x [5]. IDNA Library Vulnerabilities: - Resource Consumption/DoS: - CVE-2024-3651: Identified in the kjd/idna Python library, where specially crafted inputs to idna.encode caused significant resource consumption due to quadratic complexity [6][7]. - CVE-2026-45409: A follow-up issue involving the same kjd/idna library, where the original fix for CVE-2024-3651 could be bypassed using specific payloads, allowing attackers to trigger long processing times [8]. Users are advised to use version 3.15 or later [8]. - Logic/Equivalence Vulnerabilities: - RUSTSEC-2024-0421 (CVE-2024-12224): Found in the Rust idna crate (used by Servo's rust-url). The library accepted Punycode labels that did not produce non-ASCII output, allowing ASCII labels to be masked as punycode. This could lead to host name confusion or privilege escalation in applications relying on host name comparisons [9][10][11]. This was fixed in version 1.0.3 [9][11].
Citations:
- 1: GHSA-8qvm-5x2c-j2w7
- 2: https://nvd.nist.gov/vuln/detail/cve-2025-4565
- 3: GHSA-735f-pc8j-v9w8
- 4: https://nvd.nist.gov/vuln/detail/CVE-2024-7254
- 5: https://nvd.nist.gov/vuln/detail/CVE-2024-2410
- 6: GHSA-jjg7-2v4v-x38h
- 7: https://nvd.nist.gov/vuln/detail/CVE-2024-3651
- 8: GHSA-65pc-fj4g-8rjx
- 9: https://rustsec.org/advisories/RUSTSEC-2024-0421
- 10: https://osv.dev/RUSTSEC-2024-0421
- 11: https://security-tracker.debian.org/tracker/CVE-2024-12224
Pin Gmail node dependencies to prevent vulnerable transitive versions.
These packages are unpinned. Transitive dependencies idna and protobuf have known security vulnerabilities (CVE-2024-3651 in idna, CVE-2025-4565 in protobuf-python). Lock tested versions so installs are reproducible and auditable. At minimum:
- Require
idna>=3.15(fixes CVE-2024-3651 and CVE-2026-45409) - Require
protobuf>=4.25.8(or>=5.29.5or>=6.31.1depending on your base version)
🧰 Tools
🪛 OSV Scanner (2.3.8)
[MEDIUM] 1-1: idna 3.9.0: undefined
(PYSEC-2026-215)
[MEDIUM] 1-1: idna 3.9.0: Internationalized Domain Names in Applications (IDNA): Specially crafted inputs to idna.encode() can bypass CVE-2024-3651 fix
[HIGH] 1-1: protobuf 4.25.9: protobuf affected by a JSON recursion depth bypass
🤖 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 `@nodes/src/nodes/tool_gmail/requirements.txt` around lines 1 - 4, The
requirements.txt file for the tool_gmail node contains unpinned dependencies
(google-api-python-client, google-auth, google-auth-oauthlib,
google-auth-httplib2) which allow vulnerable transitive versions of idna and
protobuf to be installed. Pin these dependencies to tested versions that resolve
the security vulnerabilities: add version constraints to require idna>=3.15 to
fix CVE-2024-3651, and require protobuf>=4.25.8 (or >=5.29.5 or >=6.31.1
depending on your base version) to fix CVE-2025-4565. Update each package line
in requirements.txt to include the appropriate version specifier using the
format package-name>=version.
Source: Linters/SAST tools
| // i18n is not initialized in every host (e.g. the VS Code webview). When a key | ||
| // doesn't resolve, t() returns the key itself — fall back to a literal so the | ||
| // button never shows a raw key. | ||
| const label = (key: string, fallback: string): string => { | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const value = t(key as any) as string; | ||
| return value && value !== key ? value : fallback; | ||
| }; | ||
| const text = authenticated ? label('addSource.formStep.authenticated', 'Authenticated') : label('addSource.formStep.loginWithGoogleButton', 'Login with Google'); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consolidate duplicated i18n fallback helper across social login buttons.
The same label(key, fallback) logic is now repeated in Google/Microsoft/Slack buttons. Extracting it into a shared utility/hook will reduce drift and keep fallback behavior consistent across providers.
🤖 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/shared-ui/src/components/canvas/components/rjsf-widgets/social-buttons/LoginWithGoogleButton.tsx`
around lines 100 - 108, The label helper function in LoginWithGoogleButton that
handles i18n fallback logic (the function that takes a key and fallback string
and returns the resolved translation or the fallback) is duplicated across
multiple social login button components (Google, Microsoft, Slack). Extract this
label function into a shared utility file or custom hook that can be imported by
all social login button components, then replace the duplicate implementations
with imports from this shared location to ensure consistent fallback behavior
across all providers.
|
Closing in favour of a consolidated PR (#1334) that includes this feature plus the Google user-OAuth broker wiring (RR-1142) and fixes discovered during integration testing (OAuth scope forwarding, agent_langchain JSON parser). |
Summary
tool_gmailnode exposing the Gmail v1 API as agent tools: read/search/organize mail, manage labels and drafts, send (incl. in-thread replies), and gated permanent delete.fullaccess tier +allowHardDeletegate to the shared Google access/scope resolver; hard-delete requires bothfulltier and the gate.Type
feature
Testing
./builder testpassesChecklist
Related Issues
Closes RR-1055
Summary by CodeRabbit
Release Notes
New Features
Style