Skip to content

feat(netsuite): add Oracle NetSuite integration - #6476

Merged
waleedlatif1 merged 11 commits into
stagingfrom
feat/oracle-netsuite-integration
Aug 13, 2026
Merged

feat(netsuite): add Oracle NetSuite integration#6476
waleedlatif1 merged 11 commits into
stagingfrom
feat/oracle-netsuite-integration

Conversation

@BillLeoutsakosvl346

@BillLeoutsakosvl346 BillLeoutsakosvl346 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add an Oracle NetSuite block with 27 explicit SuiteTalk REST operations for records, metadata, SuiteQL, SuiteAnalytics datasets, homogeneous async batches, and async job inspection.
  • Store the SuiteTalk URL, Client ID, Certificate ID, and private key once in a reusable netsuite-service-account credential; tools receive only a short-lived access token and normalized SuiteTalk origin.
  • Add bounded record-type and known-job async-task selectors with Advanced manual fallbacks, generated metadata/docs, setup guidance, templates, skills, and catalog entries.
  • Exclude RESTlets, arbitrary API requests, triggers, and an unverified dataset picker.

Architecture record

This branch is rebased on staging commit cc7f005b3ae1183a502d258320a54b4d0fab2d61.

  • Primary UX reference: Snowflake. Every block selects one reusable credential, and discovery follows the direct block → selector provider → typed route → authorized credential resolution → provider-tool flow.
  • Credential lifecycle references: Salesforce, Box, Zoho Desk, and Zoom. NetSuite uses the existing client-credential service-account family because Oracle requires certificate-backed JWT signing and short-lived token minting; Snowflake's stored-PAT backend would be incorrect.
  • Selector references: Snowflake and Zoho Desk. Record types are bounded to 1,000 unique options and fail closed rather than returning a partial catalog. Async tasks are bounded to 100 and validated against the selected SuiteTalk origin and requested job. Advanced mode supports manual values.
  • Credential reuse: the first, second, tenth, or any later NetSuite block can select the same stored credential. Workflow state stores only the credential ID; signing material and bearer tokens stay server-side.
  • Provider-specific transport: Oracle-specific status/body contracts, validated Location headers, async idempotency replay, bounded JSON admission, cancellation, deadlines, and error redaction remain in the NetSuite tool layer because the generic executor cannot represent the documented HTTP 400 idempotent-replay success.
  • Persistence: NetSuite has not shipped, so no NetSuite workflow migration is included. No legacy NetSuite secret schema is treated as released state.
  • Shared extension points: descriptor-selected certificateId, the netsuite-service-account provider registration, selector registry/context entries, API-route baseline bookkeeping, and the handwritten service-account-doc allowlist. No generic executor, selector component, docs parser, credential-deletion behavior, canonical-mode behavior, or NetSuite application layer was added.

Final audit fixes

  • Record-type discovery no longer silently slices catalogs above 1,000 unique entries. It bounds the deduplicated collection during traversal and returns the route's safe provider-response failure instead of partial options.
  • X-NetSuite-PropertyNameValidation: error is now limited to /services/rest/record/ request bodies. SuiteQL sends only its documented Prefer: transient behavior plus ordinary JSON/authentication headers.
  • The executable Oracle matrix now proves the exact ordinary Get Record expand query while retaining its explicitly live-unverified status because current Oracle references conflict.

Validation

  • Focused NetSuite, selector-route, minter, credential, auth, context, and migration suite: 16 files, 331/331 tests passed.
  • Full repository test run: 16/16 tasks passed; 1,851 passing files and 24,706 passing tests (2 files and 30 tests skipped).
  • Monorepo type-check: 23/23 tasks passed.
  • Monorepo check-only lint: 23/23 tasks passed.
  • Tool metadata: 4,613 tools in sync; integration catalog: 239 integrations in sync.
  • Strict API validation: 1,106/1,106 routes Zod-backed with the boundary baseline enforced.
  • Tool-request, tool-registry, client, monorepo-boundary, route-verb, migration-safety, and docs-parser checks passed.
  • NetSuite canvas coverage: 27/27 operations; global canvas coverage: 4,826/4,826 operations.
  • Tool metadata and docs generation were rerun. Deterministic unrelated generator formatting/icon drift was discarded; committed metadata, catalog, and documentation checks remain synchronized.
  • git diff --check and the focused four-file Biome check passed.
  • A final read-only validate-integration and memory-load pass used the complete integration_feedback.md, reviewed every branch-changed subsystem, current repository precedents, and current official Oracle evidence. No additional confirmed NetSuite-local defect was found.

Merge dependency: shared credential collision

Do not merge this PR until the separate shared credential-creation fix lands and this branch is rebased onto it.

Today, creating a second secret-backed service account with the same provider and display name can return the existing credential instead of rejecting the newly verified secret material. For NetSuite, two valid certificate/entity/role mappings for one account receive the same default display name, so the second mapping can silently select the first credential and execute with the wrong role. This is a generic credential-orchestration defect affecting multiple service-account families and is intentionally not patched inside this integration PR. The shared fix should return a conflict for fresh-secret collisions while preserving explicitly supported exact-ID replay behavior; after it lands, NetSuite must verify the same-name two-mapping journey returns HTTP 409.

Live limitations

No NetSuite credential was available, so real OAuth certificate mappings, account/role permissions, production and sandbox discovery, NetSuite 2026.1 feature availability, mutations, async polling/result variants, and account-specific record/dataset schemas remain live-unverified. Oracle's current create-form guide names expand as a GET response query parameter, while the 2026.1 Record API Browser omits it from ordinary singular GET; that behavior still needs a sandbox probe. No destructive live calls were attempted.

Type of change

  • Feature

Checklist

  • Code follows project style guidelines
  • Self-reviewed and independently audited
  • 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)

@vercel

vercel Bot commented Aug 9, 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 Aug 13, 2026 10:23pm

Request Review

@cursor

cursor Bot commented Aug 9, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Touches certificate-based auth, encrypted signing keys, token minting/caching, and broad ERP record mutation APIs; PR notes a separate shared fix is needed before merge when two mappings share the same display name.

Overview
Introduces Oracle NetSuite as a new integration: workflows connect through a reusable netsuite-service-account credential (account SuiteTalk URL, Client ID, Certificate ID, PEM private key). The platform signs Oracle’s JWT client assertion, validates with a real token exchange, encrypts key material, and at runtime mints short-lived bearer tokens plus a normalized SuiteTalk origin for tools—same reusable-credential pattern as Snowflake/Salesforce client-credentials.

Workflow surface: a NetSuite block with 27 operations (record CRUD/upsert, subresources, forms, select options, attach/detach, actions, transforms, SuiteQL, SuiteAnalytics datasets, async batches, job status/results, metadata, governance). Bounded pickers (record types up to 1,000, async tasks up to 100) go through a new /api/tools/netsuite/objects route with strict link validation; Advanced mode keeps manual IDs.

Platform wiring: certificateId on credential create/update, token responses that include instanceUrl, selector registry entries, block registry, integration catalog, icons, and integration docs (netsuite + netsuite-service-account). NetSuite-specific HTTP behavior stays in the NetSuite tool layer rather than the generic executor.

Reviewed by Cursor Bugbot for commit eb21fe4. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds an Oracle NetSuite integration with certificate-backed service-account authentication, selectors, documentation, and 27 SuiteTalk operations.

  • Registers the NetSuite block, tools, generated metadata, icons, and integration catalog entries.
  • Adds reusable credential storage, token minting, SuiteTalk request validation, bounded payload handling, and async-job support.
  • Adds typed selector routes for record types and known async tasks, with manual fallbacks.
  • Adds focused tests and setup documentation for credentials and supported operations.

Confidence Score: 5/5

The PR appears safe to merge from the reviewed follow-up findings.

No blocking failure remains from the previously reported token-cache or import-path issues.

Important Files Changed

Filename Overview
apps/sim/lib/oauth/credential-service.ts Extends reusable service-account token resolution and safely isolates cached credentials by credential ID and encrypted-secret rotation fingerprint.
apps/sim/lib/credentials/client-credential-accounts/minters/netsuite.ts Implements certificate-backed NetSuite client-credential assertion signing and token exchange.
apps/sim/tools/netsuite/utils.ts Provides shared SuiteTalk validation, request execution, response contracts, payload limits, timeout handling, and error sanitization.
apps/sim/blocks/blocks/netsuite.ts Defines the NetSuite block’s 27 operations, inputs, selectors, tool mappings, and outputs.
apps/sim/app/api/tools/netsuite/objects/route.ts Adds the typed, credential-authorized selector endpoint for NetSuite record types and async tasks.
apps/sim/tools/netsuite/netsuite.test.ts Verifies block-to-tool coverage and now follows the established absolute import convention.

Sequence Diagram

sequenceDiagram
  participant User
  participant Block as NetSuite Block
  participant Cred as Credential Service
  participant OAuth as NetSuite OAuth
  participant Tool as NetSuite Tool
  participant SuiteTalk as SuiteTalk REST API

  User->>Block: Select stored NetSuite credential
  Block->>Cred: Resolve credential ID
  Cred->>Cred: Decrypt signing material
  Cred->>OAuth: Send signed client assertion
  OAuth-->>Cred: Short-lived access token
  Cred-->>Tool: Token and normalized SuiteTalk origin
  Tool->>SuiteTalk: Validated operation request
  SuiteTalk-->>Tool: Record, metadata, dataset, or async response
  Tool-->>Block: Normalized bounded result
Loading

Reviews (9): Last reviewed commit: "chore(netsuite): regenerate tool metadat..." | Re-trigger Greptile

Comment thread apps/sim/tools/netsuite/utils.ts Outdated
Comment thread apps/sim/blocks/blocks/netsuite.test.ts Outdated
@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author

@greptile

@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor 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 cdd5240. Configure here.

@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author

@greptile

@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor 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 61407f5. Configure here.

Comment thread apps/sim/blocks/blocks/netsuite.ts
Comment thread scripts/generate-docs.test.ts
@BillLeoutsakosvl346
BillLeoutsakosvl346 force-pushed the feat/oracle-netsuite-integration branch from 8bb7adb to 841aa5c Compare August 13, 2026 18:46
@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author

@greptile

@BillLeoutsakosvl346

Copy link
Copy Markdown
Contributor Author

Architecture note

NetSuite intentionally combines three established integration patterns:

  • Snowflake — credential and selector UX: reusable service-account credentials, credential selectors, provider-backed pickers, and Advanced manual fallbacks.

  • Salesforce, Zoho Desk, Box, and Zoom — credential lifecycle: encrypted long-lived credential material, server-side short-lived token minting, caching, reconnection, and injection of only the token and provider origin into tools.

  • Windchill and Agiloft — provider-specific transport: explicit operation tools with dedicated handling for complex response validation, asynchronous jobs, Location headers, idempotency, and unusual HTTP semantics.

No single existing integration covers all of Oracle’s requirements. NetSuite composes these established patterns at their existing architectural boundaries rather than introducing a new integration architecture.

@waleedlatif1

Copy link
Copy Markdown
Collaborator

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator

@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 607c177. Configure here.

@waleedlatif1

Copy link
Copy Markdown
Collaborator

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator

@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 8cf2388. Configure here.

Bill Leoutsakos and others added 11 commits August 13, 2026 15:14
Oracle documents the Location response header for create and update, and
both tools already require it. Upsert and transform also produce a record
but Oracle documents no response headers for either, so they dropped the
header entirely and the new record's ID was unreachable.

Add a `resource-optional` location mode that captures Location when
NetSuite sends it and never fails when it is absent, and wire it to
upsert and transform along with their tool and block outputs.

Async task discovery rejected the whole response if any task link carried
a rel other than `self`, collapsing the picker into a 502. Oracle
documents a `self` link per task but never guarantees it is the only one,
so skip other relationships and fail only when no self link exists.

Also use the shared `truncate` helper in the error sanitizer per the
repo convention instead of an inline slice.
The shared collection-page validator required links, items, count,
hasMore, offset, and totalResults on every 200, and a missing field turns
a successful call into a reported failure.

Oracle documents all six for record collections and SuiteAnalytics
dataset pages, but its SuiteQL reference lists only links, count, offset,
totalResults, and items. A documented SuiteQL response that omits hasMore
would therefore have been rejected.

Split out a suiteql-page validator that requires the five documented
SuiteQL fields and type-checks hasMore only when the account returns it.
Record collections and dataset pages keep requiring all six.
The rebase conflicted only in the generated tool-id, tool-metadata, and
tool-output artifacts, which NetSuite and the newly landed LogRocket
integration both extend. Regenerated from the merged registries: the
result is staging's catalog plus the 27 NetSuite tools, with LogRocket's
entries intact and no other tool changed.
@waleedlatif1
waleedlatif1 force-pushed the feat/oracle-netsuite-integration branch from 8cf2388 to eb21fe4 Compare August 13, 2026 22:18
@waleedlatif1

Copy link
Copy Markdown
Collaborator

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator

@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 eb21fe4. Configure here.

@waleedlatif1
waleedlatif1 merged commit 1424809 into staging Aug 13, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the feat/oracle-netsuite-integration branch August 13, 2026 22:47
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.

2 participants