Skip to content

feat(integrations): SAP S/4HANA#4301

Open
waleedlatif1 wants to merge 3 commits intostagingfrom
waleedlatif1/sap-integration
Open

feat(integrations): SAP S/4HANA#4301
waleedlatif1 wants to merge 3 commits intostagingfrom
waleedlatif1/sap-integration

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • New SAP S/4HANA integration: 37 tools across Business Partner, Customer, Supplier, Sales Order, Product, Purchase Order/Requisition, Supplier Invoice, Outbound/Inbound Delivery, Material Stock/Documents, Billing Document + a generic OData v2 query escape hatch
  • Single internal proxy route handles BTP UAA token caching, CSRF fetch+retry on writes, and OData error/payload normalization
  • Supports Cloud Public Edition, Cloud Private Edition (RISE), and on-premise — with OAuth 2.0 client credentials or HTTP Basic auth selectable per deployment
  • Block, registry entries, icon, integrations landing entry, and generated docs

Type of Change

  • New feature

Testing

Tested manually

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)

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 26, 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 27, 2026 3:49am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 26, 2026

PR Summary

Medium Risk
Introduces a new server-side proxy that performs authenticated outbound requests (token fetch + CSRF handling) and is therefore sensitive to validation/SSRF and auth-edge cases, though it includes explicit URL/path restrictions and error normalization.

Overview
Adds a new SAP S/4HANA integration end-to-end: new docs page (sap_s4hana.mdx) and tool metadata, plus UI/icon wiring so it appears in both Docs and the Sim integrations landing.

Implements a new internal API route (/api/tools/sap_s4hana/proxy) that brokers SAP OData v2 calls, including OAuth client-credentials token caching, optional Basic auth for private/on-prem deployments, CSRF fetch+retry for write methods, and normalized OData unwrapping/error handling.

Registers a new SapS4HanaBlock and ~37 SAP tool configs (list/get/create/update/delete + generic sap_s4hana_odata_query) into the blocks/tools registries and icon mappings so workflows can invoke SAP operations through the proxy.

Reviewed by Cursor Bugbot for commit de70b89. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 26, 2026

Greptile Summary

This PR introduces a full SAP S/4HANA integration with 37 OData v2 tools (Business Partner, Customer, Supplier, Sales Order, Product, Purchase Order/Requisition, Supplier Invoice, Inbound/Outbound Delivery, Material Stock/Documents, Billing Document) plus a generic OData escape-hatch, backed by a single internal proxy route that manages BTP UAA token caching (LRU-capped at 500 entries), CSRF fetch-and-retry, OData payload normalization, and multi-deployment auth (OAuth 2.0 or HTTP Basic). All previously flagged security issues (SSRF via unvalidated URLs, unbounded token cache, missing fetch timeouts, unsafe parseJsonInput return type, partial RFC-1918 coverage) have been resolved in this revision.

Confidence Score: 5/5

Safe to merge — no outstanding P0 or P1 findings; all previously flagged security issues have been addressed.

The PR is a large but well-structured new feature. Security mitigations (SSRF blocklists covering loopback, link-local, RFC-1918, and IPv4-mapped IPv6 addresses; HTTPS enforcement; fetch timeouts; LRU token cache cap) are thorough. Tool implementations follow consistent patterns with proper input validation. No P1 or P0 findings identified in the current revision.

apps/sim/app/api/tools/sap_s4hana/proxy/route.ts — most complex file; worth a final read-through, but no blocking issues found.

Important Files Changed

Filename Overview
apps/sim/app/api/tools/sap_s4hana/proxy/route.ts Central proxy: handles auth (OAuth + Basic), CSRF fetch/retry, OData normalization, and SSRF mitigations (HTTPS-only, private IP blocklist, RFC-1918 ranges, IPv4-mapped IPv6). All previously flagged security issues addressed.
apps/sim/tools/sap_s4hana/utils.ts Shared utilities: baseProxyBody, buildOdataQuery, parseJsonInput (return type fixed to T
apps/sim/tools/sap_s4hana/types.ts Type definitions for all 37 tools and SAP base params; clean and consistent across entities.
apps/sim/tools/sap_s4hana/odata_query.ts Generic OData v2 escape-hatch tool; normalizes query string/JSON input, injects $format=json, delegates all auth/CSRF/unwrap to the proxy.
apps/sim/blocks/blocks/sap_s4hana.ts Block definition with 37 operations, shared subBlock conditions for filter/top/skip/orderBy/select/expand, and per-operation entity-key/body inputs. Consistent with existing block patterns.
apps/sim/tools/sap_s4hana/create_sales_order.ts Creates A_SalesOrder with deep insert via to_Item; validates items is an array before sending.
apps/sim/tools/sap_s4hana/delete_sales_order.ts Sends DELETE to A_SalesOrder with wildcard If-Match default; correctly uses quoteOdataKey for the entity key.
apps/sim/tools/sap_s4hana/index.ts Barrel export for all 37 tool configs; no issues.

Sequence Diagram

sequenceDiagram
    participant Client as Sim Client (Tool)
    participant Proxy as /api/tools/sap_s4hana/proxy
    participant SAP_Auth as SAP OAuth / BTP UAA
    participant SAP as SAP OData Service

    Client->>Proxy: POST (deploymentType, auth creds, service, path, method, body)
    Proxy->>Proxy: Zod validation (URL safety, required fields)
    Proxy->>Proxy: checkInternalAuth()

    alt OAuth (cloud_public / cloud_private)
        Proxy->>Proxy: Check TOKEN_CACHE (LRU, max 500)
        alt Cache miss / expired
            Proxy->>SAP_Auth: POST /oauth/token (client_credentials)
            SAP_Auth-->>Proxy: access_token + expires_in
            Proxy->>Proxy: rememberToken() into LRU cache
        end
    end

    alt Write method (POST/PATCH/PUT/DELETE/MERGE)
        Proxy->>SAP: GET /$metadata (X-CSRF-Token: Fetch)
        SAP-->>Proxy: x-csrf-token + Set-Cookie
    end

    Proxy->>SAP: OData request (Authorization, CSRF token if write)
    SAP-->>Proxy: Response

    alt 403 + CSRF required
        Proxy->>SAP: GET /$metadata (re-fetch CSRF)
        SAP-->>Proxy: New CSRF token
        Proxy->>SAP: Retry OData request
        SAP-->>Proxy: Response
    end

    Proxy->>Proxy: unwrapOdata() strip .d / .d.results wrapper
    Proxy-->>Client: { success, output: { status, data } }
Loading

Reviews (3): Last reviewed commit: "fix(sap_s4hana): allow versioned service..." | Re-trigger Greptile

Comment thread apps/sim/app/api/tools/sap_s4hana/proxy/route.ts
Comment thread apps/sim/app/api/tools/sap_s4hana/proxy/route.ts
Comment thread apps/sim/app/api/tools/sap_s4hana/proxy/route.ts
Comment thread apps/sim/tools/sap_s4hana/utils.ts Outdated
Comment thread apps/sim/blocks/blocks/sap_s4hana.ts
Comment thread apps/sim/app/api/tools/sap_s4hana/proxy/route.ts
- Validate baseUrl/tokenUrl in Zod schema and at runtime to prevent SSRF
  (https-only, deny loopback/link-local/cloud-metadata hosts)
- Cap proxy token cache at 500 entries with LRU eviction
- Add 30s timeout to outbound token, CSRF, and OData fetches
- Make parseJsonInput return T | undefined so missing input is type-safe
- Reset authType when deploymentType changes and surface OAuth fields
  whenever auth is not basic, so cloud_public users always see clientId/
  clientSecret after switching from a basic-auth private deployment
- Reject OData service names that are not uppercase identifiers and
  paths containing ".." or "." traversal segments

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/sap_s4hana/proxy/route.ts
Comment thread apps/sim/app/api/tools/sap_s4hana/proxy/route.ts
Comment thread apps/sim/app/api/tools/sap_s4hana/proxy/route.ts
…fenses

- Permit ";v=NNNN" suffix on ServiceName regex so the four delivery tools
  (API_OUTBOUND_DELIVERY_SRV;v=0002, API_INBOUND_DELIVERY_SRV;v=0002) pass
  schema validation
- Restrict subdomain to RFC 1123 label characters and region to lowercase
  alphanumeric short codes; run the constructed cloud_public host through
  assertSafeExternalUrl so a crafted subdomain (e.g. "evil.com#") cannot
  redirect requests carrying SAP credentials
- Block RFC-1918 (10/8, 172.16/12, 192.168/16), 127/8, 169.254/16, and
  0.0.0.0 via isPrivateIPv4, plus IPv4-mapped IPv6 variants
  (::ffff:10.0.0.1, ::10.0.0.1) so private internal hosts cannot be
  reached from baseUrl, tokenUrl, or the resolved cloud_public URL

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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit de70b89. Configure here.

}
}
return null
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

IPv4-mapped IPv6 SSRF check bypassed by URL normalization

Medium Severity

extractIPv4MappedHost expects dotted-decimal IPv4 after the ::ffff: prefix, but Node.js's WHATWG URL parser normalizes IPv4-mapped IPv6 addresses to hex form. For example, https://[::ffff:169.254.169.254]/ yields parsed.hostname of ::ffff:a9fe:a9fe, not the dotted form. The candidate a9fe:a9fe fails the IPv4 regex, so the check returns null. Likewise, FORBIDDEN_HOSTS entries like [::ffff:127.0.0.1] never match because the normalized form is ::ffff:7f00:1. This allows private/loopback addresses to bypass SSRF protections when supplied as IPv4-mapped IPv6 in baseUrl or tokenUrl. The HTTPS-only requirement limits impact but doesn't eliminate it for internal services with valid TLS.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit de70b89. Configure here.

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