Skip to content

Commit aff5c44

Browse files
committed
feat(credentials): Thrive saved credential, and close the batch-3 audit findings
Thrive gets a credential holding its key, tenant id, and region host (one of its four API hosts). Audit fixes: the connect form sends URL-shaped domains as typed so the provider check keeps their scheme and path; credentials default to a name with their domain or account id (GitLab keeps its token name) and record it in the audit log; Upstash accepts http and a read-only token refused PING; Infisical keeps http and a proxy path; Devin, Dynatrace, and Logfire refuse dot segments, non-http schemes, and mistyped regions.
1 parent 9e281c8 commit aff5c44

72 files changed

Lines changed: 292 additions & 184 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/docs/components/ui/icon-mapping.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
773773
textract_v3: TextractIcon,
774774
thinking: BrainIcon,
775775
thrive: ThriveIcon,
776+
thrive_v2: ThriveIcon,
776777
tiktok: TikTokIcon,
777778
tinybird: TinybirdIcon,
778779
tinybird_v2: TinybirdIcon,

‎apps/docs/content/docs/integrations/thrive.mdx‎

Lines changed: 1 addition & 142 deletions
Large diffs are not rendered by default.

‎apps/sim/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal/token-service-account-modal.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function TokenServiceAccountModalForm({
110110
const workspaceField = descriptor.fields.find((field) => field.id === 'providerWorkspaceId')
111111

112112
const trimmedToken = apiToken.trim()
113-
const normalizedDomain = normalizeDomainInput(domain)
113+
const normalizedDomain = domainField?.url ? domain.trim() : normalizeDomainInput(domain)
114114
const isPending =
115115
createCredential.isPending || updateCredential.isPending || submitPending === true
116116
const isDisabled =

‎apps/sim/blocks/blocks/dynatrace.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,8 +2343,6 @@ export const DynatraceV2Block: BlockConfig = {
23432343
},
23442344
},
23452345
},
2346-
longDescription:
2347-
'Integrate Dynatrace into workflows. Investigate and close Davis problems, query metrics and monitored entities, search and ingest logs, push deployment events, manage SLOs and their burn rates, triage and mute Application Security vulnerabilities, review runtime attacks, tag entities, manage settings objects such as maintenance windows and alerting profiles, run synthetic monitors on demand, and read the audit log.',
23482346
...withSavedCredential(DynatraceBlock, {
23492347
id: 'credential',
23502348
type: 'oauth-input',

‎apps/sim/blocks/blocks/thrive.ts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ThriveIcon } from '@/components/icons'
22
import { AuthMode, type BlockConfig, type BlockMeta, IntegrationType } from '@/blocks/types'
3+
import { withSavedCredential } from '@/blocks/utils'
34

45
const PAGINATED_OPS = [
56
'search_users',
@@ -71,6 +72,8 @@ const STATUS_FILTER_FIELD = ['userStatus', 'statuses'] as const
7172

7273
export const ThriveBlock: BlockConfig = {
7374
type: 'thrive',
75+
hideFromToolbar: true,
76+
sunset: { status: 'legacy', replacedBy: 'thrive_v2' },
7477
name: 'Thrive',
7578
description: 'Manage users, audiences, learning and CPD on Thrive',
7679
longDescription:
@@ -1185,3 +1188,16 @@ export const ThriveBlockMeta = {
11851188
},
11861189
],
11871190
} as const satisfies BlockMeta
1191+
1192+
export const ThriveV2Block: BlockConfig = {
1193+
...ThriveBlock,
1194+
type: 'thrive_v2',
1195+
authMode: AuthMode.OAuth,
1196+
hideFromToolbar: false,
1197+
sunset: undefined,
1198+
...withSavedCredential(
1199+
ThriveBlock,
1200+
{ id: 'credential', type: 'oauth-input', serviceId: 'thrive', title: 'Thrive Credential' },
1201+
{ required: true }
1202+
),
1203+
}

‎apps/sim/blocks/blocks/tinybird.ts‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,8 +666,6 @@ export const TinybirdV2Block: BlockConfig = {
666666
authMode: AuthMode.OAuth,
667667
hideFromToolbar: false,
668668
sunset: undefined,
669-
longDescription:
670-
'Interact with Tinybird: stream JSON or NDJSON events with the Events API, run SQL with the Query API, call published Pipe API Endpoints by name with dynamic parameters, manage Data Sources by appending from a URL, truncating, or deleting rows by condition, and poll the status of asynchronous jobs.',
671669
...withSavedCredential(TinybirdBlock, {
672670
id: 'credential',
673671
type: 'oauth-input',

‎apps/sim/blocks/registry-maps.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ import {
415415
TextractV3Block,
416416
} from '@/blocks/blocks/textract'
417417
import { ThinkingBlock } from '@/blocks/blocks/thinking'
418-
import { ThriveBlock, ThriveBlockMeta } from '@/blocks/blocks/thrive'
418+
import { ThriveBlock, ThriveBlockMeta, ThriveV2Block } from '@/blocks/blocks/thrive'
419419
import { TikTokBlock, TikTokBlockMeta } from '@/blocks/blocks/tiktok'
420420
import { TinybirdBlock, TinybirdBlockMeta, TinybirdV2Block } from '@/blocks/blocks/tinybird'
421421
import { TinyFishBlock, TinyFishBlockMeta } from '@/blocks/blocks/tinyfish'
@@ -912,6 +912,7 @@ export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
912912
textract_v3: TextractV3Block,
913913
thinking: ThinkingBlock,
914914
thrive: ThriveBlock,
915+
thrive_v2: ThriveV2Block,
915916
tiktok: TikTokBlock,
916917
tinybird: TinybirdBlock,
917918
tinybird_v2: TinybirdV2Block,

‎apps/sim/lib/block-metadata/names.generated.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ export const BLOCK_NAMES: Readonly<Record<string, string>> = {
289289
temporal: 'Temporal',
290290
textract_v3: 'AWS Textract',
291291
thinking: 'Thinking',
292-
thrive: 'Thrive',
292+
thrive_v2: 'Thrive',
293293
tiktok: 'TikTok',
294294
tinybird_v2: 'Tinybird',
295295
tinyfish: 'TinyFish',

‎apps/sim/lib/credentials/token-service-accounts/descriptors.ts‎

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ export interface TokenServiceAccountField {
2424
placeholder: string
2525
/** Rendered with SecretInput and never echoed back. */
2626
secret: boolean
27+
/**
28+
* The value is a URL whose scheme and path matter (a self-hosted instance or
29+
* deployment URL), so the connect form sends it as typed and the provider's
30+
* check normalizes it. Other domains are reduced to a bare host first.
31+
*/
32+
url?: boolean
2733
/** Soft-format hint shown while the current value doesn't match `hintPattern`. */
2834
hintPattern?: RegExp
2935
hintMessage?: string
@@ -85,6 +91,7 @@ export const FLOW_SERVICE_ACCOUNT_PROVIDER_ID = 'flow-service-account' as const
8591
export const CODA_SERVICE_ACCOUNT_PROVIDER_ID = 'coda-service-account' as const
8692
export const GAUGE_SERVICE_ACCOUNT_PROVIDER_ID = 'gauge-service-account' as const
8793
export const HIGGSFIELD_SERVICE_ACCOUNT_PROVIDER_ID = 'higgsfield-service-account' as const
94+
export const THRIVE_SERVICE_ACCOUNT_PROVIDER_ID = 'thrive-service-account' as const
8895
export const SUPABASE_SERVICE_ACCOUNT_PROVIDER_ID = 'supabase-service-account' as const
8996
export const INFISICAL_SERVICE_ACCOUNT_PROVIDER_ID = 'infisical-service-account' as const
9097
export const OKTA_SERVICE_ACCOUNT_PROVIDER_ID = 'okta-service-account' as const
@@ -211,6 +218,7 @@ export type TokenServiceAccountProviderId =
211218
| typeof CODA_SERVICE_ACCOUNT_PROVIDER_ID
212219
| typeof GAUGE_SERVICE_ACCOUNT_PROVIDER_ID
213220
| typeof HIGGSFIELD_SERVICE_ACCOUNT_PROVIDER_ID
221+
| typeof THRIVE_SERVICE_ACCOUNT_PROVIDER_ID
214222
| typeof SUPABASE_SERVICE_ACCOUNT_PROVIDER_ID
215223
| typeof INFISICAL_SERVICE_ACCOUNT_PROVIDER_ID
216224
| typeof OKTA_SERVICE_ACCOUNT_PROVIDER_ID
@@ -1839,6 +1847,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
18391847
label: 'Grafana URL',
18401848
placeholder: 'https://your-stack.grafana.net',
18411849
secret: false,
1850+
url: true,
18421851
},
18431852
],
18441853
docsUrl: 'https://docs.sim.ai/integrations/grafana',
@@ -1864,6 +1873,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
18641873
label: 'Server URL',
18651874
placeholder: 'https://jupyter.example.com',
18661875
secret: false,
1876+
url: true,
18671877
},
18681878
],
18691879
docsUrl: 'https://docs.sim.ai/integrations/jupyter',
@@ -1889,6 +1899,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
18891899
label: 'Deployment URL',
18901900
placeholder: 'https://your-deployment.convex.cloud',
18911901
secret: false,
1902+
url: true,
18921903
},
18931904
],
18941905
docsUrl: 'https://docs.sim.ai/integrations/convex',
@@ -1909,6 +1920,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
19091920
label: 'API base URL',
19101921
placeholder: 'https://api.tinybird.co',
19111922
secret: false,
1923+
url: true,
19121924
},
19131925
],
19141926
docsUrl: 'https://docs.sim.ai/integrations/tinybird',
@@ -1929,6 +1941,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
19291941
label: 'Environment URL',
19301942
placeholder: 'https://abc12345.live.dynatrace.com',
19311943
secret: false,
1944+
url: true,
19321945
},
19331946
],
19341947
docsUrl: 'https://docs.sim.ai/integrations/dynatrace',
@@ -1964,6 +1977,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
19641977
label: 'Region or host',
19651978
placeholder: 'auto, us, eu, or https://logfire.example.com',
19661979
secret: false,
1980+
url: true,
19671981
},
19681982
],
19691983
docsUrl: 'https://docs.sim.ai/integrations/logfire',
@@ -2023,7 +2037,13 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
20232037
connectNoun: 'API token',
20242038
fields: [
20252039
{ id: 'apiToken', label: 'API token', placeholder: 'plane_api_...', secret: true },
2026-
{ id: 'domain', label: 'Instance URL', placeholder: 'https://api.plane.so', secret: false },
2040+
{
2041+
id: 'domain',
2042+
label: 'Instance URL',
2043+
placeholder: 'https://api.plane.so',
2044+
secret: false,
2045+
url: true,
2046+
},
20272047
],
20282048
docsUrl: 'https://docs.sim.ai/integrations/plane',
20292049
helpText:
@@ -2103,7 +2123,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
21032123
],
21042124
docsUrl: 'https://docs.sim.ai/integrations/algolia',
21052125
helpText:
2106-
'Copy the Application ID and an API key from Settings > API Keys in the Algolia dashboard. Use the Write API key, or a key with the ACLs your workflows need; a Search-only key can only search.',
2126+
'Copy the Application ID and an API key from Settings > API Keys in the Algolia dashboard. Use the Write API key, or a key with the ACLs your workflows need; a Search-only key can only search, and secured (derived) keys are not supported.',
21072127
invalidCredentialsHelp:
21082128
'Algolia rejected this application ID and API key. Check that the key belongs to this application and has not been deleted.',
21092129
},
@@ -2124,6 +2144,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
21242144
label: 'REST URL',
21252145
placeholder: 'https://your-database.upstash.io',
21262146
secret: false,
2147+
url: true,
21272148
},
21282149
],
21292150
docsUrl: 'https://docs.sim.ai/integrations/upstash',
@@ -2149,6 +2170,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
21492170
label: 'Instance URL',
21502171
placeholder: 'https://dedi.emailbison.com',
21512172
secret: false,
2173+
url: true,
21522174
},
21532175
],
21542176
docsUrl: 'https://docs.sim.ai/integrations/emailbison',
@@ -2204,7 +2226,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
22042226
helpText:
22052227
'Create an API token in the Okta Admin Console under Security > API > Tokens. The token acts with the admin roles of the user who created it. Enter your Okta domain, such as dev-123456.okta.com; custom domains are not supported.',
22062228
invalidCredentialsHelp:
2207-
'Okta rejected this token. Check that it is active, was created in this Okta org, and that the domain is your okta.com (or oktapreview.com) domain.',
2229+
'Okta rejected this token. Check that it is active, was created in this Okta org, and that the domain is your Okta-hosted domain (okta.com, oktapreview.com, okta-emea.com, or okta-gov.com).',
22082230
},
22092231
[INFISICAL_SERVICE_ACCOUNT_PROVIDER_ID]: {
22102232
providerId: INFISICAL_SERVICE_ACCOUNT_PROVIDER_ID,
@@ -2223,6 +2245,7 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
22232245
label: 'Instance URL',
22242246
placeholder: 'https://us.infisical.com',
22252247
secret: false,
2248+
url: true,
22262249
},
22272250
],
22282251
docsUrl: 'https://docs.sim.ai/integrations/infisical',
@@ -2246,6 +2269,27 @@ export const TOKEN_SERVICE_ACCOUNT_DESCRIPTORS: Record<
22462269
invalidCredentialsHelp:
22472270
"Supabase rejected this key. Check that it belongs to the project you entered and hasn't been revoked.",
22482271
},
2272+
[THRIVE_SERVICE_ACCOUNT_PROVIDER_ID]: {
2273+
providerId: THRIVE_SERVICE_ACCOUNT_PROVIDER_ID,
2274+
serviceLabel: 'Thrive',
2275+
tokenNoun: 'API key',
2276+
connectNoun: 'API key',
2277+
fields: [
2278+
{ id: 'apiToken', label: 'API key', placeholder: 'Paste your Thrive API key', secret: true },
2279+
{
2280+
id: 'providerWorkspaceId',
2281+
label: 'Tenant ID',
2282+
placeholder: 'Your Thrive tenant ID',
2283+
secret: false,
2284+
},
2285+
{ id: 'domain', label: 'Region host', placeholder: 'public.api.learn.link', secret: false },
2286+
],
2287+
docsUrl: 'https://docs.sim.ai/integrations/thrive',
2288+
helpText:
2289+
'Use the API key and tenant ID from your Thrive admin settings. Region host is public.api.learn.link, or public.api.mea.learn.tech for the Middle East and Africa (staging hosts also work).',
2290+
invalidCredentialsHelp:
2291+
'Thrive rejected this API key. Check that the tenant ID matches the key and that the region host is the one your tenant uses.',
2292+
},
22492293
}
22502294

22512295
/**

‎apps/sim/lib/credentials/token-service-accounts/server.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ import {
103103
TAILSCALE_SERVICE_ACCOUNT_PROVIDER_ID,
104104
TAVILY_SERVICE_ACCOUNT_PROVIDER_ID,
105105
TELEGRAM_SERVICE_ACCOUNT_PROVIDER_ID,
106+
THRIVE_SERVICE_ACCOUNT_PROVIDER_ID,
106107
TINYBIRD_SERVICE_ACCOUNT_PROVIDER_ID,
107108
TOKEN_SERVICE_ACCOUNT_SECRET_TYPE,
108109
type TokenServiceAccountProviderId,
@@ -223,6 +224,7 @@ import {
223224
validateTailscaleServiceAccount,
224225
validateTavilyServiceAccount,
225226
validateTelegramServiceAccount,
227+
validateThriveServiceAccount,
226228
validateTinybirdServiceAccount,
227229
validateTriggerDevServiceAccount,
228230
validateTwilioServiceAccount,
@@ -394,6 +396,7 @@ const TOKEN_SERVICE_ACCOUNT_VALIDATORS: Record<
394396
[STRIPE_SERVICE_ACCOUNT_PROVIDER_ID]: validateStripeServiceAccount,
395397
[SUPABASE_SERVICE_ACCOUNT_PROVIDER_ID]: validateSupabaseServiceAccount,
396398
[TELEGRAM_SERVICE_ACCOUNT_PROVIDER_ID]: validateTelegramServiceAccount,
399+
[THRIVE_SERVICE_ACCOUNT_PROVIDER_ID]: validateThriveServiceAccount,
397400
[TINYBIRD_SERVICE_ACCOUNT_PROVIDER_ID]: validateTinybirdServiceAccount,
398401
[TWILIO_SERVICE_ACCOUNT_PROVIDER_ID]: validateTwilioServiceAccount,
399402
[TYPEFORM_SERVICE_ACCOUNT_PROVIDER_ID]: validateTypeformServiceAccount,

0 commit comments

Comments
 (0)