UNPKG

@aws-solutions-constructs/core

Version:
916 lines 105 kB
"use strict"; /** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance * with the License. A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0 * * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions * and limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); const assertions_1 = require("aws-cdk-lib/assertions"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const cloudfront = require("aws-cdk-lib/aws-cloudfront"); const lambda = require("aws-cdk-lib/aws-lambda"); const cloudfront_distribution_helper_1 = require("../lib/cloudfront-distribution-helper"); const s3_bucket_helper_1 = require("../lib/s3-bucket-helper"); const aws_s3_1 = require("aws-cdk-lib/aws-s3"); const origins = require("aws-cdk-lib/aws-cloudfront-origins"); const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront"); const acm = require("aws-cdk-lib/aws-certificatemanager"); const defaults = require("../"); test('check bucket policy metadata', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket }); const template = assertions_1.Template.fromStack(stack); template.hasResource('AWS::S3::BucketPolicy', { Metadata: { cfn_nag: { rules_to_suppress: [ { id: "F16", reason: "Public website bucket policy requires a wildcard principal" } ] } } }); }); test('test cloudfront check bucket policy', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::S3::BucketPolicy", { PolicyDocument: { Statement: [ { Action: "s3:*", Condition: { Bool: { "aws:SecureTransport": "false" } }, Effect: "Deny", Principal: { AWS: "*" }, Resource: [ { "Fn::GetAtt": [ "S3Bucket07682993", "Arn" ] }, { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "S3Bucket07682993", "Arn" ] }, "/*" ] ] } ] } ], Version: "2012-10-17" } }); }); test('test cloudfront with no security headers ', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: {}, httpSecurityHeaders: false }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", Compress: true, TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } } } }); }); test('test cloudfront override cloudfront logging bucket ', () => { const stack = new aws_cdk_lib_1.Stack(); const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}, 'content-bucket'); const logBucket = new aws_s3_1.Bucket(stack, 'cloudfront-log-bucket'); const myprops = { enableLogging: true, logBucket }; (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: contentBucketResponse.bucket, cloudFrontDistributionProps: myprops }); const template = assertions_1.Template.fromStack(stack); // Should be content bucket and it's associated S3 logging bucket, plus simple CloudFront log bucket template.resourceCountIs("AWS::S3::Bucket", 3); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { Logging: { Bucket: { "Fn::GetAtt": [ "cloudfrontlogbucketDF7058FB", "RegionalDomainName" ] } } } }); }); test('test cloudfront with logging disabled', () => { const stack = new aws_cdk_lib_1.Stack(); const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const cfDistroProps = { enableLogging: false, }; (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: contentBucketResponse.bucket, cloudFrontDistributionProps: cfDistroProps }); const template = assertions_1.Template.fromStack(stack); // Should only be content bucket and it's associated S3 logging bucket template.resourceCountIs("AWS::S3::Bucket", 2); // There should be no logging of distribution template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { Logging: assertions_1.Match.anyValue() } } }, 0); }); test('test cloudfront override properties', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const props = { defaultBehavior: { origin: new origins.S3Origin(buildS3BucketResponse.bucket, { originPath: '/testPath' }), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS }, }; (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: props }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { AllowedMethods: [ "GET", "HEAD", "OPTIONS", "PUT", "PATCH", "POST", "DELETE" ], CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", CachedMethods: [ "GET", "HEAD", "OPTIONS" ], Compress: true, FunctionAssociations: [ { EventType: "viewer-response", FunctionARN: { "Fn::GetAtt": [ "SetHttpSecurityHeadersEE936115", "FunctionARN" ] } } ], TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } }, Origins: [ { DomainName: { "Fn::GetAtt": [ "S3Bucket07682993", "RegionalDomainName" ] }, Id: "CloudFrontDistributionOrigin176EC3A12", OriginPath: '/testPath', S3OriginConfig: { OriginAccessIdentity: { "Fn::Join": [ "", [ "origin-access-identity/cloudfront/", { Ref: "CloudFrontDistributionOrigin1S3Origin3D9CA0E9" } ] ] } } } ] } }); }); test('test override cloudfront with custom cloudfront function', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); // custom cloudfront function const cloudfrontFunction = new cloudfront.Function(stack, "MyFunction", { code: cloudfront.FunctionCode.fromInline("exports.handler = (event, context, callback) => {}") }); (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: { defaultBehavior: { functionAssociations: [ { eventType: cloudfront.FunctionEventType.VIEWER_RESPONSE, function: cloudfrontFunction } ], } } }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", Compress: true, FunctionAssociations: [ { EventType: "viewer-response", FunctionARN: { "Fn::GetAtt": [ "MyFunction3BAA72D1", "FunctionARN" ] } } ], TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } } } }); }); test('test override cloudfront replace custom lambda@edge', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); // custom lambda@edg function const handler = new lambda.Function(stack, 'SomeHandler', { functionName: 'SomeHandler', runtime: defaults.COMMERCIAL_REGION_LAMBDA_NODE_RUNTIME, handler: 'index.handler', code: lambda.Code.fromAsset(`${__dirname}/lambda`), }); const handlerVersion = new lambda.Version(stack, 'SomeHandlerVersion', { lambda: handler, }); (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: { defaultBehavior: { edgeLambdas: [ { eventType: aws_cloudfront_1.LambdaEdgeEventType.VIEWER_REQUEST, includeBody: false, functionVersion: handlerVersion, } ] } }, httpSecurityHeaders: false }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", Compress: true, LambdaFunctionAssociations: [ { EventType: "viewer-request", IncludeBody: false, LambdaFunctionARN: { Ref: "SomeHandlerVersionDA986E41" } } ], TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } } } }); }); test('test cloudfront override cloudfront custom domain names ', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012'); const myprops = { domainNames: ['mydomains'], certificate }; (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: myprops }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { Aliases: [ "mydomains" ], } }); }); test('Are cloudfront log bucket access log bucket properties used', () => { const stack = new aws_cdk_lib_1.Stack(); const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const testName = 'random-name-avcb'; const response = (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: contentBucketResponse.bucket, cloudFrontLoggingBucketS3AccessLogBucketProps: { bucketName: testName } }); expect(response.loggingBucket).toBeDefined(); expect(response.loggingBucketS3AccesssLogBucket).toBeDefined(); const template = assertions_1.Template.fromStack(stack); // Content Bucket, Content Bucket Access Log, CloudFront Log, CloudFront Log Access Log template.resourceCountIs("AWS::S3::Bucket", 4); template.hasResourceProperties("AWS::S3::Bucket", { BucketName: testName }); }); test('Is logCloudFrontAccessLog observed', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const response = (0, cloudfront_distribution_helper_1.createCloudFrontDistributionForS3)(stack, 'sample-cf-distro', { sourceBucket: buildS3BucketResponse.bucket, logCloudFrontAccessLog: false, cloudFrontDistributionProps: {}, }); expect(response.loggingBucket).toBeDefined(); expect(response.loggingBucketS3AccesssLogBucket).not.toBeDefined(); const template = assertions_1.Template.fromStack(stack); // Content Bucket, Content Bucket Access Log, CloudFront Log, NO CloudFront Log Access Log template.resourceCountIs("AWS::S3::Bucket", 3); }); // --------------------------- // Duplicate tests for createCloudFrontOaiDistributinForS3 // --------------------------- test('check bucket policy metadata - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket }); const template = assertions_1.Template.fromStack(stack); template.hasResource('AWS::S3::BucketPolicy', { Metadata: { cfn_nag: { rules_to_suppress: [ { id: "F16", reason: "Public website bucket policy requires a wildcard principal" } ] } } }); }); test('check createCloudFrontOaiDistributionForS3 response', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const response = (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket }); expect(response.originAccessIdentity).toBeDefined(); expect(response.distribution).toBeDefined(); expect(response.loggingBucket).toBeDefined(); expect(response.cloudfrontFunction).toBeDefined(); expect(response.loggingBucketS3AccesssLogBucket).toBeDefined(); }); test('test cloudfront check bucket policy - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::S3::BucketPolicy", { PolicyDocument: { Statement: [ { Action: "s3:*", Condition: { Bool: { "aws:SecureTransport": "false" } }, Effect: "Deny", Principal: { AWS: "*" }, Resource: [ { "Fn::GetAtt": [ "S3Bucket07682993", "Arn" ] }, { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "S3Bucket07682993", "Arn" ] }, "/*" ] ] } ] }, { Action: "s3:GetObject", Effect: "Allow", Principal: { CanonicalUser: { "Fn::GetAtt": [ "constructsGeneratedOai6A430BBF", "S3CanonicalUserId" ] } }, Resource: { "Fn::Join": [ "", [ { "Fn::GetAtt": [ "S3Bucket07682993", "Arn" ] }, "/*" ] ] } } ], Version: "2012-10-17" } }); }); test('test cloudfront with no security headers - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: {}, httpSecurityHeaders: false }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", Compress: true, TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } } } }); }); test('test cloudfront override cloudfront logging bucket - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}, 'content-bucket'); const logBucket = new aws_s3_1.Bucket(stack, 'cloudfront-log-bucket'); const myprops = { enableLogging: true, logBucket }; (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: contentBucketResponse.bucket, cloudFrontDistributionProps: myprops }); const template = assertions_1.Template.fromStack(stack); // Should be content bucket and it's associated S3 logging bucket, plus simple CloudFront log bucket template.resourceCountIs("AWS::S3::Bucket", 3); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { Logging: { Bucket: { "Fn::GetAtt": [ "cloudfrontlogbucketDF7058FB", "RegionalDomainName" ] } } } }); }); test('test cloudfront with logging disabled - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const cfDistroProps = { enableLogging: false, }; (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: contentBucketResponse.bucket, cloudFrontDistributionProps: cfDistroProps }); const template = assertions_1.Template.fromStack(stack); // Should only be content bucket and it's associated S3 logging bucket template.resourceCountIs("AWS::S3::Bucket", 2); // There should be no logging of distribution template.resourcePropertiesCountIs("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { Logging: assertions_1.Match.anyValue() } } }, 0); }); test('test cloudfront override properties - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const props = { defaultBehavior: { origin: new origins.S3Origin(buildS3BucketResponse.bucket, { originPath: '/testPath' }), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS }, }; (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: props }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { AllowedMethods: [ "GET", "HEAD", "OPTIONS", "PUT", "PATCH", "POST", "DELETE" ], CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", CachedMethods: [ "GET", "HEAD", "OPTIONS" ], Compress: true, FunctionAssociations: [ { EventType: "viewer-response", FunctionARN: { "Fn::GetAtt": [ "SetHttpSecurityHeadersEE936115", "FunctionARN" ] } } ], TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } }, Origins: [ { DomainName: { "Fn::GetAtt": [ "S3Bucket07682993", "RegionalDomainName" ] }, Id: "CloudFrontDistributionOrigin176EC3A12", OriginPath: '/testPath', S3OriginConfig: { OriginAccessIdentity: { "Fn::Join": [ "", [ "origin-access-identity/cloudfront/", { Ref: "CloudFrontDistributionOrigin1S3Origin3D9CA0E9" } ] ] } } } ] } }); }); test('test override cloudfront with custom cloudfront function - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); // custom cloudfront function const cloudfrontFunction = new cloudfront.Function(stack, "MyFunction", { code: cloudfront.FunctionCode.fromInline("exports.handler = (event, context, callback) => {}") }); (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: { defaultBehavior: { functionAssociations: [ { eventType: cloudfront.FunctionEventType.VIEWER_RESPONSE, function: cloudfrontFunction } ], } } }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", Compress: true, FunctionAssociations: [ { EventType: "viewer-response", FunctionARN: { "Fn::GetAtt": [ "MyFunction3BAA72D1", "FunctionARN" ] } } ], TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } } } }); }); test('test override cloudfront replace custom lambda@edge - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); // custom lambda@edg function const handler = new lambda.Function(stack, 'SomeHandler', { functionName: 'SomeHandler', runtime: defaults.COMMERCIAL_REGION_LAMBDA_NODE_RUNTIME, handler: 'index.handler', code: lambda.Code.fromAsset(`${__dirname}/lambda`), }); const handlerVersion = new lambda.Version(stack, 'SomeHandlerVersion', { lambda: handler, }); (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: { defaultBehavior: { edgeLambdas: [ { eventType: aws_cloudfront_1.LambdaEdgeEventType.VIEWER_REQUEST, includeBody: false, functionVersion: handlerVersion, } ] } }, httpSecurityHeaders: false }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { DefaultCacheBehavior: { CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6", Compress: true, LambdaFunctionAssociations: [ { EventType: "viewer-request", IncludeBody: false, LambdaFunctionARN: { Ref: "SomeHandlerVersionDA986E41" } } ], TargetOriginId: "CloudFrontDistributionOrigin176EC3A12", ViewerProtocolPolicy: "redirect-to-https" }, DefaultRootObject: "index.html", Enabled: true, HttpVersion: "http2", IPV6Enabled: true, Logging: { Bucket: { "Fn::GetAtt": [ "CloudfrontLoggingBucket3C3EFAA7", "RegionalDomainName" ] } } } }); }); test('test cloudfront override cloudfront custom domain names - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const certificate = acm.Certificate.fromCertificateArn(stack, 'Cert', 'arn:aws:acm:us-east-1:123456789012:certificate/11112222-3333-1234-1234-123456789012'); const myprops = { domainNames: ['mydomains'], certificate }; (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, cloudFrontDistributionProps: myprops }); const template = assertions_1.Template.fromStack(stack); template.hasResourceProperties("AWS::CloudFront::Distribution", { DistributionConfig: { Aliases: [ "mydomains" ], } }); }); test('Are cloudfront log bucket access log bucket properties used - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const contentBucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const testName = 'random-name-avcb'; const response = (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: contentBucketResponse.bucket, cloudFrontLoggingBucketS3AccessLogBucketProps: { bucketName: testName } }); expect(response.loggingBucket).toBeDefined(); expect(response.loggingBucketS3AccesssLogBucket).toBeDefined(); const template = assertions_1.Template.fromStack(stack); // Content Bucket, Content Bucket Access Log, CloudFront Log, CloudFront Log Access Log template.resourceCountIs("AWS::S3::Bucket", 4); template.hasResourceProperties("AWS::S3::Bucket", { BucketName: testName }); }); test('Is logCloudFrontAccessLog observed - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, {}); const response = (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, logCloudFrontAccessLog: false, cloudFrontDistributionProps: {}, }); expect(response.loggingBucket).toBeDefined(); expect(response.loggingBucketS3AccesssLogBucket).not.toBeDefined(); const template = assertions_1.Template.fromStack(stack); // Content Bucket, Content Bucket Access Log, CloudFront Log, NO CloudFront Log Access Log template.resourceCountIs("AWS::S3::Bucket", 3); }); test('Test that web site enabled buckets throw an error - oai', () => { const stack = new aws_cdk_lib_1.Stack(); const buildS3BucketResponse = (0, s3_bucket_helper_1.buildS3Bucket)(stack, { bucketProps: { websiteIndexDocument: "index.html" } }); const app = () => { (0, cloudfront_distribution_helper_1.createCloudFrontOaiDistributionForS3)(stack, { sourceBucket: buildS3BucketResponse.bucket, logCloudFrontAccessLog: false, cloudFrontDistributionProps: {}, }); }; // Assertion expect(app).toThrowError(); }); // --------------------------- // Prop Tests // --------------------------- test('Test CloudFront insertHttpHeaders bad props', () => { const props = { insertHttpSecurityHeaders: true, responseHeadersPolicyProps: { securityHeadersBehavior: {} } }; const app = () => { defaults.CheckCloudFrontProps(props); }; // Assertion expect(app).toThrowError('responseHeadersPolicyProps.securityHeadersBehavior can only be passed if httpSecurityHeaders is set to `false`.'); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWRmcm9udC1kaXN0cmlidXRpb24tczMtaGVscGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbG91ZGZyb250LWRpc3RyaWJ1dGlvbi1zMy1oZWxwZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7O0dBV0c7O0FBRUgsdURBQXlEO0FBQ3pELDZDQUFvQztBQUNwQyx5REFBeUQ7QUFDekQsaURBQWlEO0FBQ2pELDBGQUFnSTtBQUNoSSw4REFBd0Q7QUFDeEQsK0NBQTRDO0FBQzVDLDhEQUE4RDtBQUM5RCwrREFBaUU7QUFDakUsMERBQTBEO0FBQzFELGdDQUFnQztBQUVoQyxJQUFJLENBQUMsOEJBQThCLEVBQUUsR0FBRyxFQUFFO0lBQ3hDLE1BQU0sS0FBSyxHQUFHLElBQUksbUJBQUssRUFBRSxDQUFDO0lBQzFCLE1BQU0scUJBQXFCLEdBQUcsSUFBQSxnQ0FBYSxFQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN2RCxJQUFBLGtFQUFpQyxFQUFDLEtBQUssRUFBRSxrQkFBa0IsRUFBRTtRQUMzRCxZQUFZLEVBQUUscUJBQXFCLENBQUMsTUFBTTtLQUMzQyxDQUFDLENBQUM7SUFDSCxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzQyxRQUFRLENBQUMsV0FBVyxDQUFDLHVCQUF1QixFQUFFO1FBQzVDLFFBQVEsRUFBRTtZQUNSLE9BQU8sRUFBRTtnQkFDUCxpQkFBaUIsRUFBRTtvQkFDakI7d0JBQ0UsRUFBRSxFQUFFLEtBQUs7d0JBQ1QsTUFBTSxFQUFFLDREQUE0RDtxQkFDckU7aUJBQ0Y7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMscUNBQXFDLEVBQUUsR0FBRyxFQUFFO0lBQy9DLE1BQU0sS0FBSyxHQUFHLElBQUksbUJBQUssRUFBRSxDQUFDO0lBQzFCLE1B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