Skip to content

fix(integrations): harden jira, jsm, ashby, google drive, slack, confluence, notion#4345

Merged
waleedlatif1 merged 17 commits intostagingfrom
waleedlatif1/jira-validate
Apr 30, 2026
Merged

fix(integrations): harden jira, jsm, ashby, google drive, slack, confluence, notion#4345
waleedlatif1 merged 17 commits intostagingfrom
waleedlatif1/jira-validate

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

@waleedlatif1 waleedlatif1 commented Apr 29, 2026

Summary

Audit and harden multiple integrations against API contracts, input validation, and error handling.

Jira (largest scope)

  • NaN guards on timeSpentSeconds in worklog tools
  • JSON.parse try/catch on internal /api/tools/jira/{write,update} responses (handles HTML 5xx from proxies)
  • Domain normalization (strip leading https://) — fixes silent fallback to wrong site
  • JQL injection prevention via project key regex validation in bulk_read
  • ADF helper consolidation (toAdf across comments/links/transitions)
  • Migrated to /search/jql nextPageToken pagination (deprecated /search startAt)
  • Defensive .trim() on ID path params; encodeURIComponent on watcher account IDs
  • resolveAssigneeAccountId helper; parent-as-object wrapping; summary fallback
  • New read-bulk block operation; removed silent read → bulk_read fallback
  • Restored total field (always null at runtime) to preserve TS contract

Other integrations

  • JSM: customer/organization route validation
  • Ashby: 30+ tools — output normalization, types cleanup
  • Google Drive: tighter response handling across read/write/share
  • Slack: types + tool fixes (canvas, reactions, messaging, members)
  • Confluence: update tool + types
  • Docs: regenerated .mdx for all touched integrations

Test plan

  • Run a Jira workflow: search, read, write, update, comment, worklog, transition, watcher
  • Verify worklog accepts numeric and human-readable durations without NaN
  • Verify domain entered as https://x.atlassian.net resolves to correct cloudId
  • JSM customer + organization flows
  • Ashby candidate/application/job flows
  • Google Drive copy/share/list/permissions
  • Slack message + canvas + reactions
  • Confluence update

…, slack, confluence, notion

Audit and fix contract drift, input validation, and error handling across integrations:

- Jira: NaN guards on worklog seconds, JSON.parse try/catch on internal API responses,
  domain normalization (strip leading https://), JQL injection prevention via project
  key validation, ADF helper consolidation, /search/jql nextPageToken pagination,
  defensive .trim() on ID path params, encodeURIComponent on watcher account IDs,
  resolveAssigneeAccountId helper, parent-as-object wrapping, summary fallback,
  add read-bulk operation. Restored total field (always null) to preserve contract.
- JSM: customer/organization route validation
- Ashby: types and tool output cleanup across all 30+ tools
- Google Drive: tighter response handling across read/write/share tools
- Slack: types and tool fixes (canvas, reactions, messaging, members)
- Confluence: update tool and types
- Docs: regenerated mdx for all touched integrations
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 30, 2026 1:49am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 29, 2026

PR Summary

Medium Risk
Touches multiple production integration routes and request/response contracts (pagination, endpoint selection, and validation), which could impact existing workflows if any behavior changes were relied upon. Changes are mostly defensive and additive, but require careful regression testing against real third-party API responses.

Overview
Hardens Atlassian API interactions across Jira/JSM/Confluence by tightening input validation and pagination, improving error handling, and aligning requests with API expectations. Jira bulk issue reads now validate/sanitize issue keys, JQL escaping is hardened, pagination switches to nextPageToken, notifyUsers is handled explicitly, parent issue handling is normalized, and worklog time inputs reject non-positive/NaN values.

Confluence space/comment/property operations are made more robust: comment update/delete auto-detects footer vs inline comment endpoints, page property updates can auto-fetch the current version when not provided, and space update/delete uses the REST v1 space-key endpoint and surfaces long-task IDs/links on deletion.

Expands tool surface + docs/UX: Google Drive adds search, get_content, move, and untrash operations (with new block UI params and integration catalog updates); Slack list operations gain cursor pagination and update_view enforces an ID; Ashby adds new candidate/note fields and list filters (created/open/closed timestamps, job board/job expansion, include deactivated/archived, etc.) and standardizes auth/error helpers. Corresponding .mdx tool docs are updated to reflect these contract changes (including removing/adjusting deprecated fields like JSM emails and Ashby job/user output fields).

Reviewed by Cursor Bugbot for commit 952d1a9. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 29, 2026

Greptile Summary

This PR audits and hardens seven integrations across ~104 files, with the broadest scope on Jira. The changes are generally well-considered: NaN guards on worklog inputs, defensive JSON.parse try/catch on proxy responses, domain normalization, JQL injection prevention via project-key regex, and migration to the newer /search/jql pagination API.

  • P1 — bulk_read.ts pagination: The break on line 133 fires before the page-token assignment on line 134, leaving the cursor stale on the final page of a multi-page fetch and causing isLast to evaluate incorrectly.

Confidence Score: 4/5

Safe to merge after the stale-cursor bug in bulk_read.ts is resolved.

One P1 logic bug in bulk_read.ts (stale cursor causes incorrect isLast on multi-page results). All other changes are clean hardening with no introduced regressions found.

apps/sim/tools/jira/bulk_read.ts — stale pagination cursor on the terminal break.

Important Files Changed

Filename Overview
apps/sim/tools/jira/bulk_read.ts New jira_bulk_read tool with nextPageToken pagination; stale-cursor bug makes isLast incorrect on final multi-page fetch.
apps/sim/tools/jira/utils.ts Adds normalizeDomain, normalizeJiraWorklogTimestamp, toAdf helpers; exports made public; clean refactor.
apps/sim/tools/jira/write.ts Added JSON.parse try/catch for proxy 5xx HTML responses; parent field now correctly wrapped as {id} or {key} object.
apps/sim/tools/jira/update.ts Added JSON.parse try/catch for non-JSON responses; otherwise clean.
apps/sim/tools/jira/add_worklog.ts NaN guard added for timeSpentSeconds; toAdf helper used for comment body; timestamp normalized.
apps/sim/tools/jira/search_issues.ts total field fixed to always return null; isLast derivation improved; minor description update.
apps/sim/app/api/tools/jira/issues/route.ts Issue key regex validation added; pagination migrated from startAt to nextPageToken; escapeJql now escapes backslashes.
apps/sim/app/api/tools/jira/update/route.ts .json().catch defensive fallback added; notifyUsers ternary now handles explicit true; summaryValue added as fallback in output.
apps/sim/app/api/tools/jsm/organization/route.ts Added positive-integer guard for organizationId before the Atlassian request; clean improvement.
apps/sim/tools/confluence/update.ts Removed version param from tool definition; route handler now auto-increments version; body sends {value} which route wraps with representation: storage.
apps/sim/tools/google_drive/share.ts moveToNewOwnersRoot now gated on transferOwnership; ownership transfers always send sendNotificationEmail=true.
apps/sim/tools/slack/canvas.ts canvas_id fallback restored to data.id; channel and title fields removed from output.
apps/sim/tools/slack/list_members.ts Added cursor pagination param and nextCursor output field; channel trimmed.
apps/sim/tools/jira/assign_issue.ts resolveAssigneeAccountId helper correctly maps empty/null/special strings; .trim() on issueKey.

Sequence Diagram

sequenceDiagram
    participant Caller
    participant BulkRead as jira_bulk_read
    participant Atlassian as Atlassian OAuth Resources
    participant JiraAPI as Jira search/jql

    Caller->>BulkRead: invoke(domain, projectId, accessToken)
    BulkRead->>Atlassian: GET accessible-resources
    Atlassian-->>BulkRead: list of sites with IDs
    BulkRead->>JiraAPI: GET page 1
    JiraAPI-->>BulkRead: issues + pagination token
    alt More pages available
        BulkRead->>JiraAPI: GET page 2 using token
        JiraAPI-->>BulkRead: issues + isLast=true
        Note over BulkRead: BUG: break fires before token is updated, output carries stale token, isLast evaluates to false
    end
    BulkRead-->>Caller: issues + incorrect pagination state
Loading

Comments Outside Diff (1)

  1. apps/sim/tools/jira/bulk_read.ts, line 133-134 (link)

    P1 Stale pagination cursor makes isLast wrong on the final page

    When the loop breaks because pageData.isLast is true or pageData.nextPageToken is absent, the break on line 133 fires before the assignment on line 134 executes. So on a two-page fetch the cursor variable still holds the value used to reach the final page rather than being cleared. The output at line 168-169 evaluates isLast: !nextPageToken against this stale value, returning isLast: false and a non-null cursor even though all issues have been consumed. Any caller driving incremental reads off these fields will re-request the already-consumed last page.

    The fix is to run the assignment before evaluating the terminal condition, so the cursor reflects the final page state before the break.

Reviews (8): Last reviewed commit: "fix(jira): quote project key in bulk_rea..." | Re-trigger Greptile

Comment thread apps/sim/tools/slack/canvas.ts Outdated
Comment thread apps/sim/app/api/tools/jsm/customers/route.ts
Comment thread apps/sim/tools/google_drive/copy.ts
Comment thread apps/sim/blocks/blocks/ashby.ts
Comment thread apps/sim/blocks/blocks/ashby.ts Outdated
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Address greptile review on PR #4345: instead of silently dropping
`emails` and falling through to list-customers, return a 400 telling
the caller to use `accountIds`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
waleedlatif1 and others added 2 commits April 29, 2026 15:28
Address greptile review on PR #4345: when Google Drive returns a non-JSON
error body, surface the response status/statusText so failures are
diagnosable instead of falling through to a generic message.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The update_candidate tool reads params.websiteUrl directly; mapping it
to result.website added a confusing dead field. The websiteUrl subBlock
auto-passes through with the matching name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`mimeType`, `query`, and `pageSize` canonical IDs collided with existing
subBlock IDs in the same block (failing the canonical-param validation
test). Drop the canonicalParamId from search/get_content single-input
fields and route them to tool params explicitly in tools.config.params.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/lib/workflows/migrations/subblock-migrations.ts
The candidate-id filter was reintroduced as a valid Ashby subBlock, but
the migration map still rewrote it to _removed_filterCandidateId on every
workflow load, silently breaking the field. Drop the entry so user values
persist.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 5ab87a9. Configure here.

Restore three fields that exist in Ashby's API responses but were dropped
during the recent refactor: applicationLimitCalloutHtml on /jobPosting.info,
compensation on /job.info (and add the `compensation` expand), and managerId
on /user.list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/blocks/blocks/ashby.ts Outdated
Comment thread apps/sim/app/api/tools/confluence/comment/route.ts
Same shared-target hazard as the prior fix: offerApplicationId maps to
result.applicationId without an operation guard, so a stale value from
list_offers could overwrite the active applicationId on get_application,
change_application_stage, or list_interviews.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/blocks/blocks/ashby.ts
Ashby's /location.list accepts includeArchived per the API docs, and the
docs page already documents the toggle for list_locations. Add the missing
operation value so the toggle renders.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/blocks/blocks/ashby.ts
Comment thread apps/sim/app/api/tools/jira/update/route.ts
Block now distinguishes true/false/undefined for notifyUsers, but the route
collapsed true and undefined into a no-param request. Forward the explicit
true intent so it survives any future API default change or proxy override.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Comment thread apps/sim/app/api/tools/jira/issues/route.ts
Comment thread apps/sim/app/api/tools/confluence/space/route.ts
Comment thread apps/sim/lib/workflows/migrations/subblock-migrations.ts
The alphanumeric regex check above already blocks injection, but quoting
the project key matches the pattern used elsewhere (issues/route.ts) and
hardens the path against future regex changes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 952d1a9. Configure here.

@waleedlatif1 waleedlatif1 merged commit 0c69302 into staging Apr 30, 2026
14 checks passed
waleedlatif1 added a commit that referenced this pull request Apr 30, 2026
…luence, notion (#4345)

* fix(integrations): validate and harden jira, jsm, ashby, google drive, slack, confluence, notion

Audit and fix contract drift, input validation, and error handling across integrations:

- Jira: NaN guards on worklog seconds, JSON.parse try/catch on internal API responses,
  domain normalization (strip leading https://), JQL injection prevention via project
  key validation, ADF helper consolidation, /search/jql nextPageToken pagination,
  defensive .trim() on ID path params, encodeURIComponent on watcher account IDs,
  resolveAssigneeAccountId helper, parent-as-object wrapping, summary fallback,
  add read-bulk operation. Restored total field (always null) to preserve contract.
- JSM: customer/organization route validation
- Ashby: types and tool output cleanup across all 30+ tools
- Google Drive: tighter response handling across read/write/share tools
- Slack: types and tool fixes (canvas, reactions, messaging, members)
- Confluence: update tool and types
- Docs: regenerated mdx for all touched integrations

* fix(ashby): add subblock migrations for removed expand form definition fields

* fix(slack): restore canvas_id fallback to data.id for backwards compat

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(jsm): explicit 400 when deprecated `emails` param is sent

Address greptile review on PR #4345: instead of silently dropping
`emails` and falling through to list-customers, return a 400 telling
the caller to use `accountIds`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(google_drive): include HTTP status in fallback error messages

Address greptile review on PR #4345: when Google Drive returns a non-JSON
error body, surface the response status/statusText so failures are
diagnosable instead of falling through to a generic message.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): drop stray websiteUrl→website remap for update_candidate

The update_candidate tool reads params.websiteUrl directly; mapping it
to result.website added a confusing dead field. The websiteUrl subBlock
auto-passes through with the matching name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(google_drive): rename canonical params to avoid subBlock ID clash

`mimeType`, `query`, and `pageSize` canonical IDs collided with existing
subBlock IDs in the same block (failing the canonical-param validation
test). Drop the canonicalParamId from search/get_content single-input
fields and route them to tool params explicitly in tools.config.params.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): remove filterCandidateId from removed-subblock migrations

The candidate-id filter was reintroduced as a valid Ashby subBlock, but
the migration map still rewrote it to _removed_filterCandidateId on every
workflow load, silently breaking the field. Drop the entry so user values
persist.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): restore documented response fields dropped during refactor

Restore three fields that exist in Ashby's API responses but were dropped
during the recent refactor: applicationLimitCalloutHtml on /jobPosting.info,
compensation on /job.info (and add the `compensation` expand), and managerId
on /user.list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* correctness

* updated types

* fix(ashby): gate operation-specific param mappings to prevent stale overwrites

Multiple subBlocks share the same target tool param (createdAt is set by
appCreatedAt/candidateCreatedAt/noteCreatedAt; candidateId by appCandidateId/
filterCandidateId). Because subBlock values persist across operation switches,
a stale value from a prior operation could silently overwrite the correct one.
Guard each mapping with an explicit operation check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): gate offerApplicationId mapping by operation

Same shared-target hazard as the prior fix: offerApplicationId maps to
result.applicationId without an operation guard, so a stale value from
list_offers could overwrite the active applicationId on get_application,
change_application_stage, or list_interviews.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): include list_locations in includeArchived condition

Ashby's /location.list accepts includeArchived per the API docs, and the
docs page already documents the toggle for list_locations. Add the missing
operation value so the toggle renders.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(jira): forward explicit notifyUsers=true query param on issue update

Block now distinguishes true/false/undefined for notifyUsers, but the route
collapsed true and undefined into a no-param request. Forward the explicit
true intent so it survives any future API default change or proxy override.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(jira): quote project key in JQL to defend against injection

* fix(jira): quote project key in bulk_read JQL for defense in depth

The alphanumeric regex check above already blocks injection, but quoting
the project key matches the pattern used elsewhere (issues/route.ts) and
hardens the path against future regex changes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/jira-validate branch April 30, 2026 21:50
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