Skip to content

Commit 57f9068

Browse files
authored
fix(amplify-alpha): handle empty customResponseHeaders array (#35700)
### Issue # (if applicable) Closes #35693. ### Reason for this change The `amplify.App` construct fails with a TypeError when `customResponseHeaders` is an empty array, preventing CDK synthesis. This is a regression introduced in v2.202.0 (PR #31771) that breaks applications passing an empty array to this property. ### Description of changes Added defensive checks to prevent array access on empty `customResponseHeaders` arrays: 1. **Length check** in App constructor (line 319-321): Prevents calling render function with empty arrays by checking length before invocation, ensuring CloudFormation `CustomHeaders` property is properly omitted (undefined) 2. **Defensive assertion** in `renderCustomResponseHeaders` function (line 608-611): Throws clear error if function is called with empty array, catching potential CDK programming bugs 3. **JSDoc documentation** added to clarify function contract and internal nature 4. **Unit test** enhanced with clarifying comments referencing issue #35693 The fix follows CDK defensive programming patterns with a clear separation of concerns: - **Call site validation** (line 319): Handles user input, ensures proper CloudFormation output - **Function assertion** (line 608): Catches CDK programming errors with fail-fast behavior - **Documentation**: Makes the contract explicit for future maintainers ### Description of how you validated changes - **Unit tests**: Added new test case "with empty custom response headers array" that verifies empty arrays don't cause errors and that the CloudFormation `CustomHeaders` property is correctly absent. All 45 unit tests pass (100%). - **Integration tests**: All 10 existing integration tests pass with UNCHANGED status, confirming no regression in existing functionality. The `integ.app-monorepo-custom-headers` test specifically validates custom headers behavior remains correct. - **Manual validation**: Tested the exact reproduction case from issue #35693 - empty array no longer causes TypeError and synthesis completes successfully. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent effa46d commit 57f9068

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

packages/@aws-cdk/aws-amplify-alpha/lib/app.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,9 @@ export class App extends Resource implements IApp, iam.IGrantable {
316316
name: props.appName || this.node.id,
317317
oauthToken: sourceCodeProviderOptions?.oauthToken?.unsafeUnwrap(), // Safe usage
318318
repository: sourceCodeProviderOptions?.repository,
319-
customHeaders: props.customResponseHeaders ? renderCustomResponseHeaders(props.customResponseHeaders, this) : undefined,
319+
customHeaders: props.customResponseHeaders && props.customResponseHeaders.length > 0
320+
? renderCustomResponseHeaders(props.customResponseHeaders, this)
321+
: undefined,
320322
platform: appPlatform,
321323
jobConfig: props.buildComputeType ? { buildComputeType: props.buildComputeType } : undefined,
322324
});
@@ -594,7 +596,21 @@ export interface CustomResponseHeader {
594596
readonly headers: { [key: string]: string };
595597
}
596598

599+
/**
600+
* Renders custom response headers to YAML format.
601+
*
602+
* @param customHeaders - Array of custom headers. Must not be empty.
603+
* @param scope - Construct scope for error reporting
604+
* @returns YAML string representation of custom headers
605+
*
606+
* @internal
607+
*/
597608
function renderCustomResponseHeaders(customHeaders: CustomResponseHeader[], scope: IConstruct): string {
609+
// Defensive assertion - should never happen due to call site validation
610+
if (customHeaders.length === 0) {
611+
throw new ValidationError('renderCustomResponseHeaders called with empty array', scope);
612+
}
613+
598614
const hasAppRoot = customHeaders[0].appRoot !== undefined;
599615
const yaml = [hasAppRoot ? 'applications:' : 'customHeaders:'];
600616

packages/@aws-cdk/aws-amplify-alpha/test/app.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Template } from 'aws-cdk-lib/assertions';
1+
import { Template, Match } from 'aws-cdk-lib/assertions';
22
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
33
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
44
import * as iam from 'aws-cdk-lib/aws-iam';
@@ -549,6 +549,24 @@ test('error with inconsistent appRoot in custom headers', () => {
549549
}).toThrow('appRoot must be either be present or absent across all custom response headers');
550550
});
551551

552+
test('with empty custom response headers array', () => {
553+
// WHEN - Empty array should be handled gracefully (regression test for #35693)
554+
new amplify.App(stack, 'App', {
555+
sourceCodeProvider: new amplify.GitHubSourceCodeProvider({
556+
owner: 'aws',
557+
repository: 'aws-cdk',
558+
oauthToken: SecretValue.unsafePlainText('secret'),
559+
}),
560+
customResponseHeaders: [],
561+
});
562+
563+
// THEN - CustomHeaders property should be omitted from CloudFormation
564+
Template.fromStack(stack).hasResourceProperties('AWS::Amplify::App', {
565+
Name: 'App',
566+
CustomHeaders: Match.absent(),
567+
});
568+
});
569+
552570
test('create a statically hosted app by default', () => {
553571
// WHEN
554572
new amplify.App(stack, 'App', {});

0 commit comments

Comments
 (0)