Skip to content

Commit dc8782e

Browse files
committed
fix(ci): restore staging files the branch split had reverted, and format
Three problems, all from assembling this branch by checking paths out of a WIP branch built on an older `staging`. Anything `staging` changed since that base came back as a revert. - Root `package.json` had lost the `opentype.js` / `@types/opentype.js` dependencies `staging` added, which desynced `bun.lock` and failed `bun audit`. It also carried a `check:outbound-delivery` script belonging to other work. Every `package.json` is now taken from `staging` with only the `engines.bun` line re-applied. - `executor/utils/block-data.test.ts` — a 77-line file `staging` added — was deleted outright. Restored. - `executor/handlers/generic/generic-handler.test.ts` had lost a test `staging` added. Restored, with only the one `blockId` assertion re-applied. Also formats `keyed-invocation-identity.test.ts` and sorts imports in `internal-api-base-url.test.ts`, which is what `lint:check` failed on.
1 parent 82f8450 commit dc8782e

6 files changed

Lines changed: 145 additions & 6 deletions

File tree

apps/sim/executor/handlers/generic/generic-handler.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '@sim/testing/mocks/executor'
22

33
import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest'
4+
import { HarmonicBlock } from '@/blocks/blocks/harmonic'
45
import { KnowledgeBlock } from '@/blocks/blocks/knowledge'
56
import { getBlock } from '@/blocks/index'
67
import { BlockType } from '@/executor/constants'
@@ -490,6 +491,47 @@ describe('GenericBlockHandler', () => {
490491
expect(transform).toHaveBeenCalledTimes(1)
491492
})
492493

494+
it('does not expose an invalid resolved Harmonic batch value in handler errors', async () => {
495+
const resolvedSecret = 'sk-live-invalid-json-secret'
496+
mockBlock.metadata = { id: 'harmonic', name: 'Harmonic' }
497+
mockGetBlock.mockReturnValue(HarmonicBlock)
498+
mockExecuteTool.mockResolvedValue({
499+
success: false,
500+
error: 'Harmonic "personUrns" must be a JSON array',
501+
})
502+
503+
const registry = new ResolvedSecretTraceRegistry([
504+
{
505+
name: 'BATCH_IDENTIFIERS',
506+
plaintext: resolvedSecret,
507+
encryptedValue: 'encrypted-batch-identifiers',
508+
},
509+
])
510+
registry.recordResolvedAtInputPath('BATCH_IDENTIFIERS', resolvedSecret, ['personUrns'])
511+
registry.recordResolvedInputProjection(['personUrns'], resolvedSecret, '{{BATCH_IDENTIFIERS}}')
512+
mockContext.resolvedSecretTraceRegistry = registry
513+
514+
let thrown: unknown
515+
try {
516+
await handler.execute(mockContext, mockBlock, {
517+
operation: 'harmonic_batch_get_people',
518+
oauthCredential: 'credential-id',
519+
personUrns: resolvedSecret,
520+
})
521+
} catch (error) {
522+
thrown = error
523+
}
524+
525+
expect(thrown).toBeInstanceOf(Error)
526+
expect((thrown as Error).message).toBe('Harmonic "personUrns" must be a JSON array')
527+
expect((thrown as Error).message).not.toContain(resolvedSecret)
528+
expect(mockExecuteTool).toHaveBeenCalledWith(
529+
'some_custom_tool',
530+
expect.objectContaining({ personUrns: resolvedSecret }),
531+
{ executionContext: mockContext }
532+
)
533+
})
534+
493535
it('should throw error if the associated tool is not found', async () => {
494536
const inputs = { param1: 'value' }
495537

apps/sim/executor/handlers/generic/keyed-invocation-identity.test.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,21 @@ describe('keyed invocation identity', () => {
6565

6666
it('separates two different blocks inside one execution', () => {
6767
const a = deriveDeliveryKey(
68-
{ executionId: 'exec-1', blockId: 'block-a', toolId: 'brex_create_transfer', invocationId: '1' },
68+
{
69+
executionId: 'exec-1',
70+
blockId: 'block-a',
71+
toolId: 'brex_create_transfer',
72+
invocationId: '1',
73+
},
6974
'brex_create_transfer'
7075
)
7176
const b = deriveDeliveryKey(
72-
{ executionId: 'exec-1', blockId: 'block-b', toolId: 'brex_create_transfer', invocationId: '1' },
77+
{
78+
executionId: 'exec-1',
79+
blockId: 'block-b',
80+
toolId: 'brex_create_transfer',
81+
invocationId: '1',
82+
},
7383
'brex_create_transfer'
7484
)
7585

@@ -78,11 +88,21 @@ describe('keyed invocation identity', () => {
7888

7989
it('separates the same block across two executions', () => {
8090
const first = deriveDeliveryKey(
81-
{ executionId: 'exec-1', blockId: 'block-1', toolId: 'brex_create_transfer', invocationId: '1' },
91+
{
92+
executionId: 'exec-1',
93+
blockId: 'block-1',
94+
toolId: 'brex_create_transfer',
95+
invocationId: '1',
96+
},
8297
'brex_create_transfer'
8398
)
8499
const second = deriveDeliveryKey(
85-
{ executionId: 'exec-2', blockId: 'block-1', toolId: 'brex_create_transfer', invocationId: '1' },
100+
{
101+
executionId: 'exec-2',
102+
blockId: 'block-1',
103+
toolId: 'brex_create_transfer',
104+
invocationId: '1',
105+
},
86106
'brex_create_transfer'
87107
)
88108

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { describe, expect, it, vi } from 'vitest'
5+
import { getBlockSchema } from '@/executor/utils/block-data'
6+
import { resolveBlockReference } from '@/executor/utils/block-reference'
7+
import type { SerializedBlock } from '@/serializer/types'
8+
9+
/**
10+
* These assertions are about what the real block registry publishes, so the global stub — which
11+
* returns one mock block with no outputs — would make every case here pass vacuously.
12+
*/
13+
vi.unmock('@/blocks/registry')
14+
15+
function triggerBlock(type: string, params: Record<string, unknown> = {}): SerializedBlock {
16+
return {
17+
id: 'trigger-1',
18+
metadata: { id: type, name: 'webhook1', category: 'triggers' },
19+
position: { x: 0, y: 0 },
20+
config: { tool: '', params },
21+
inputs: {},
22+
outputs: {},
23+
enabled: true,
24+
} as unknown as SerializedBlock
25+
}
26+
27+
function resolve(
28+
pathParts: string[],
29+
schema: ReturnType<typeof getBlockSchema>
30+
): ReturnType<typeof resolveBlockReference> {
31+
return resolveBlockReference(
32+
'webhook1',
33+
pathParts,
34+
{
35+
blockNameMapping: { webhook1: 'trigger-1' },
36+
blockData: { 'trigger-1': { query: { env: 'prod' } } },
37+
blockOutputSchemas: schema ? { 'trigger-1': schema } : {},
38+
} as never,
39+
{} as never
40+
)
41+
}
42+
43+
describe('generic webhook output schema', () => {
44+
/**
45+
* A generic webhook receives whatever the caller sends, so it must publish no schema at all.
46+
* `collectBlockData` registers any non-empty output declaration as exhaustive, which turns
47+
* every unlisted field into a hard `InvalidFieldError` rather than an absent value.
48+
*/
49+
it('publishes no output schema, leaving the block shape open', () => {
50+
expect(getBlockSchema(triggerBlock('generic_webhook'))).toBeUndefined()
51+
})
52+
53+
it.each([
54+
[{}, 'no flags set'],
55+
[{ acceptOtherMethods: true, exposeRequestHeaders: true }, 'both request-metadata flags on'],
56+
])('stays open with %o (%s)', (params) => {
57+
expect(getBlockSchema(triggerBlock('generic_webhook', params))).toBeUndefined()
58+
})
59+
60+
/**
61+
* The production regression this pins: a Slack interactive payload reaching a workflow that
62+
* reads `actions.0.selected_option.value`. When a delivery omits the field the reference must
63+
* resolve to `undefined` so the condition simply evaluates falsy — not abort the run.
64+
*/
65+
it('resolves an absent body field to undefined instead of throwing', () => {
66+
const schema = getBlockSchema(triggerBlock('generic_webhook'))
67+
68+
expect(() => resolve(['actions', '0', 'selected_option', 'value'], schema)).not.toThrow()
69+
expect(resolve(['actions', '0', 'selected_option', 'value'], schema)?.value).toBeUndefined()
70+
})
71+
72+
it('still resolves request metadata the provider merges into the input', () => {
73+
const schema = getBlockSchema(triggerBlock('generic_webhook'))
74+
75+
expect(resolve(['query', 'env'], schema)?.value).toBe('prod')
76+
})
77+
})

apps/sim/lib/core/utils/internal-api-base-url.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
*/
1414
import { resetEnvMock, setEnv } from '@sim/testing'
1515
import { afterEach, describe, expect, it } from 'vitest'
16-
1716
import { getInternalApiBaseUrl } from '@/lib/core/utils/urls'
1817

1918
const PUBLIC_URL = 'https://sim.ai'

apps/sim/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@
208208
"nuqs": "2.8.9",
209209
"officeparser": "^5.2.0",
210210
"openai": "7.0.0",
211+
"opentype.js": "1.3.4",
211212
"pdf-lib": "1.17.1",
212213
"pdfjs-dist": "5.4.296",
213214
"postgres": "^3.4.5",
@@ -264,6 +265,7 @@
264265
"@types/mssql": "12.3.0",
265266
"@types/node": "24.2.1",
266267
"@types/nodemailer": "8.0.1",
268+
"@types/opentype.js": "1.3.10",
267269
"@types/prismjs": "^1.26.5",
268270
"@types/react": "^19",
269271
"@types/react-dom": "^19",

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
"check:icon-path-precision": "bun run scripts/check-icon-path-precision.ts",
5252
"check:migrations": "bun run scripts/check-migrations-safety.ts",
5353
"check:native-typecheck": "bun run scripts/check-native-typecheck.ts",
54-
"check:outbound-delivery": "bun run scripts/check-outbound-delivery.ts",
5554
"check:source-text": "bun run scripts/check-source-text.ts",
5655
"check:audits": "bun run scripts/run-audits.ts",
5756
"check:skills": "bun run scripts/sync-skills.ts --check",

0 commit comments

Comments
 (0)