From d04bf57e86f24c1bb3035323650a6da402aab09b Mon Sep 17 00:00:00 2001 From: Jackie Wang Date: Thu, 5 Jan 2023 13:11:10 -0500 Subject: [PATCH] fix(servicecatalog): incorrect objectkey produced from asset relative path --- .../lib/private/product-stack-synthesizer.ts | 7 +- .../test/product-stack.test.ts | 64 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts b/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts index 55cb511b65424..d451f34fc51ad 100644 --- a/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts +++ b/packages/@aws-cdk/aws-servicecatalog/lib/private/product-stack-synthesizer.ts @@ -1,3 +1,4 @@ +import * as path from 'path'; import { CfnBucket, IBucket } from '@aws-cdk/aws-s3'; import { BucketDeployment, Source } from '@aws-cdk/aws-s3-deployment'; import * as cdk from '@aws-cdk/core'; @@ -42,7 +43,11 @@ export class ProductStackSynthesizer extends cdk.StackSynthesizer { const physicalName = this.physicalNameOfBucket(this.assetBucket); const bucketName = physicalName; - const s3Filename = asset.fileName?.split('.')[1] + '.zip'; + if (!asset.fileName) { + throw new Error('Asset file name is undefined'); + } + const assetFileBaseName = path.basename(asset.fileName); + const s3Filename = assetFileBaseName.split('.')[1] + '.zip'; const objectKey = `${s3Filename}`; const s3ObjectUrl = `s3://${bucketName}/${objectKey}`; const httpUrl = `https://s3.${bucketName}/${objectKey}`; diff --git a/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts b/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts index e9caacbce81ed..fd897111d1f5e 100644 --- a/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts +++ b/packages/@aws-cdk/aws-servicecatalog/test/product-stack.test.ts @@ -1,5 +1,7 @@ import * as fs from 'fs'; import * as path from 'path'; +import { Template } from '@aws-cdk/assertions'; +import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import * as s3_assets from '@aws-cdk/aws-s3-assets'; import * as sns from '@aws-cdk/aws-sns'; @@ -32,13 +34,69 @@ describe('ProductStack', () => { assetBucket: testAssetBucket, }); - // WHEN - new s3_assets.Asset(productStack, 'testAsset', { - path: path.join(__dirname, 'assets'), + new lambda.Function(productStack, 'HelloHandler', { + runtime: lambda.Runtime.PYTHON_3_9, + code: lambda.Code.fromAsset(path.join(__dirname, 'assets')), + handler: 'index.handler', }); + // WHEN + const assembly = app.synth(); + // THEN expect(productStack._getAssetBucket()).toBeDefined(); + const template = JSON.parse(fs.readFileSync(path.join(assembly.directory, productStack.templateFile), 'utf-8')); + Template.fromJSON(template).hasResourceProperties('AWS::Lambda::Function', { + Code: { + S3Bucket: 'test-asset-bucket', + S3Key: 'd3833f63e813b3a96ea04c8c50ca98209330867f5f6ac358efca11f85a3476c2.zip', + }, + }); + }); + + test('Used defined Asset bucket in product stack with nested assets', () => { + // GIVEN + const app = new cdk.App( + { outdir: 'cdk.out' }, + ); + const mainStack = new cdk.Stack(app, 'MyStack'); + let templateFileUrl = ''; + class PortfolioStage extends cdk.Stage { + constructor(scope: Construct, id: string) { + super(scope, id); + + const portfolioStack: cdk.Stack = new cdk.Stack(this, 'NestedStack'); + + const testAssetBucket = new s3.Bucket(portfolioStack, 'TestAssetBucket', { + bucketName: 'test-asset-bucket', + }); + const productStack = new servicecatalog.ProductStack(portfolioStack, 'MyProductStack', { + assetBucket: testAssetBucket, + }); + + new lambda.Function(productStack, 'HelloHandler', { + runtime: lambda.Runtime.PYTHON_3_9, + code: lambda.Code.fromAsset(path.join(__dirname, 'assets')), + handler: 'index.handler', + }); + + expect(productStack._getAssetBucket()).toBeDefined(); + templateFileUrl = productStack.templateFile; + } + } + const portfolioStage = new PortfolioStage(mainStack, 'PortfolioStage'); + + // WHEN + app.synth(); + + //THEN + const template = JSON.parse(fs.readFileSync(path.join(portfolioStage.outdir, templateFileUrl), 'utf-8')); + Template.fromJSON(template).hasResourceProperties('AWS::Lambda::Function', { + Code: { + S3Bucket: 'test-asset-bucket', + S3Key: 'd3833f63e813b3a96ea04c8c50ca98209330867f5f6ac358efca11f85a3476c2.zip', + }, + }); }); test('fails if bucketName is not specified in product stack with assets', () => {