Skip to content

Commit fd2ab61

Browse files
committed
fix(workflows): check JSON editors sent under a canonical param
1 parent 5f67bf1 commit fd2ab61

3 files changed

Lines changed: 48 additions & 6 deletions

File tree

‎apps/sim/lib/workflows/application/deployments.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ async function requireMutableWorkflow(workflowId: string): Promise<void> {
102102
}
103103

104104
/**
105-
* The lint findings of the version a deploy just made live, as one warning.
105+
* The lint findings of the version a deploy admitted, as one warning. That
106+
* version serves callers once activation completes, so it is linted even while
107+
* activation is still pending.
106108
*
107109
* Deploy does not refuse on lint: findings are advisory, and some depend on the
108110
* identity that runs the workflow. But a caller that deployed without linting
@@ -127,7 +129,7 @@ async function deployedVersionLintWarning(
127129
)
128130
)
129131
if (!hasWorkflowLintIssues(report)) return undefined
130-
return `The deployed version has lint findings and may fail when it runs. ${formatWorkflowLintMessage(report)}`
132+
return `The version this deploy publishes has lint findings and may fail when it runs. ${formatWorkflowLintMessage(report)}`
131133
} catch (error) {
132134
logger.warn('Deployed version lint failed', {
133135
workflowId: context.workflowId,

‎apps/sim/lib/workflows/editing/json-literal-refs.test.ts‎

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ const MOCK_BLOCKS = vi.hoisted(
3838
condition: { field: 'operation', value: ['insert_row', 'update_row'] },
3939
},
4040
{ id: 'rows', type: 'code', language: 'json' },
41+
{
42+
id: 'filterBuilder',
43+
type: 'filter-builder',
44+
canonicalParamId: 'filterInput',
45+
mode: 'basic',
46+
},
47+
{
48+
id: 'filter',
49+
type: 'code',
50+
language: 'json',
51+
canonicalParamId: 'filterInput',
52+
mode: 'advanced',
53+
},
4154
],
4255
outputs: {},
4356
},
@@ -87,7 +100,10 @@ const START = {
87100
}
88101

89102
function graph(
90-
blocks: Record<string, { type?: string; name?: string; subBlocks?: Record<string, unknown> }>
103+
blocks: Record<
104+
string,
105+
{ type?: string; name?: string; subBlocks?: Record<string, unknown>; data?: unknown }
106+
>
91107
) {
92108
return { blocks } as Parameters<typeof collectUnquotedJsonStringReferences>[0]
93109
}
@@ -215,4 +231,22 @@ describe('collectUnquotedJsonStringReferences', () => {
215231
)
216232
expect(findings).toHaveLength(0)
217233
})
234+
235+
it('checks a JSON editor that is sent under its canonical parameter', () => {
236+
const findings = collectUnquotedJsonStringReferences(
237+
graph({
238+
start: START,
239+
query: {
240+
type: 'table_v2',
241+
name: 'Find Order',
242+
data: { canonicalModes: { filterInput: 'advanced' } },
243+
subBlocks: {
244+
operation: { value: 'query_rows' },
245+
filter: { value: '{"field": "order_id", "op": "eq", "value": <start.order_id>}' },
246+
},
247+
},
248+
})
249+
)
250+
expect(findings).toMatchObject([{ blockId: 'query', field: 'filter' }])
251+
})
218252
})

‎apps/sim/lib/workflows/editing/lint.ts‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -799,15 +799,21 @@ export function collectUnquotedJsonStringReferences(
799799
(subBlock) => subBlock.type === 'code' && subBlock.language === 'json'
800800
)
801801
if (!jsonFields?.length) continue
802-
/** Only what the serializer sends: a field the selected operation drops never runs. */
802+
/**
803+
* Only what the serializer sends: a field the selected operation or mode
804+
* drops never runs, and a canonical member is sent under its canonical id.
805+
*/
803806
let params: Record<string, unknown>
804807
try {
805808
params = extractBlockParams(block as Parameters<typeof extractBlockParams>[0])
806809
} catch {
807810
continue
808811
}
809-
for (const field of new Set(jsonFields.map((subBlock) => subBlock.id))) {
810-
const json = params[field]
812+
const sentParamByField = new Map(
813+
jsonFields.map((subBlock) => [subBlock.id, subBlock.canonicalParamId ?? subBlock.id])
814+
)
815+
for (const [field, param] of sentParamByField) {
816+
const json = params[param]
811817
if (typeof json !== 'string') continue
812818
const unquoted = new Set<string>()
813819
for (const token of unquotedJsonReferenceTokens(json)) {

0 commit comments

Comments
 (0)