diff --git a/packages/@aws-cdk/aws-amplify-alpha/lib/app.ts b/packages/@aws-cdk/aws-amplify-alpha/lib/app.ts index 057d413961dbd..ffcc482811ba6 100644 --- a/packages/@aws-cdk/aws-amplify-alpha/lib/app.ts +++ b/packages/@aws-cdk/aws-amplify-alpha/lib/app.ts @@ -316,7 +316,9 @@ export class App extends Resource implements IApp, iam.IGrantable { name: props.appName || this.node.id, oauthToken: sourceCodeProviderOptions?.oauthToken?.unsafeUnwrap(), // Safe usage repository: sourceCodeProviderOptions?.repository, - customHeaders: props.customResponseHeaders ? renderCustomResponseHeaders(props.customResponseHeaders, this) : undefined, + customHeaders: props.customResponseHeaders && props.customResponseHeaders.length > 0 + ? renderCustomResponseHeaders(props.customResponseHeaders, this) + : undefined, platform: appPlatform, jobConfig: props.buildComputeType ? { buildComputeType: props.buildComputeType } : undefined, }); @@ -594,7 +596,21 @@ export interface CustomResponseHeader { readonly headers: { [key: string]: string }; } +/** + * Renders custom response headers to YAML format. + * + * @param customHeaders - Array of custom headers. Must not be empty. + * @param scope - Construct scope for error reporting + * @returns YAML string representation of custom headers + * + * @internal + */ function renderCustomResponseHeaders(customHeaders: CustomResponseHeader[], scope: IConstruct): string { + // Defensive assertion - should never happen due to call site validation + if (customHeaders.length === 0) { + throw new ValidationError('renderCustomResponseHeaders called with empty array', scope); + } + const hasAppRoot = customHeaders[0].appRoot !== undefined; const yaml = [hasAppRoot ? 'applications:' : 'customHeaders:']; diff --git a/packages/@aws-cdk/aws-amplify-alpha/test/app.test.ts b/packages/@aws-cdk/aws-amplify-alpha/test/app.test.ts index 6903d23d7ff27..0a2814a7ec0e1 100644 --- a/packages/@aws-cdk/aws-amplify-alpha/test/app.test.ts +++ b/packages/@aws-cdk/aws-amplify-alpha/test/app.test.ts @@ -1,4 +1,4 @@ -import { Template } from 'aws-cdk-lib/assertions'; +import { Template, Match } from 'aws-cdk-lib/assertions'; import * as codebuild from 'aws-cdk-lib/aws-codebuild'; import * as codecommit from 'aws-cdk-lib/aws-codecommit'; import * as iam from 'aws-cdk-lib/aws-iam'; @@ -549,6 +549,24 @@ test('error with inconsistent appRoot in custom headers', () => { }).toThrow('appRoot must be either be present or absent across all custom response headers'); }); +test('with empty custom response headers array', () => { + // WHEN - Empty array should be handled gracefully (regression test for #35693) + new amplify.App(stack, 'App', { + sourceCodeProvider: new amplify.GitHubSourceCodeProvider({ + owner: 'aws', + repository: 'aws-cdk', + oauthToken: SecretValue.unsafePlainText('secret'), + }), + customResponseHeaders: [], + }); + + // THEN - CustomHeaders property should be omitted from CloudFormation + Template.fromStack(stack).hasResourceProperties('AWS::Amplify::App', { + Name: 'App', + CustomHeaders: Match.absent(), + }); +}); + test('create a statically hosted app by default', () => { // WHEN new amplify.App(stack, 'App', {});