Skip to content

Add experimental Google Workspace Gmail read#2052

Open
benjaminshafii wants to merge 1 commit into
devfrom
feature/google-workspace-experimental-scopes-clean
Open

Add experimental Google Workspace Gmail read#2052
benjaminshafii wants to merge 1 commit into
devfrom
feature/google-workspace-experimental-scopes-clean

Conversation

@benjaminshafii
Copy link
Copy Markdown
Member

Summary

  • Add experimental Google Workspace scopes for Gmail read and Calendar event write.
  • Add Gmail latest/read/download actions that can return Gmail attachments as downloadable chat file parts.
  • Update Google Workspace settings copy to warn that experimental Gmail read and Calendar write require your own OAuth credentials for now and may be removed.
  • Make chat file cards downloadable and update Google Workspace OAuth docs.

Verification

  • PASS: pnpm --filter openwork-server test src/extensions/google-workspace.test.ts
  • PASS: pnpm --filter openwork-server typecheck
  • PASS: pnpm --filter @openwork/app typecheck
  • FAIL (baseline/unrelated): pnpm --filter openwork-server test fails with existing workspace bootstrap/import/reload expectations, Bun better-sqlite3 unsupported loading, and serve-node stream error.

Daytona E2E

  • Started Electron sandbox from feature/google-workspace-experimental-scopes and confirmed real Electron UA.
  • Created a local workspace in the app.
  • Opened Settings -> Extensions -> Google Workspace and verified the experimental Gmail read / Calendar write cards, own-OAuth warning, and client ID field.
  • Verified the running server action registry includes calendar_create_event, gmail_get_latest_message, gmail_read_message, and gmail_download_attachment.
  • PASS in Daytona: pnpm --filter openwork-server test src/extensions/google-workspace.test.ts.
  • Live Google OAuth/Gmail API flow was not run because no Google OAuth credentials were available in the sandbox.

Recording: https://8090-fugzd4hvnd9ibvvm.daytonaproxy01.net/recordings/google-workspace-experimental-scopes.mp4

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Jun 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openwork-app Ready Ready Preview, Comment Jun 2, 2026 6:42am
openwork-den Ready Ready Preview, Comment Jun 2, 2026 6:42am
openwork-den-worker-proxy Ready Ready Preview, Comment Jun 2, 2026 6:42am
openwork-landing Ready Ready Preview, Comment, Open in v0 Jun 2, 2026 6:42am

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 7 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/server/src/extensions/google-workspace.ts">

<violation number="1" location="apps/server/src/extensions/google-workspace.ts:730">
P2: Gmail body extraction does not skip attachment parts, so text attachments can be returned as the email body.</violation>
</file>

<file name="apps/app/src/react-app/domains/settings/google-workspace-config.tsx">

<violation number="1" location="apps/app/src/react-app/domains/settings/google-workspace-config.tsx:251">
P2: The new experimental-scope reconnect flow warns users to use their own OAuth credentials, but the client ID input is hidden for already configured accounts, so affected users cannot update credentials from this settings panel.</violation>
</file>

<file name="apps/app/src/components/chat/message-list.tsx">

<violation number="1" location="apps/app/src/components/chat/message-list.tsx:151">
P1: Attachment downloads trust unvalidated URLs; unsafe schemes can be executed when the file card is clicked.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

function downloadFilePart(part: FileUIPart, title: string) {
if (!part.url) return
const anchor = document.createElement("a")
anchor.href = part.url
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Attachment downloads trust unvalidated URLs; unsafe schemes can be executed when the file card is clicked.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/components/chat/message-list.tsx, line 151:

<comment>Attachment downloads trust unvalidated URLs; unsafe schemes can be executed when the file card is clicked.</comment>

<file context>
@@ -144,36 +145,56 @@ interface FileMessageProps {
+function downloadFilePart(part: FileUIPart, title: string) {
+  if (!part.url) return
+  const anchor = document.createElement("a")
+  anchor.href = part.url
+  anchor.download = part.filename || title || "download"
+  anchor.rel = "noopener noreferrer"
</file context>

Comment on lines +730 to +731
if (mimeType === "text/plain") return decodeGmailText(data);
if (mimeType === "text/html" && !html) html = decodeGmailText(data);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Gmail body extraction does not skip attachment parts, so text attachments can be returned as the email body.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/server/src/extensions/google-workspace.ts, line 730:

<comment>Gmail body extraction does not skip attachment parts, so text attachments can be returned as the email body.</comment>

<file context>
@@ -500,6 +689,222 @@ async function googleWorkspaceCreateDraft(config: ServerConfig, args: Record<str
+    const data = readStringField(body, "data");
+    if (!data) continue;
+    const mimeType = readStringField(part, "mimeType");
+    if (mimeType === "text/plain") return decodeGmailText(data);
+    if (mimeType === "text/html" && !html) html = decodeGmailText(data);
+  }
</file context>
Suggested change
if (mimeType === "text/plain") return decodeGmailText(data);
if (mimeType === "text/html" && !html) html = decodeGmailText(data);
const filename = readStringField(part, "filename");
if (filename) continue;
if (mimeType === "text/plain") return decodeGmailText(data);
if (mimeType === "text/html" && !html) html = decodeGmailText(data);

<ShieldCheck />
<AlertTitle>Reconnect for experimental scopes</AlertTitle>
<AlertDescription>
Gmail read and Calendar write are experimental, only work with your own Google OAuth credentials for now, and may be removed. Reconnect this account to request the new scopes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The new experimental-scope reconnect flow warns users to use their own OAuth credentials, but the client ID input is hidden for already configured accounts, so affected users cannot update credentials from this settings panel.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/app/src/react-app/domains/settings/google-workspace-config.tsx, line 251:

<comment>The new experimental-scope reconnect flow warns users to use their own OAuth credentials, but the client ID input is hidden for already configured accounts, so affected users cannot update credentials from this settings panel.</comment>

<file context>
@@ -218,7 +239,17 @@ function GoogleWorkspaceConfig({ openworkServerClient, hostOpenworkServerClient,
+          <ShieldCheck />
+          <AlertTitle>Reconnect for experimental scopes</AlertTitle>
+          <AlertDescription>
+            Gmail read and Calendar write are experimental, only work with your own Google OAuth credentials for now, and may be removed. Reconnect this account to request the new scopes.
+          </AlertDescription>
         </Alert>
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant