diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets.json new file mode 100644 index 0000000000000..1b4bb946623bb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "displayName": "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC Template", + "source": { + "path": "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-d8d86b35": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/cdk.out new file mode 100644 index 0000000000000..523a9aac37cbf --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"48.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ-cloudfront-response-completion-timeout.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ-cloudfront-response-completion-timeout.assets.json new file mode 100644 index 0000000000000..4a57c56b2998f --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ-cloudfront-response-completion-timeout.assets.json @@ -0,0 +1,20 @@ +{ + "version": "48.0.0", + "files": { + "fce5ba9671d1ea9abce1ac791616e045bbd5e41cedf0132dabd628463a77f4f2": { + "displayName": "integ-cloudfront-response-completion-timeout Template", + "source": { + "path": "integ-cloudfront-response-completion-timeout.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region-c26d69b3": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "fce5ba9671d1ea9abce1ac791616e045bbd5e41cedf0132dabd628463a77f4f2.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ-cloudfront-response-completion-timeout.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ-cloudfront-response-completion-timeout.template.json new file mode 100644 index 0000000000000..ac95cb730a7e3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ-cloudfront-response-completion-timeout.template.json @@ -0,0 +1,217 @@ +{ + "Resources": { + "FunctionServiceRole675BB04A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "Function76856677": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "ZipFile": "exports.handler = async () => ({ statusCode: 200, body: \"Hello from Lambda!\" });" + }, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "FunctionServiceRole675BB04A", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "FunctionServiceRole675BB04A" + ] + }, + "FunctionLogGroup55B80E27": { + "Type": "AWS::Logs::LogGroup", + "Properties": { + "LogGroupName": { + "Fn::Join": [ + "", + [ + "/aws/lambda/", + { + "Ref": "Function76856677" + } + ] + ] + }, + "RetentionInDays": 731 + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "FunctionFunctionUrl08F79AC9": { + "Type": "AWS::Lambda::Url", + "Properties": { + "AuthType": "NONE", + "TargetFunctionArn": { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + } + } + }, + "FunctioninvokefunctionurlA70D8F37": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "Action": "lambda:InvokeFunctionUrl", + "FunctionName": { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + }, + "FunctionUrlAuthType": "NONE", + "Principal": "*" + } + }, + "Distribution830FAC52": { + "Type": "AWS::CloudFront::Distribution", + "Properties": { + "DistributionConfig": { + "CacheBehaviors": [ + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "/api/*", + "TargetOriginId": "integcloudfrontresponsecompletiontimeoutDistributionOrigin24E64923B", + "ViewerProtocolPolicy": "allow-all" + }, + { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "PathPattern": "/files/*", + "TargetOriginId": "integcloudfrontresponsecompletiontimeoutDistributionOrigin36D3F546F", + "ViewerProtocolPolicy": "allow-all" + } + ], + "DefaultCacheBehavior": { + "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6", + "Compress": true, + "TargetOriginId": "integcloudfrontresponsecompletiontimeoutDistributionOrigin1B68EA04D", + "ViewerProtocolPolicy": "allow-all" + }, + "Enabled": true, + "HttpVersion": "http2", + "IPV6Enabled": true, + "Origins": [ + { + "CustomOriginConfig": { + "OriginProtocolPolicy": "https-only", + "OriginReadTimeout": 60, + "OriginSSLProtocols": [ + "TLSv1.2" + ] + }, + "DomainName": "example.com", + "Id": "integcloudfrontresponsecompletiontimeoutDistributionOrigin1B68EA04D", + "ResponseCompletionTimeout": 120 + }, + { + "CustomOriginConfig": { + "OriginProtocolPolicy": "https-only", + "OriginReadTimeout": 30, + "OriginSSLProtocols": [ + "TLSv1.2" + ] + }, + "DomainName": { + "Fn::Select": [ + 2, + { + "Fn::Split": [ + "/", + { + "Fn::GetAtt": [ + "FunctionFunctionUrl08F79AC9", + "FunctionUrl" + ] + } + ] + } + ] + }, + "Id": "integcloudfrontresponsecompletiontimeoutDistributionOrigin24E64923B", + "ResponseCompletionTimeout": 90 + }, + { + "CustomOriginConfig": { + "OriginProtocolPolicy": "https-only", + "OriginSSLProtocols": [ + "TLSv1.2" + ] + }, + "DomainName": "api.example.com", + "Id": "integcloudfrontresponsecompletiontimeoutDistributionOrigin36D3F546F", + "ResponseCompletionTimeout": 300 + } + ] + } + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ.json new file mode 100644 index 0000000000000..7f6abae4eae49 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "48.0.0", + "testCases": { + "CloudFrontResponseCompletionTimeoutTest/DefaultTest": { + "stacks": [ + "integ-cloudfront-response-completion-timeout" + ], + "assertionStack": "CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert", + "assertionStackName": "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC" + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/manifest.json new file mode 100644 index 0000000000000..114e7898e8ad8 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/manifest.json @@ -0,0 +1,666 @@ +{ + "version": "48.0.0", + "artifacts": { + "integ-cloudfront-response-completion-timeout.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-cloudfront-response-completion-timeout.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-cloudfront-response-completion-timeout": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-cloudfront-response-completion-timeout.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/fce5ba9671d1ea9abce1ac791616e045bbd5e41cedf0132dabd628463a77f4f2.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-cloudfront-response-completion-timeout.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integ-cloudfront-response-completion-timeout.assets" + ], + "metadata": { + "/integ-cloudfront-response-completion-timeout/Function": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/ServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/ServiceRole/ImportServiceRole": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctionServiceRole675BB04A" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Function76856677" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/LogGroup": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/LogGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctionLogGroup55B80E27" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/FunctionUrl": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/FunctionUrl/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctionFunctionUrl08F79AC9" + } + ], + "/integ-cloudfront-response-completion-timeout/Function/invoke-function-url": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctioninvokefunctionurlA70D8F37" + } + ], + "/integ-cloudfront-response-completion-timeout/Distribution": [ + { + "type": "aws:cdk:analytics:construct", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + }, + { + "type": "aws:cdk:analytics:method", + "data": "*" + } + ], + "/integ-cloudfront-response-completion-timeout/Distribution/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Distribution830FAC52" + } + ], + "/integ-cloudfront-response-completion-timeout/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-cloudfront-response-completion-timeout/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-cloudfront-response-completion-timeout" + }, + "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "CloudFrontResponseCompletionTimeoutTestDefaultTestDeployAssert28BE7FDC.assets" + ], + "metadata": { + "/CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-lib/feature-flag-report": { + "type": "cdk:feature-flag-report", + "properties": { + "module": "aws-cdk-lib", + "flags": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": { + "recommendedValue": true, + "explanation": "Pass signingProfileName to CfnSigningProfile" + }, + "@aws-cdk/core:newStyleStackSynthesis": { + "recommendedValue": true, + "explanation": "Switch to new stack synthesis method which enables CI/CD", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:stackRelativeExports": { + "recommendedValue": true, + "explanation": "Name exports based on the construct paths relative to the stack, rather than the global construct path", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": { + "recommendedValue": true, + "explanation": "Disable implicit openListener when custom security groups are provided" + }, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": { + "recommendedValue": true, + "explanation": "Force lowercasing of RDS Cluster names in CDK", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": { + "recommendedValue": true, + "explanation": "Allow adding/removing multiple UsagePlanKeys independently", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeVersionProps": { + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-lambda:recognizeLayerVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`." + }, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": { + "recommendedValue": true, + "explanation": "Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:checkSecretUsage": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations" + }, + "@aws-cdk/core:target-partitions": { + "recommendedValue": [ + "aws", + "aws-cn" + ], + "explanation": "What regions to include in lookup tables of environment agnostic stacks" + }, + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": { + "userValue": true, + "recommendedValue": true, + "explanation": "ECS extensions will automatically add an `awslogs` driver if no logging is specified" + }, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names." + }, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": { + "userValue": true, + "recommendedValue": true, + "explanation": "ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID." + }, + "@aws-cdk/aws-iam:minimizePolicies": { + "userValue": true, + "recommendedValue": true, + "explanation": "Minimize IAM policies by combining Statements" + }, + "@aws-cdk/core:validateSnapshotRemovalPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Error on snapshot removal policies on resources that do not support it." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate key aliases that include the stack name" + }, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist." + }, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict KMS key policy for encrypted Queues a bit more" + }, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make default CloudWatch Role behavior safe for multiple API Gateways in one environment" + }, + "@aws-cdk/core:enablePartitionLiterals": { + "userValue": true, + "recommendedValue": true, + "explanation": "Make ARNs concrete if AWS partition is known" + }, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": { + "userValue": true, + "recommendedValue": true, + "explanation": "Event Rules may only push to encrypted SQS queues in the same account" + }, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": { + "userValue": true, + "recommendedValue": true, + "explanation": "Avoid setting the \"ECS\" deployment controller when adding a circuit breaker" + }, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable this feature to by default create default policy names for imported roles that depend on the stack the role is in." + }, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use S3 Bucket Policy instead of ACLs for Server Access Logging" + }, + "@aws-cdk/aws-route53-patters:useCertificate": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use the official `Certificate` resource instead of `DnsValidatedCertificate`" + }, + "@aws-cdk/customresources:installLatestAwsSdkDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "Whether to install the latest SDK by default in AwsCustomResource" + }, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": { + "userValue": true, + "recommendedValue": true, + "explanation": "Use unique resource name for Database Proxy" + }, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Remove CloudWatch alarms from deployment group" + }, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include authorizer configuration in the calculation of the API deployment logical ID." + }, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": { + "userValue": true, + "recommendedValue": true, + "explanation": "Define user data for a launch template by default when a machine image is provided." + }, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": { + "userValue": true, + "recommendedValue": true, + "explanation": "SecretTargetAttachments uses the ResourcePolicy of the attached Secret." + }, + "@aws-cdk/aws-redshift:columnId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Whether to use an ID to track Redshift column changes" + }, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable AmazonEMRServicePolicy_v2 managed policies" + }, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "Restrict access to the VPC default security group" + }, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a unique id for each RequestValidator added to a method" + }, + "@aws-cdk/aws-kms:aliasNameRef": { + "userValue": true, + "recommendedValue": true, + "explanation": "KMS Alias name and keyArn will have implicit reference to KMS Key" + }, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enable grant methods on Aliases imported by name to use kms:ResourceAliases condition" + }, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": { + "userValue": true, + "recommendedValue": true, + "explanation": "Generate a launch template when creating an AutoScalingGroup" + }, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": { + "userValue": true, + "recommendedValue": true, + "explanation": "Include the stack prefix in the stack name generation process" + }, + "@aws-cdk/aws-efs:denyAnonymousAccess": { + "userValue": true, + "recommendedValue": true, + "explanation": "EFS denies anonymous clients accesses" + }, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables support for Multi-AZ with Standby deployment for opensearch domains" + }, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables aws-lambda-nodejs.Function to use the latest available NodeJs runtime as the default" + }, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, mount targets will have a stable logicalId that is linked to the associated subnet." + }, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a scope of InstanceParameterGroup for AuroraClusterInstance with each parameters will change." + }, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, will always use the arn for identifiers for CfnSourceApiAssociation in the GraphqlApi construct rather than id." + }, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, creating an RDS database cluster from a snapshot will only render credentials for snapshot credentials." + }, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the CodeCommit source action is using the default branch name 'main'." + }, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the logical ID of a Lambda permission for a Lambda action includes an alarm ID." + }, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default value for crossAccountKeys to false." + }, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "Enables Pipeline to set the default pipeline type to V2." + }, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only." + }, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from PipelineAssetsFileRole trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-eks:nodegroupNameAttribute": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix." + }, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default volume type of the EBS volume will be GP3" + }, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, remove default deployment alarm settings" + }, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default" + }, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": { + "userValue": false, + "recommendedValue": false, + "explanation": "When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack." + }, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": { + "recommendedValue": true, + "explanation": "When enabled, use new props for S3 URI field in task definition of state machine for bedrock invoke model.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/core:explicitStackTags": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, stack tags need to be assigned explicitly on a Stack." + }, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": { + "userValue": false, + "recommendedValue": false, + "explanation": "When set to true along with canContainersAccessInstanceRole=false in ECS cluster, new updated commands will be added to UserData to block container accessing IMDS. **Applicable to Linux only. IMPORTANT: See [details.](#aws-cdkaws-ecsenableImdsBlockingDeprecatedFeature)**" + }, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, CDK synth will throw exception if canContainersAccessInstanceRole is false. **IMPORTANT: See [details.](#aws-cdkaws-ecsdisableEcsImdsBlocking)**" + }, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, we will only grant the necessary permissions when users specify cloudwatch log group through logConfiguration" + }, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled will allow you to specify a resource policy per replica, and not copy the source table policy to all replicas" + }, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, initOptions.timeout and resourceSignalTimeout values will be summed together." + }, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, a Lambda authorizer Permission created when using GraphqlApi will be properly scoped with a SourceArn." + }, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the value of property `instanceResourceId` in construct `DatabaseInstanceReadReplica` will be set to the correct value which is `DbiResourceId` instead of currently `DbInstanceArn`" + }, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CFN templates added with `cfn-include` will error if the template contains Resource Update or Create policies with CFN Intrinsics that include non-primitive values." + }, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, both `@aws-sdk` and `@smithy` packages will be excluded from the Lambda Node.js 18.x runtime to prevent version mismatches in bundled applications." + }, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resource of IAM Run Ecs policy generated by SFN EcsRunTask will reference the definition, instead of constructing ARN." + }, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the BastionHost construct will use the latest Amazon Linux 2023 AMI, instead of Amazon Linux 2." + }, + "@aws-cdk/core:aspectStabilization": { + "recommendedValue": true, + "explanation": "When enabled, a stabilization loop will be run when invoking Aspects during synthesis.", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, use a new method for DNS Name of user pool domain target without creating a custom resource." + }, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default security group ingress rules will allow IPv6 ingress from anywhere" + }, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the default behaviour of OIDC provider will reject unauthorized connections" + }, + "@aws-cdk/core:enableAdditionalMetadataCollection": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will expand the scope of usage data collected to better inform CDK development and improve communication for security concerns and emerging issues." + }, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": { + "userValue": false, + "recommendedValue": false, + "explanation": "[Deprecated] When enabled, Lambda will create new inline policies with AddToRolePolicy instead of adding to the Default Policy Statement" + }, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK will automatically generate a unique role name that is used for s3 object replication." + }, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": { + "recommendedValue": true, + "explanation": "Remove the root account principal from Stage addActions trust policy", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-events:requireEventBusPolicySid": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, grantPutEventsTo() will use resource policies with Statement IDs for service principals." + }, + "@aws-cdk/core:aspectPrioritiesMutating": { + "userValue": true, + "recommendedValue": true, + "explanation": "When set to true, Aspects added by the construct library on your behalf will be given a priority of MUTATING." + }, + "@aws-cdk/aws-dynamodb:retainTableReplica": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, table replica will be default to the removal policy of source table unless specified otherwise." + }, + "@aws-cdk/cognito:logUserPoolClientSecretValue": { + "recommendedValue": false, + "explanation": "When disabled, the value of the user pool client secret will not be logged in the custom resource lambda function logs." + }, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": { + "recommendedValue": true, + "explanation": "When enabled, scopes down the trust policy for the cross-account action role", + "unconfiguredBehavesLike": { + "v2": true + } + }, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the resultWriterV2 property of DistributedMap will be used insted of resultWriter" + }, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": { + "userValue": true, + "recommendedValue": true, + "explanation": "Add an S3 trust policy to a KMS key resource policy for SNS subscriptions." + }, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, the EgressOnlyGateway resource is only created if private subnets are defined in the dual-stack VPC." + }, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": { + "recommendedValue": false, + "explanation": "When enabled, use resource IDs for VPC V2 migration" + }, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, setting any combination of options for BlockPublicAccess will automatically set true for any options not defined." + }, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": { + "userValue": true, + "recommendedValue": true, + "explanation": "When enabled, CDK creates and manages loggroup for the lambda function" + } + } + } + } + }, + "minimumCliVersion": "2.1027.0" +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/tree.json new file mode 100644 index 0000000000000..42332b6f9f2d6 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.js.snapshot/tree.json @@ -0,0 +1 @@ +{"version":"tree-0.1","tree":{"id":"App","path":"","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"children":{"integ-cloudfront-response-completion-timeout":{"id":"integ-cloudfront-response-completion-timeout","path":"integ-cloudfront-response-completion-timeout","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"children":{"Function":{"id":"Function","path":"integ-cloudfront-response-completion-timeout/Function","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]},"children":{"ServiceRole":{"id":"ServiceRole","path":"integ-cloudfront-response-completion-timeout/Function/ServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]},"children":{"ImportServiceRole":{"id":"ImportServiceRole","path":"integ-cloudfront-response-completion-timeout/Function/ServiceRole/ImportServiceRole","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]}},"Resource":{"id":"Resource","path":"integ-cloudfront-response-completion-timeout/Function/ServiceRole/Resource","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"attributes":{"aws:cdk:cloudformation:type":"AWS::IAM::Role","aws:cdk:cloudformation:props":{"assumeRolePolicyDocument":{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"}}],"Version":"2012-10-17"},"managedPolicyArns":[{"Fn::Join":["",["arn:",{"Ref":"AWS::Partition"},":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]]}]}}}}},"Resource":{"id":"Resource","path":"integ-cloudfront-response-completion-timeout/Function/Resource","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Function","aws:cdk:cloudformation:props":{"code":{"zipFile":"exports.handler = async () => ({ statusCode: 200, body: \"Hello from Lambda!\" });"},"handler":"index.handler","role":{"Fn::GetAtt":["FunctionServiceRole675BB04A","Arn"]},"runtime":"nodejs18.x"}}},"LogGroup":{"id":"LogGroup","path":"integ-cloudfront-response-completion-timeout/Function/LogGroup","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]},"children":{"Resource":{"id":"Resource","path":"integ-cloudfront-response-completion-timeout/Function/LogGroup/Resource","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Logs::LogGroup","aws:cdk:cloudformation:props":{"logGroupName":{"Fn::Join":["",["/aws/lambda/",{"Ref":"Function76856677"}]]},"retentionInDays":731}}}}},"FunctionUrl":{"id":"FunctionUrl","path":"integ-cloudfront-response-completion-timeout/Function/FunctionUrl","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*"]},"children":{"Resource":{"id":"Resource","path":"integ-cloudfront-response-completion-timeout/Function/FunctionUrl/Resource","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Url","aws:cdk:cloudformation:props":{"authType":"NONE","targetFunctionArn":{"Fn::GetAtt":["Function76856677","Arn"]}}}}}},"invoke-function-url":{"id":"invoke-function-url","path":"integ-cloudfront-response-completion-timeout/Function/invoke-function-url","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"attributes":{"aws:cdk:cloudformation:type":"AWS::Lambda::Permission","aws:cdk:cloudformation:props":{"action":"lambda:InvokeFunctionUrl","functionName":{"Fn::GetAtt":["Function76856677","Arn"]},"functionUrlAuthType":"NONE","principal":"*"}}}}},"Distribution":{"id":"Distribution","path":"integ-cloudfront-response-completion-timeout/Distribution","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2","metadata":["*","*","*"]},"children":{"Origin1":{"id":"Origin1","path":"integ-cloudfront-response-completion-timeout/Distribution/Origin1","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Origin2":{"id":"Origin2","path":"integ-cloudfront-response-completion-timeout/Distribution/Origin2","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Origin3":{"id":"Origin3","path":"integ-cloudfront-response-completion-timeout/Distribution/Origin3","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"Resource":{"id":"Resource","path":"integ-cloudfront-response-completion-timeout/Distribution/Resource","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"attributes":{"aws:cdk:cloudformation:type":"AWS::CloudFront::Distribution","aws:cdk:cloudformation:props":{"distributionConfig":{"enabled":true,"origins":[{"domainName":"example.com","id":"integcloudfrontresponsecompletiontimeoutDistributionOrigin1B68EA04D","customOriginConfig":{"originSslProtocols":["TLSv1.2"],"originProtocolPolicy":"https-only","originReadTimeout":60},"responseCompletionTimeout":120},{"domainName":{"Fn::Select":[2,{"Fn::Split":["/",{"Fn::GetAtt":["FunctionFunctionUrl08F79AC9","FunctionUrl"]}]}]},"id":"integcloudfrontresponsecompletiontimeoutDistributionOrigin24E64923B","customOriginConfig":{"originSslProtocols":["TLSv1.2"],"originProtocolPolicy":"https-only","originReadTimeout":30},"responseCompletionTimeout":90},{"domainName":"api.example.com","id":"integcloudfrontresponsecompletiontimeoutDistributionOrigin36D3F546F","customOriginConfig":{"originSslProtocols":["TLSv1.2"],"originProtocolPolicy":"https-only"},"responseCompletionTimeout":300}],"defaultCacheBehavior":{"pathPattern":"*","targetOriginId":"integcloudfrontresponsecompletiontimeoutDistributionOrigin1B68EA04D","cachePolicyId":"658327ea-f89d-4fab-a63d-7e88639e58f6","compress":true,"viewerProtocolPolicy":"allow-all"},"cacheBehaviors":[{"pathPattern":"/api/*","targetOriginId":"integcloudfrontresponsecompletiontimeoutDistributionOrigin24E64923B","cachePolicyId":"658327ea-f89d-4fab-a63d-7e88639e58f6","compress":true,"viewerProtocolPolicy":"allow-all"},{"pathPattern":"/files/*","targetOriginId":"integcloudfrontresponsecompletiontimeoutDistributionOrigin36D3F546F","cachePolicyId":"658327ea-f89d-4fab-a63d-7e88639e58f6","compress":true,"viewerProtocolPolicy":"allow-all"}],"httpVersion":"http2","ipv6Enabled":true}}}}}},"BootstrapVersion":{"id":"BootstrapVersion","path":"integ-cloudfront-response-completion-timeout/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"integ-cloudfront-response-completion-timeout/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}},"CloudFrontResponseCompletionTimeoutTest":{"id":"CloudFrontResponseCompletionTimeoutTest","path":"CloudFrontResponseCompletionTimeoutTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTest","version":"0.0.0"},"children":{"DefaultTest":{"id":"DefaultTest","path":"CloudFrontResponseCompletionTimeoutTest/DefaultTest","constructInfo":{"fqn":"@aws-cdk/integ-tests-alpha.IntegTestCase","version":"0.0.0"},"children":{"Default":{"id":"Default","path":"CloudFrontResponseCompletionTimeoutTest/DefaultTest/Default","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"DeployAssert":{"id":"DeployAssert","path":"CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"},"children":{"BootstrapVersion":{"id":"BootstrapVersion","path":"CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert/BootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}},"CheckBootstrapVersion":{"id":"CheckBootstrapVersion","path":"CloudFrontResponseCompletionTimeoutTest/DefaultTest/DeployAssert/CheckBootstrapVersion","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}}}}},"Tree":{"id":"Tree","path":"Tree","constructInfo":{"fqn":"constructs.Construct","version":"10.4.2"}}}}} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.ts new file mode 100644 index 0000000000000..7f7e9bc4452d1 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-cloudfront-origins/test/integ.origin-response-completion-timeout.ts @@ -0,0 +1,50 @@ +import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; +import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as cdk from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'integ-cloudfront-response-completion-timeout'); + +const httpOrigin = new origins.HttpOrigin('example.com', { + responseCompletionTimeout: cdk.Duration.seconds(120), + readTimeout: cdk.Duration.seconds(60), +}); + +const fn = new lambda.Function(stack, 'Function', { + runtime: lambda.Runtime.NODEJS_18_X, + handler: 'index.handler', + code: lambda.Code.fromInline('exports.handler = async () => ({ statusCode: 200, body: "Hello from Lambda!" });'), +}); + +const fnUrl = fn.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.NONE, +}); + +const functionUrlOrigin = new origins.FunctionUrlOrigin(fnUrl, { + responseCompletionTimeout: cdk.Duration.seconds(90), + readTimeout: cdk.Duration.seconds(30), +}); + +const httpOriginNoReadTimeout = new origins.HttpOrigin('api.example.com', { + responseCompletionTimeout: cdk.Duration.seconds(300), +}); + +new cloudfront.Distribution(stack, 'Distribution', { + defaultBehavior: { + origin: httpOrigin, + }, + additionalBehaviors: { + '/api/*': { + origin: functionUrlOrigin, + }, + '/files/*': { + origin: httpOriginNoReadTimeout, + }, + }, +}); + +new IntegTest(app, 'CloudFrontResponseCompletionTimeoutTest', { + testCases: [stack], +}); diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/README.md b/packages/aws-cdk-lib/aws-cloudfront-origins/README.md index 04af3ff831f99..57285cffc998e 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/README.md +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/README.md @@ -577,6 +577,7 @@ const origin = new origins.LoadBalancerV2Origin(loadBalancer, { connectionAttempts: 3, connectionTimeout: Duration.seconds(5), readTimeout: Duration.seconds(45), + responseCompletionTimeout: Duration.seconds(120), keepaliveTimeout: Duration.seconds(45), protocolPolicy: cloudfront.OriginProtocolPolicy.MATCH_VIEWER, }); @@ -596,6 +597,22 @@ new cloudfront.Distribution(this, 'myDist', { }); ``` +The origin can be customized with timeout settings to handle different response scenarios: + +```ts +new cloudfront.Distribution(this, 'Distribution', { + defaultBehavior: { + origin: new origins.HttpOrigin('api.example.com', { + readTimeout: Duration.seconds(60), + responseCompletionTimeout: Duration.seconds(120), + keepaliveTimeout: Duration.seconds(45), + }), + }, +}); +``` + +The `responseCompletionTimeout` property specifies the time that a request from CloudFront to the origin can stay open and wait for a response. If the complete response isn't received from the origin by this time, CloudFront ends the connection. Valid values are 1-3600 seconds, and if set, the value must be equal to or greater than the `readTimeout` value. + See the documentation of `aws-cdk-lib/aws-cloudfront` for more information. ## VPC origins @@ -801,6 +818,25 @@ new cloudfront.Distribution(this, 'Distribution', { }); ``` +You can also configure timeout settings for Lambda Function URL origins: + +```ts +import * as lambda from 'aws-cdk-lib/aws-lambda'; + +declare const fn: lambda.Function; +const fnUrl = fn.addFunctionUrl({ authType: lambda.FunctionUrlAuthType.NONE }); + +new cloudfront.Distribution(this, 'Distribution', { + defaultBehavior: { + origin: new origins.FunctionUrlOrigin(fnUrl, { + readTimeout: Duration.seconds(30), + responseCompletionTimeout: Duration.seconds(90), + keepaliveTimeout: Duration.seconds(45), + }), + }, +}); +``` + ### Lambda Function URL with Origin Access Control (OAC) You can configure the Lambda Function URL with Origin Access Control (OAC) for enhanced security. When using OAC with Signing SIGV4_ALWAYS, it is recommended to set the Lambda Function URL authType to AWS_IAM to ensure proper authorization. diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts index 98240667c9aa2..a43d7604cd19d 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts @@ -68,6 +68,7 @@ export class FunctionUrlOrigin extends cloudfront.OriginBase { validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + this.validateResponseCompletionTimeoutWithReadTimeout(props.responseCompletionTimeout, props.readTimeout); } protected renderCustomOriginConfig(): cloudfront.CfnDistribution.CustomOriginConfigProperty | undefined { diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts index 30526dfcfb0eb..8259db8f2a6b5 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts @@ -66,6 +66,7 @@ export class HttpOrigin extends cloudfront.OriginBase { validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + this.validateResponseCompletionTimeoutWithReadTimeout(props.responseCompletionTimeout, props.readTimeout); } protected renderCustomOriginConfig(): cloudfront.CfnDistribution.CustomOriginConfigProperty | undefined { diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts index 904b13623aacc..863edea868912 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts @@ -45,6 +45,7 @@ export class RestApiOrigin extends cloudfront.OriginBase { validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + this.validateResponseCompletionTimeoutWithReadTimeout(props.responseCompletionTimeout, props.readTimeout); } protected renderCustomOriginConfig(): cloudfront.CfnDistribution.CustomOriginConfigProperty | undefined { diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/test/function-url-origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/test/function-url-origin.test.ts index f9aa1099da87e..8ad5baf8182f7 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/test/function-url-origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/test/function-url-origin.test.ts @@ -441,4 +441,100 @@ describe('FunctionUrlOriginAccessControl', () => { }); }).toThrow('The authType of the Function URL must be set to AWS_IAM when origin access control signing method is SIGV4_ALWAYS.'); }); + + test('renders responseCompletionTimeout in origin property', () => { + const fn = new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('exports.handler = async () => {};'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_20_X, + }); + + const fnUrl = fn.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.NONE, + }); + + const origin = new FunctionUrlOrigin(fnUrl, { + responseCompletionTimeout: Duration.seconds(120), + }); + + const originBindConfig = origin.bind(stack, { originId: 'StackOriginLambdaFunctionURL' }); + + expect(stack.resolve(originBindConfig.originProperty)).toEqual({ + id: 'StackOriginLambdaFunctionURL', + domainName: { + 'Fn::Select': [ + 2, + { + 'Fn::Split': [ + '/', + { 'Fn::GetAtt': ['MyFunctionFunctionUrlFF6DE78C', 'FunctionUrl'] }, + ], + }, + ], + }, + responseCompletionTimeout: 120, + customOriginConfig: { + originProtocolPolicy: 'https-only', + originSslProtocols: ['TLSv1.2'], + }, + }); + }); + + test('configure both responseCompletionTimeout and readTimeout', () => { + const fn = new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('exports.handler = async () => {};'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_20_X, + }); + + const fnUrl = fn.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.NONE, + }); + + const origin = new FunctionUrlOrigin(fnUrl, { + responseCompletionTimeout: Duration.seconds(60), + readTimeout: Duration.seconds(60), + }); + + const originBindConfig = origin.bind(stack, { originId: 'StackOriginLambdaFunctionURL' }); + + expect(stack.resolve(originBindConfig.originProperty)).toEqual({ + id: 'StackOriginLambdaFunctionURL', + domainName: { + 'Fn::Select': [ + 2, + { + 'Fn::Split': [ + '/', + { 'Fn::GetAtt': ['MyFunctionFunctionUrlFF6DE78C', 'FunctionUrl'] }, + ], + }, + ], + }, + responseCompletionTimeout: 60, + customOriginConfig: { + originProtocolPolicy: 'https-only', + originSslProtocols: ['TLSv1.2'], + originReadTimeout: 60, + }, + }); + }); + + test('throw error for configuring readTimeout less than responseCompletionTimeout value', () => { + const fn = new lambda.Function(stack, 'MyFunction', { + code: lambda.Code.fromInline('exports.handler = async () => {};'), + handler: 'index.handler', + runtime: lambda.Runtime.NODEJS_20_X, + }); + const fnUrl = fn.addFunctionUrl({ + authType: lambda.FunctionUrlAuthType.NONE, + }); + + expect(() => { + new FunctionUrlOrigin(fnUrl, { + responseCompletionTimeout: Duration.seconds(30), + readTimeout: Duration.seconds(60), + }); + }).toThrow('responseCompletionTimeout must be equal to or greater than readTimeout (60s), got: 30s.'); + }); }); diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts index fce80fd25375e..2119965f061de 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts @@ -7,7 +7,7 @@ let stack: Stack; beforeEach(() => { app = new App(); - new Stack(app, 'Stack', { + stack = new Stack(app, 'Stack', { env: { account: '1234', region: 'testregion' }, }); }); @@ -114,3 +114,56 @@ test.each([ }); }).toThrow(/must be a whole number of/); }); + +test('renders responseCompletionTimeout in origin property', () => { + const origin = new HttpOrigin('www.example.com', { + responseCompletionTimeout: Duration.seconds(120), + }); + const originBindConfig = origin.bind(stack, { originId: 'StackOrigin029E19582' }); + + expect(originBindConfig.originProperty).toEqual({ + id: 'StackOrigin029E19582', + domainName: 'www.example.com', + originCustomHeaders: undefined, + originPath: undefined, + responseCompletionTimeout: 120, + customOriginConfig: { + originProtocolPolicy: 'https-only', + originSslProtocols: [ + 'TLSv1.2', + ], + }, + }); +}); + +test('configure both responseCompletionTimeout and readTimeout', () => { + const origin = new HttpOrigin('www.example.com', { + responseCompletionTimeout: Duration.seconds(60), + readTimeout: Duration.seconds(60), + }); + + const originBindConfig = origin.bind(stack, { originId: 'StackOrigin029E19582' }); + expect(originBindConfig.originProperty).toEqual({ + id: 'StackOrigin029E19582', + domainName: 'www.example.com', + originCustomHeaders: undefined, + originPath: undefined, + responseCompletionTimeout: 60, + customOriginConfig: { + originProtocolPolicy: 'https-only', + originSslProtocols: [ + 'TLSv1.2', + ], + originReadTimeout: 60, + }, + }); +}); + +test('throw error for configuring readTimeout less than responseCompletionTimeout value', () => { + expect(() => { + new HttpOrigin('www.example.com', { + responseCompletionTimeout: Duration.seconds(30), + readTimeout: Duration.seconds(60), + }); + }).toThrow('responseCompletionTimeout must be equal to or greater than readTimeout (60s), got: 30s.'); +}); diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/test/load-balancer-origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/test/load-balancer-origin.test.ts index 071687db26d4f..8d19387dd74be 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/test/load-balancer-origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/test/load-balancer-origin.test.ts @@ -61,3 +61,46 @@ test('Can customize properties of the origin', () => { }, }); }); + +test('renders responseCompletionTimeout in origin property', () => { + const loadBalancer = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'elbv2', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:111111111111:loadbalancer/net/mylb/5d1b75f4f1cee11e', + loadBalancerDnsName: 'mylb-5d1b75f4f1cee11e.elb.us-west-2.amazonaws.com', + }); + + const origin = new LoadBalancerV2Origin(loadBalancer, { + responseCompletionTimeout: Duration.seconds(120), + }); + const originBindConfig = origin.bind(stack, { originId: 'StackOrigin029E19582' }); + + expect(originBindConfig.originProperty?.responseCompletionTimeout).toEqual(120); +}); + +test('configure both responseCompletionTimeout and readTimeout', () => { + const loadBalancer = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'elbv2', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:111111111111:loadbalancer/net/mylb/5d1b75f4f1cee11e', + loadBalancerDnsName: 'mylb-5d1b75f4f1cee11e.elb.us-west-2.amazonaws.com', + }); + + const origin = new LoadBalancerV2Origin(loadBalancer, { + responseCompletionTimeout: Duration.seconds(60), + readTimeout: Duration.seconds(60), + }); + + const originBindConfig = origin.bind(stack, { originId: 'StackOrigin029E19582' }); + expect(originBindConfig.originProperty?.responseCompletionTimeout).toEqual(60); +}); + +test('throw error for configuring readTimeout less than responseCompletionTimeout value', () => { + const loadBalancer = elbv2.NetworkLoadBalancer.fromNetworkLoadBalancerAttributes(stack, 'elbv2', { + loadBalancerArn: 'arn:aws:elasticloadbalancing:us-west-2:111111111111:loadbalancer/net/mylb/5d1b75f4f1cee11e', + loadBalancerDnsName: 'mylb-5d1b75f4f1cee11e.elb.us-west-2.amazonaws.com', + }); + + expect(() => { + new LoadBalancerV2Origin(loadBalancer, { + responseCompletionTimeout: Duration.seconds(30), + readTimeout: Duration.seconds(60), + }); + }).toThrow('responseCompletionTimeout must be equal to or greater than readTimeout (60s), got: 30s.'); +}); diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/test/rest-api-origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/test/rest-api-origin.test.ts index b874a5817e556..91d1c964011f5 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/test/rest-api-origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/test/rest-api-origin.test.ts @@ -1,5 +1,5 @@ import * as apigateway from '../../aws-apigateway'; -import { Stack } from '../../core'; +import { Duration, Stack } from '../../core'; import { RestApiOrigin } from '../lib'; let stack: Stack; @@ -148,3 +148,40 @@ test('Correctly renders the origin, with custom originPath', () => { }, }); }); + +test('renders responseCompletionTimeout in origin property', () => { + const api = new apigateway.RestApi(stack, 'RestApi'); + api.root.addMethod('GET'); + + const origin = new RestApiOrigin(api, { + responseCompletionTimeout: Duration.seconds(120), + }); + const originBindConfig = origin.bind(stack, { originId: 'StackOrigin029E19582' }); + + expect(originBindConfig.originProperty?.responseCompletionTimeout).toEqual(120); +}); + +test('configure both responseCompletionTimeout and readTimeout', () => { + const api = new apigateway.RestApi(stack, 'RestApi'); + api.root.addMethod('GET'); + + const origin = new RestApiOrigin(api, { + responseCompletionTimeout: Duration.seconds(60), + readTimeout: Duration.seconds(60), + }); + + const originBindConfig = origin.bind(stack, { originId: 'StackOrigin029E19582' }); + expect(originBindConfig.originProperty?.responseCompletionTimeout).toEqual(60); +}); + +test('throw error for configuring readTimeout less than responseCompletionTimeout value', () => { + const api = new apigateway.RestApi(stack, 'RestApi'); + api.root.addMethod('GET'); + + expect(() => { + new RestApiOrigin(api, { + responseCompletionTimeout: Duration.seconds(30), + readTimeout: Duration.seconds(60), + }); + }).toThrow('responseCompletionTimeout must be equal to or greater than readTimeout (60s), got: 30s.'); +}); diff --git a/packages/aws-cdk-lib/aws-cloudfront/lib/origin.ts b/packages/aws-cdk-lib/aws-cloudfront/lib/origin.ts index e5a35d37f5274..affb732abfff3 100644 --- a/packages/aws-cdk-lib/aws-cloudfront/lib/origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront/lib/origin.ts @@ -1,6 +1,6 @@ import { Construct } from 'constructs'; import { CfnDistribution } from './cloudfront.generated'; -import { Duration, Token, UnscopedValidationError, ValidationError } from '../../core'; +import { Duration, Token, UnscopedValidationError, ValidationError, withResolved } from '../../core'; /** * The selection criteria for the origin group. @@ -128,6 +128,18 @@ export interface OriginOptions { * @default - no origin access control */ readonly originAccessControlId?: string; + + /** + * The time that a request from CloudFront to the origin can stay open and wait for a response. + * + * If the complete response isn't received from the origin by this time, CloudFront ends the connection. + * + * Valid values are 1-3600 seconds, inclusive. + * + * @default undefined - AWS CloudFront default is not enforcing a maximum value + * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesOrigin.html#response-completion-timeout + */ + readonly responseCompletionTimeout?: Duration; } /** @@ -176,10 +188,12 @@ export abstract class OriginBase implements IOrigin { private readonly originShieldEnabled: boolean; private readonly originId?: string; private readonly originAccessControlId?: string; + private readonly responseCompletionTimeout?: Duration; protected constructor(domainName: string, props: OriginProps = {}) { validateIntInRangeOrUndefined('connectionTimeout', 1, 10, props.connectionTimeout?.toSeconds()); validateIntInRangeOrUndefined('connectionAttempts', 1, 3, props.connectionAttempts, false); + validateIntInRangeOrUndefined('responseCompletionTimeout', 1, 3600, props.responseCompletionTimeout?.toSeconds()); validateCustomHeaders(props.customHeaders); this.domainName = domainName; @@ -191,6 +205,29 @@ export abstract class OriginBase implements IOrigin { this.originId = props.originId; this.originShieldEnabled = props.originShieldEnabled ?? true; this.originAccessControlId = props.originAccessControlId; + this.responseCompletionTimeout = props.responseCompletionTimeout; + } + + /** + * Validates that responseCompletionTimeout is greater than or equal to readTimeout + * when both are specified. This method should be called by subclasses that support readTimeout. + */ + protected validateResponseCompletionTimeoutWithReadTimeout( + responseCompletionTimeout?: Duration, + readTimeout?: Duration, + ): void { + withResolved(responseCompletionTimeout, readTimeout, () => { + if (responseCompletionTimeout && readTimeout) { + const responseCompletionSec = responseCompletionTimeout.toSeconds(); + const readTimeoutSec = readTimeout.toSeconds(); + + if (responseCompletionSec < readTimeoutSec) { + throw new UnscopedValidationError( + `responseCompletionTimeout must be equal to or greater than readTimeout (${readTimeoutSec}s), got: ${responseCompletionSec}s.`, + ); + } + } + }); } /** @@ -218,6 +255,7 @@ export abstract class OriginBase implements IOrigin { vpcOriginConfig, originShield: this.renderOriginShield(this.originShieldEnabled, this.originShieldRegion), originAccessControlId: this.originAccessControlId, + responseCompletionTimeout: this.responseCompletionTimeout?.toSeconds(), }, }; } diff --git a/packages/aws-cdk-lib/aws-cloudfront/test/origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront/test/origin.test.ts index 9c607c6c2fadc..873b7e928362e 100644 --- a/packages/aws-cdk-lib/aws-cloudfront/test/origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront/test/origin.test.ts @@ -43,6 +43,26 @@ test.each([-0.5, 0.5, 1.5, 4]) }).toThrow(`connectionAttempts: Must be an int between 1 and 3 (inclusive); received ${connectionAttempts}.`); }); +test.each([ + Duration.seconds(0), + Duration.seconds(3601), +])('validates responseCompletionTimeout is an int between 1 and 3600 seconds - out of bounds', (responseCompletionTimeout) => { + expect(() => { + new TestOrigin('www.example.com', { + responseCompletionTimeout, + }); + }).toThrow(`responseCompletionTimeout: Must be an int between 1 and 3600 seconds (inclusive); received ${responseCompletionTimeout.toSeconds()}.`); +}); + +test('responseCompletionTimeout is correctly set in origin property', () => { + const origin = new TestOrigin('www.example.com', { + responseCompletionTimeout: Duration.seconds(120), + }); + + const originBindConfig = origin.bind(stack, { originId: 'OriginId' }); + expect(originBindConfig.originProperty?.responseCompletionTimeout).toEqual(120); +}); + test.each(['api', '/api', '/api/', 'api/']) ('enforces that originPath starts but does not end, with a /', (originPath) => { const origin = new TestOrigin('www.example.com', {