Skip to content

feat(google-appsheet): add Google AppSheet integration#5376

Merged
waleedlatif1 merged 5 commits into
stagingfrom
worktree-google-appsheet-integration
Jul 2, 2026
Merged

feat(google-appsheet): add Google AppSheet integration#5376
waleedlatif1 merged 5 commits into
stagingfrom
worktree-google-appsheet-integration

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Added Google AppSheet integration: 4 tools (find/add/edit/delete rows) against the AppSheet Action API
  • Auth is a static Application Access Key (header ApplicationAccessKey), not OAuth — AppSheet has no OAuth scopes for this API
  • Block supports region selection (global/eu/asia-southeast), an optional Selector expression for Find, and a shared JSON rows field for Add/Edit/Delete
  • Generated docs

Type of Change

  • New feature

Testing

  • tsc --noEmit clean
  • biome check clean
  • blocks/blocks.test.ts (83 tests), serializer + subblock-visibility + params-resolver suites (155 tests) all pass
  • check-bare-icons clean (multi-color brand logo, no theme-safety issue)
  • Verified generated docs page renders expected input/output tables

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@vercel

vercel Bot commented Jul 2, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jul 2, 2026 7:00pm

Request Review

@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Changes are documentation, icons, and nav metadata with no application runtime logic in the diff; risk is stale or misleading docs if they diverge from undeployed block code.

Overview
Adds Google AppSheet as a documented integration: new google_appsheet.mdx, GoogleAppsheetIcon, and google_appsheet in the integrations index and icon map. Docs cover four row CRUD actions against the AppSheet API using an Application Access Key, optional region, and selector/rows JSON fields.

The same change set regenerates or expands many other integration docs so published action/trigger tables match the current blocks— notably new or updated surfaces for Ahrefs (ahrefs_metrics, organic competitors, API param/output reshaping), Amplitude (EU dataResidency, funnels/retention, richer segmentation), Clerk (ban/lock, org membership/invitations, allow/block lists, actor tokens, more webhooks), plus smaller updates across Algolia, Brex, Gong, Hex, Langsmith, Loops, 1Password, SendGrid, SharePoint, Supabase storage, Tailscale, Trello, and others.

Reviewed by Cursor Bugbot for commit 3d8b8ee. Configure here.

Comment thread apps/sim/blocks/blocks/google_appsheet.ts
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a Google AppSheet integration with four operations — Find, Add, Edit, and Delete Rows — backed by the AppSheet Action API using a static Application Access Key. The implementation is well-structured and security issues raised in prior review rounds (region SSRF, appId URL-encoding, non-JSON response bodies) have all been addressed.

  • Tool layer (tools/google_appsheet/): Four symmetric tool files share buildAppsheetActionUrl (region allow-list + URL-encoding of both path segments) and readAppsheetResponseBody (text-first parsing, JSON fallback to { message }) from utils.ts. Unit tests cover the URL builder and response reader, including the SSRF-guard rejection path.
  • Block layer (blocks/blocks/google_appsheet.ts): Region is a dropdown (preventing invalid free-text input), the shared rows JSON field is parsed and array-validated before the tool call, generationType was removed to avoid the json-object vs. array mismatch noted in prior review, and apiKey correctly uses user-only visibility at the tool level.
  • Registry and docs: All four tools and the block are registered in the correct alphabetical positions; a new documentation page and icon are added.

Confidence Score: 5/5

Safe to merge — this is a self-contained new integration with no changes to existing tool paths.

All issues flagged in the prior review rounds have been resolved: region is now validated against an allow-list, both path segments are URL-encoded, and response bodies are read safely as text before JSON parsing. The remaining comment is a minor defensive-validation gap (empty-array rows reaching the AppSheet API) that does not cause data loss or a crash.

No files require special attention beyond the optional empty-rows guard in apps/sim/blocks/blocks/google_appsheet.ts.

Important Files Changed

Filename Overview
apps/sim/tools/google_appsheet/utils.ts Shared helpers: buildAppsheetActionUrl validates region against an allow-list and URL-encodes both path segments; readAppsheetResponseBody safely reads the body as text before attempting JSON.parse — both previously-flagged security issues are resolved.
apps/sim/tools/google_appsheet/utils.test.ts Good unit test coverage for both helpers — valid regions, URL encoding, empty/non-JSON bodies, and the SSRF-guard region-rejection path are all exercised.
apps/sim/tools/google_appsheet/find_rows.ts Find-rows tool correctly sends Rows: [] and places the optional Selector in Properties; uses shared helpers for URL construction and response parsing.
apps/sim/tools/google_appsheet/add_rows.ts Add-rows tool follows identical structure to the other three tools; passes params.rows directly into the request body and normalises the response with data.Rows ?? data.rows ?? [].
apps/sim/tools/google_appsheet/edit_rows.ts Edit-rows tool mirrors the add pattern; documentation correctly notes that each row must include the key column value.
apps/sim/tools/google_appsheet/delete_rows.ts Delete-rows tool is consistent with the others; the empty-body fallback in readAppsheetResponseBody handles AppSheet accounts that return no body on Delete, though rowCount will read 0 in those cases.
apps/sim/tools/google_appsheet/types.ts Type definitions are well-organised with a shared base, per-operation extensions, and a discriminated union GoogleAppsheetResponse used by the block.
apps/sim/blocks/blocks/google_appsheet.ts Block config looks correct: dropdown-gated region prevents invalid values, rows JSON is parsed and array-validated before the tool is called, and generationType was removed. Minor: empty-array rows for Edit/Delete will silently pass the array check and reach the API.
apps/sim/tools/google_appsheet/index.ts Barrel re-exports all four tools; straightforward, no issues.
apps/sim/tools/registry.ts All four AppSheet tools are registered correctly in alphabetical order consistent with the rest of the file.
apps/sim/blocks/registry-maps.ts Block and BlockMeta both registered in BLOCK_REGISTRY and BLOCK_META_REGISTRY; import is in alphabetical order.
apps/docs/content/docs/en/integrations/google_appsheet.mdx New documentation page covering authentication, all four operations, input/output tables, and usage notes; added to meta.json navigation.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as Sim UI (Block)
    participant BP as Block params()
    participant Tool as ToolConfig
    participant Utils as utils.ts
    participant API as AppSheet Action API

    UI->>BP: "{ operation, appId, tableName, region, rows/selector, apiKey }"
    BP->>BP: JSON.parse(rows) + Array.isArray check
    BP-->>Tool: resolved params
    Tool->>Utils: buildAppsheetActionUrl(appId, tableName, region)
    Utils->>Utils: validate region against allow-list
    Utils->>Utils: encodeURIComponent(appId) + encodeURIComponent(tableName)
    Utils-->>Tool: "https://{region}.appsheet.com/api/v2/apps/{appId}/tables/{tableName}/Action"
    Tool->>API: "POST with ApplicationAccessKey header + { Action, Properties, Rows }"
    API-->>Tool: HTTP response
    Tool->>Utils: readAppsheetResponseBody(response)
    Utils->>Utils: "response.text() → JSON.parse (or fallback to { message })"
    Utils-->>Tool: parsed body
    Tool->>Tool: check response.ok, extract data.Rows ?? data.rows ?? []
    Tool-->>UI: "{ success, output: { rows, metadata: { rowCount } } }"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as Sim UI (Block)
    participant BP as Block params()
    participant Tool as ToolConfig
    participant Utils as utils.ts
    participant API as AppSheet Action API

    UI->>BP: "{ operation, appId, tableName, region, rows/selector, apiKey }"
    BP->>BP: JSON.parse(rows) + Array.isArray check
    BP-->>Tool: resolved params
    Tool->>Utils: buildAppsheetActionUrl(appId, tableName, region)
    Utils->>Utils: validate region against allow-list
    Utils->>Utils: encodeURIComponent(appId) + encodeURIComponent(tableName)
    Utils-->>Tool: "https://{region}.appsheet.com/api/v2/apps/{appId}/tables/{tableName}/Action"
    Tool->>API: "POST with ApplicationAccessKey header + { Action, Properties, Rows }"
    API-->>Tool: HTTP response
    Tool->>Utils: readAppsheetResponseBody(response)
    Utils->>Utils: "response.text() → JSON.parse (or fallback to { message })"
    Utils-->>Tool: parsed body
    Tool->>Tool: check response.ok, extract data.Rows ?? data.rows ?? []
    Tool-->>UI: "{ success, output: { rows, metadata: { rowCount } } }"
Loading

Reviews (5): Last reviewed commit: "docs: sync generated integration docs wi..." | Re-trigger Greptile

Comment thread apps/sim/tools/google_appsheet/utils.ts Outdated
Comment thread apps/sim/tools/google_appsheet/find_rows.ts
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a Google AppSheet integration with four operations (Find, Add, Edit, Delete rows) against the AppSheet Action API, using a static ApplicationAccessKey header for auth instead of OAuth.

  • 4 new tools (find_rows, add_rows, edit_rows, delete_rows) share a common URL-builder utility and are registered in the tool/block registries alongside icons, integration JSON, and generated docs.
  • Block config exposes a shared JSON rows field with conditional visibility per operation and a wand-assist prompt; the region is restricted to a dropdown in the UI but not validated in the URL-builder utility.
  • Error handling in all four transformResponse implementations calls response.json() before checking response.ok, which will throw a SyntaxError (instead of a meaningful message) if AppSheet or an intermediary returns a non-JSON error body.

Confidence Score: 3/5

The URL-builder injects a user-supplied region string directly into the hostname without allowlisting, which can redirect requests carrying the API key to an arbitrary host.

The unvalidated region interpolation in buildAppsheetActionUrl is a real credential-leakage path: any caller who can pass a crafted region value bypasses the .appsheet.com host restriction entirely. The four transformResponse implementations all call response.json() before checking response.ok, meaning any non-JSON error body surfaces as a confusing SyntaxError rather than an actionable message. Both issues are present in every operation the integration supports.

apps/sim/tools/google_appsheet/utils.ts needs the region allowlist fix. All four tool files (find_rows.ts, add_rows.ts, edit_rows.ts, delete_rows.ts) need the response.json() / response.ok ordering corrected.

Security Review

  • SSRF / credential leakage via unvalidated region (apps/sim/tools/google_appsheet/utils.ts): The region string is concatenated directly into the URL host without being checked against the three valid values (www, eu, asia-southeast). A crafted value such as evil.com/path# produces the URL https://evil.com/path#.appsheet.com/\u2026, which the HTTP client resolves as host evil.com \u2014 forwarding the ApplicationAccessKey header to an attacker-controlled server. The fix is to allowlist the region before building the host string.

Important Files Changed

Filename Overview
apps/sim/tools/google_appsheet/utils.ts URL builder injects the region parameter into the hostname without validating it against the three allowed values, enabling SSRF/credential-leakage; also appId is not URL-encoded unlike tableName.
apps/sim/tools/google_appsheet/find_rows.ts Calls response.json() before checking response.ok, causing a confusing SyntaxError when the API returns a non-JSON error body; same pattern repeated across all four tool files.
apps/sim/tools/google_appsheet/add_rows.ts Correct Add action body and header construction; shares the response.json() before response.ok issue with the other tool files.
apps/sim/tools/google_appsheet/edit_rows.ts Correct Edit action body; shares the response.json() before response.ok issue.
apps/sim/tools/google_appsheet/delete_rows.ts Correct Delete action body; shares the response.json() before response.ok issue.
apps/sim/blocks/blocks/google_appsheet.ts Block config is well-structured with conditional subblocks and shared rows field; wandConfig.generationType is set to 'json-object' but the expected output is a JSON array.
apps/sim/tools/google_appsheet/types.ts Clean type definitions with a shared base params interface and discriminated union response type; no issues.
apps/sim/tools/registry.ts Four new tools correctly registered in alphabetical order alongside existing Google tools.
apps/sim/blocks/registry-maps.ts Block and meta correctly registered in both BLOCK_REGISTRY and BLOCK_META_REGISTRY.
apps/sim/lib/integrations/integrations.json Integration entry correctly added with all required fields including operations, authType, and tags.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant Block as GoogleAppsheetBlock
    participant Tool as Tool (find/add/edit/delete)
    participant Utils as buildAppsheetActionUrl
    participant API as AppSheet API

    User->>Block: Select operation + provide params
    Block->>Tool: Dispatch to selected tool with params
    Tool->>Utils: buildAppsheetActionUrl(appId, tableName, region)
    Utils-->>Tool: "https://{region}.appsheet.com/api/v2/apps/{appId}/tables/{tableName}/Action"
    Tool->>API: POST with ApplicationAccessKey header + Action body
    API-->>Tool: JSON response with Rows[]
    Tool->>Tool: transformResponse() — parse Rows, build metadata
    Tool-->>Block: "{ rows, metadata: { rowCount } }"
    Block-->>User: Output rows + metadata
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant Block as GoogleAppsheetBlock
    participant Tool as Tool (find/add/edit/delete)
    participant Utils as buildAppsheetActionUrl
    participant API as AppSheet API

    User->>Block: Select operation + provide params
    Block->>Tool: Dispatch to selected tool with params
    Tool->>Utils: buildAppsheetActionUrl(appId, tableName, region)
    Utils-->>Tool: "https://{region}.appsheet.com/api/v2/apps/{appId}/tables/{tableName}/Action"
    Tool->>API: POST with ApplicationAccessKey header + Action body
    API-->>Tool: JSON response with Rows[]
    Tool->>Tool: transformResponse() — parse Rows, build metadata
    Tool-->>Block: "{ rows, metadata: { rowCount } }"
    Block-->>User: Output rows + metadata
Loading

Reviews (2): Last reviewed commit: "feat(google-appsheet): add Google AppShe..." | Re-trigger Greptile

Comment thread apps/sim/tools/google_appsheet/utils.ts
Comment thread apps/sim/tools/google_appsheet/find_rows.ts
Comment thread apps/sim/blocks/blocks/google_appsheet.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit d3c5e10. Configure here.

- 4 tools (find/add/edit/delete rows) against the AppSheet Action API
- API key auth via Application Access Key (no OAuth/scopes needed)
- Block with operation dropdown, region selector, and Selector expression support
- Generated docs
…g and skills

- Guard against empty/non-JSON AppSheet response bodies (Delete may return no body)
- Add wandConfig to the Selector field for AI-assisted expression generation
- Add 3 skills grounded in attested AppSheet/Zapier automation patterns
- Tighten json output descriptions to describe inner shape
…d, validate rows shape

- Reject unrecognized region values instead of interpolating them into the
  request host (a caller could otherwise redirect the Application Access
  Key to an arbitrary domain)
- URL-encode appId, not just tableName, in the Action endpoint path
- Reject non-array Rows input in tools.config.params instead of forwarding
  a single object to the AppSheet Action API
- Drop the mismatched json-object generationType on the rows wand config
  (that enricher appends "must start with { and end with }", which
  conflicts with the JSON-array shape the field expects)
- Add utils.test.ts covering region validation and response-body parsing
@waleedlatif1 waleedlatif1 force-pushed the worktree-google-appsheet-integration branch from d3c5e10 to 5a46dab Compare July 2, 2026 18:48
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 5a46dab. Configure here.

Match the MANUAL-CONTENT convention used by other integration docs
(Airtable, Ahrefs, Google PageSpeed) — an overview of the service, what
the Sim integration lets agents do, and how to get an Application
Access Key.
Regenerate docs for integrations whose tools/blocks changed upstream
without a matching docs regen (ahrefs, algolia, amplitude, brex, clerk,
gong, hex, langsmith, loops, onepassword, sendgrid, sharepoint,
similarweb, supabase, tailscale, trello, vercel, wordpress), plus the
integrations.json catalog.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile review

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3d8b8ee. Configure here.

@waleedlatif1 waleedlatif1 merged commit 10b6bb3 into staging Jul 2, 2026
12 of 13 checks passed
@waleedlatif1 waleedlatif1 deleted the worktree-google-appsheet-integration branch July 2, 2026 18:58
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