Skip to content

Commit 6f517d7

Browse files
lizkenyonclaude
andcommitted
Fix: guard rewriteConfiguration against non-array and nullish config values
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b107811 commit 6f517d7

3 files changed

Lines changed: 36 additions & 2 deletions

File tree

.changeset/chilly-glasses-fetch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/app': patch
3+
---
4+
5+
Fix crash "config2.map is not a function" in `rewriteConfiguration` when writing app configuration with unvalidated data (e.g., from third-party templates without `client_id`)

packages/app/src/cli/services/app/write-app-configuration-file.test.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import {writeAppConfigurationFile} from './write-app-configuration-file.js'
1+
import {rewriteConfiguration, writeAppConfigurationFile} from './write-app-configuration-file.js'
22
import {DEFAULT_CONFIG, buildVersionedAppSchema} from '../../models/app/app.test-data.js'
33
import {CurrentAppConfiguration} from '../../models/app/app.js'
44
import {inTemporaryDirectory, readFile} from '@shopify/cli-kit/node/fs'
55
import {joinPath} from '@shopify/cli-kit/node/path'
6+
import {zod} from '@shopify/cli-kit/node/schema'
67
import {describe, expect, test} from 'vitest'
78

89
const FULL_CONFIGURATION = {
@@ -151,3 +152,29 @@ url = "https://example.com/prefs"
151152
})
152153
})
153154
})
155+
156+
describe('rewriteConfiguration', () => {
157+
test('handles undefined config for an optional array schema wrapped in effects', () => {
158+
const schema = zod.array(zod.string()).optional().transform((val) => val)
159+
160+
expect(rewriteConfiguration(schema, undefined)).toBeUndefined()
161+
})
162+
163+
test('handles null config for an array schema', () => {
164+
const schema = zod.array(zod.string())
165+
166+
expect(rewriteConfiguration(schema, null)).toBeUndefined()
167+
})
168+
169+
test('handles undefined config for an object schema', () => {
170+
const schema = zod.object({name: zod.string()}).optional()
171+
172+
expect(rewriteConfiguration(schema, undefined)).toBeUndefined()
173+
})
174+
175+
test('passes through non-array value when schema expects an array', () => {
176+
const schema = zod.array(zod.string())
177+
178+
expect(rewriteConfiguration(schema, 'not-an-array')).toBe('not-an-array')
179+
})
180+
})

packages/app/src/cli/services/app/write-app-configuration-file.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ export async function writeAppConfigurationFile(
2727

2828
export const rewriteConfiguration = <T extends zod.ZodTypeAny>(schema: T, config: unknown): unknown => {
2929
if (schema === null || schema === undefined) return null
30+
if (config === null || config === undefined) return undefined
3031
if (schema instanceof zod.ZodNullable || schema instanceof zod.ZodOptional)
3132
return rewriteConfiguration(schema.unwrap(), config)
3233
if (schema instanceof zod.ZodArray) {
33-
return (config as unknown[]).map((item) => rewriteConfiguration(schema.element, item))
34+
if (!Array.isArray(config)) return config
35+
return config.map((item) => rewriteConfiguration(schema.element, item))
3436
}
3537
if (schema instanceof zod.ZodEffects) {
3638
return rewriteConfiguration(schema._def.schema, config)

0 commit comments

Comments
 (0)