Skip to content

Commit 738d2d9

Browse files
committed
improvement(network): consolidate outbound HTTP helpers
1 parent cdd2ed0 commit 738d2d9

228 files changed

Lines changed: 313 additions & 266 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/sim/connectors/fireflies/fireflies.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { getErrorMessage, toError } from '@sim/utils/errors'
33
import { z } from 'zod'
4-
import { outboundFetch } from '@/lib/core/network/fetch.server'
4+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
55
import { isPayloadSizeLimitError, readResponseTextWithLimit } from '@/lib/core/utils/stream-limits'
66
import {
77
isRetryableError,

apps/sim/connectors/github/request.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { createHash } from 'node:crypto'
22
import { createLogger } from '@sim/logger'
3-
import { outboundFetch } from '@/lib/core/network/fetch.server'
43
import { acquireProviderCapacity } from '@/lib/core/rate-limiter/provider-capacity'
54
import {
65
type ProviderCapacityDeferralReason,
76
ProviderCapacityDeferredError,
87
} from '@/lib/core/rate-limiter/provider-capacity-error'
98
import type { ProviderCapacityQuota } from '@/lib/core/rate-limiter/provider-capacity-state'
9+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
1010
import { readResponseTextWithLimit } from '@/lib/core/utils/stream-limits'
1111
import {
1212
fetchWithRetry,

apps/sim/connectors/google-drive/google-drive-errors.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { outboundFetch } from '@/lib/core/network/fetch.server'
1+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
22
import {
33
attachRetryHeaders,
44
isRetryableError,

apps/sim/lib/atlassian/discovery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { sha256Hex } from '@sim/security/hash'
22
import { parseRetryAfter } from '@sim/utils/retry'
33
import { LRUCache } from 'lru-cache'
4-
import { outboundFetch } from '@/lib/core/network/fetch.server'
4+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
55
import {
66
type HTTPError,
77
isRetryableError,

apps/sim/lib/core/network/fetch.server.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

apps/sim/lib/core/security/input-validation.server.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import { toError } from '@sim/utils/errors'
1212
import { HttpProxyAgent } from 'http-proxy-agent'
1313
import { HttpsProxyAgent } from 'https-proxy-agent'
1414
import { Agent, type Dispatcher, type RequestInit as UndiciRequestInit } from 'undici/index.js'
15-
import { requireDirectOutboundTransport } from '@/lib/core/network/context.server'
15+
import { isOutboundRoutingEnabled } from '@/lib/core/network/config.server'
16+
import {
17+
requireDirectOutboundTransport,
18+
resolveCurrentOutboundRoute,
19+
} from '@/lib/core/network/context.server'
1620
import { OutboundRoutingError } from '@/lib/core/network/routing'
1721
import {
1822
createOutboundTransport,
@@ -976,6 +980,24 @@ export function createSsrfGuardedFetchWithDispatcher(options: {
976980
}
977981
}
978982

983+
let providerFetch: ReturnType<typeof createSsrfGuardedFetchWithDispatcher> | undefined
984+
985+
/**
986+
* Fetch for external provider calls. Unconfigured deployments preserve native behavior.
987+
* Required gateways use the shared guarded transport and its organization-separated pools.
988+
* User-controlled configured endpoints retain their explicit provenance-aware fetch factory.
989+
*/
990+
export async function outboundFetch(
991+
input: RequestInfo | URL,
992+
init?: RequestInit
993+
): Promise<Response> {
994+
if (!isOutboundRoutingEnabled()) return fetch(input, init)
995+
const route = await resolveCurrentOutboundRoute()
996+
if (route.kind === 'direct') return fetch(input, init)
997+
providerFetch ??= createSsrfGuardedFetchWithDispatcher({ profile: 'contentFetch' })
998+
return providerFetch.fetch(input, init)
999+
}
1000+
9791001
/**
9801002
* Builds a standard `fetch`-compatible function that pins every outbound
9811003
* connection to `resolvedIP`, preventing DNS-rebinding (TOCTOU) between URL

apps/sim/lib/credential-groups/slack-managed-users.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import { getErrorMessage } from '@sim/utils/errors'
1313
import { generateId } from '@sim/utils/id'
1414
import { and, eq, inArray, isNull, or, sql } from 'drizzle-orm'
1515
import { getRedisClient } from '@/lib/core/config/redis'
16-
import { outboundFetch } from '@/lib/core/network/fetch.server'
1716
import { resourceScopeFields, resourceScopeFromOwner } from '@/lib/core/resource-scope'
1817
import { resourceScopeCondition } from '@/lib/core/resource-scope.server'
1918
import { decryptSecret, encryptSecret } from '@/lib/core/security/encryption'
19+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
2020
import { getBaseUrl } from '@/lib/core/utils/urls'
2121
import { credentialGroupScopePolicyVersion } from '@/lib/credential-groups/provider-adapter'
2222
import {

apps/sim/lib/credential-groups/standard-oauth-provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
getManagedOAuthConnectorProviderConfig,
1313
type ManagedOAuthConnectorConfig,
1414
} from '@/lib/auth/connectors/managed-oauth'
15-
import { outboundFetch } from '@/lib/core/network/fetch.server'
15+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
1616
import { readResponseJsonWithLimit } from '@/lib/core/utils/stream-limits'
1717
import { credentialGroupOAuthNonceMatches } from '@/lib/credential-groups/oauth-state'
1818
import type {

apps/sim/lib/credentials/atlassian-service-account.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { outboundFetch } from '@/lib/core/network/fetch.server'
1+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
22
import type { AtlassianProduct } from '@/lib/credentials/service-account-fields'
33
import { parseAtlassianErrorMessage } from '@/tools/jira/utils'
44

apps/sim/lib/credentials/client-credential-accounts/minters/netsuite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createPrivateKey, type KeyObject } from 'node:crypto'
22
import { generateId } from '@sim/utils/id'
33
import { truncate } from '@sim/utils/string'
44
import { SignJWT } from 'jose'
5-
import { outboundFetch } from '@/lib/core/network/fetch.server'
5+
import { outboundFetch } from '@/lib/core/security/input-validation.server'
66
import {
77
DEFAULT_MAX_ERROR_BODY_BYTES,
88
readResponseJsonWithLimit,

0 commit comments

Comments
 (0)