Skip to content

Commit f990e34

Browse files
authored
chore: forward merge 'master' into 'v2-main' (#19189)
Automated action from aws/cdk-ops
2 parents d831d01 + fecbdf9 commit f990e34

File tree

261 files changed

+4512
-592
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

261 files changed

+4512
-592
lines changed

.github/workflows/yarn-upgrade.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
uses: actions/checkout@v2
1919

2020
- name: Set up Node
21-
uses: actions/setup-node@v2.5.1
21+
uses: actions/setup-node@v3
2222
with:
2323
node-version: 12
2424

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22

33
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
44

5+
## [1.146.0](https://github.com/aws/aws-cdk/compare/v1.145.0...v1.146.0) (2022-02-24)
6+
7+
8+
### Features
9+
10+
* **apigatewayv2:** Import existing WebSocketApi from attributes ([#18958](https://github.com/aws/aws-cdk/issues/18958)) ([f203845](https://github.com/aws/aws-cdk/commit/f203845d26ae8333f467f1cb91ad965697087d85))
11+
* **cli:** bundle dependencies ([#18667](https://github.com/aws/aws-cdk/issues/18667)) ([31d135f](https://github.com/aws/aws-cdk/commit/31d135fb51d3cd4e26fbdc132e03815a1416da75))
12+
* **cli:** support for matching notices with arbitrary module names ([#19088](https://github.com/aws/aws-cdk/issues/19088)) ([a87dee7](https://github.com/aws/aws-cdk/commit/a87dee756057e554909207237b70f80af185b110))
13+
* **cli:** support for notices ([#18936](https://github.com/aws/aws-cdk/issues/18936)) ([d37fbbb](https://github.com/aws/aws-cdk/commit/d37fbbbb31003d69da88b9340a6a9c9e1e927ac5))
14+
* **cloudfront-origins:** extend max keepaliveTimeout of HttpOrigin to 180 ([#18837](https://github.com/aws/aws-cdk/issues/18837)) ([171fdcd](https://github.com/aws/aws-cdk/commit/171fdcdf595fcff5b2567b17e6fa73bf0d42e1bc)), closes [#18697](https://github.com/aws/aws-cdk/issues/18697)
15+
* **eks:** Allow helm pull from OCI repositories ([#18547](https://github.com/aws/aws-cdk/issues/18547)) ([7e624d9](https://github.com/aws/aws-cdk/commit/7e624d994c94dbd584643c4cb6e9f8df53dabc18))
16+
* **lambda:** add a fromFunctionName() method ([#19076](https://github.com/aws/aws-cdk/issues/19076)) ([5b92cc3](https://github.com/aws/aws-cdk/commit/5b92cc3a31eea29b40814498fca614eb1c7c8724)), closes [#18255](https://github.com/aws/aws-cdk/issues/18255) [#19031](https://github.com/aws/aws-cdk/issues/19031)
17+
* **pipelines:** ECR source action ([#16385](https://github.com/aws/aws-cdk/issues/16385)) ([fc11ae2](https://github.com/aws/aws-cdk/commit/fc11ae2c4ec3bd9dfe3ff813aa831c744d8ac444)), closes [#16378](https://github.com/aws/aws-cdk/issues/16378)
18+
* **pipelines:** step outputs ([#19024](https://github.com/aws/aws-cdk/issues/19024)) ([0dec2ee](https://github.com/aws/aws-cdk/commit/0dec2ee78a70832c3a697be26c67498460a587dd)), closes [#17189](https://github.com/aws/aws-cdk/issues/17189) [#18893](https://github.com/aws/aws-cdk/issues/18893) [#15943](https://github.com/aws/aws-cdk/issues/15943) [#16407](https://github.com/aws/aws-cdk/issues/16407)
19+
* **rds:** make VPC optional for serverless Clusters ([#17413](https://github.com/aws/aws-cdk/issues/17413)) ([4f7818d](https://github.com/aws/aws-cdk/commit/4f7818dd76bd48ed652407f4852cc97ba57d7395)), closes [#17401](https://github.com/aws/aws-cdk/issues/17401)
20+
* triggers ([#19011](https://github.com/aws/aws-cdk/issues/19011)) ([11d6c69](https://github.com/aws/aws-cdk/commit/11d6c69a8b1ee70cbea025d134be7702dd804444))
21+
22+
23+
### Bug Fixes
24+
25+
* **cli:** hotswapping is slow for many resources deployed at once ([#19081](https://github.com/aws/aws-cdk/issues/19081)) ([040238e](https://github.com/aws/aws-cdk/commit/040238e9285945d1c48ef79474e527b871e7824c)), closes [#19021](https://github.com/aws/aws-cdk/issues/19021)
26+
* **s3-notifications:** notifications allowed with imported kms keys ([#18989](https://github.com/aws/aws-cdk/issues/18989)) ([7441418](https://github.com/aws/aws-cdk/commit/7441418fbf9ffdf8d85a573e3c81c45c5648fe8a))
27+
* API compatibility check fails in CI pipeline ([#19069](https://github.com/aws/aws-cdk/issues/19069)) ([6ec1005](https://github.com/aws/aws-cdk/commit/6ec1005c9cfa9723520885748d759b00be5cd2fa)), closes [#19070](https://github.com/aws/aws-cdk/issues/19070)
28+
* **cloudfront:** trim autogenerated cache policy name ([#18953](https://github.com/aws/aws-cdk/issues/18953)) ([c7394c9](https://github.com/aws/aws-cdk/commit/c7394c96c42cb6a5af1e309bee2a5f11eb3ad35c)), closes [#18918](https://github.com/aws/aws-cdk/issues/18918)
29+
* **elasticloadbalancingv2:** validate port/protocol are not provided for lambda targets ([#19043](https://github.com/aws/aws-cdk/issues/19043)) ([64d26cc](https://github.com/aws/aws-cdk/commit/64d26cc22b1fe456777c3367769ddbe860f26cf3)), closes [#12514](https://github.com/aws/aws-cdk/issues/12514)
30+
* **route53:** fix cross account delegation deployment dependency ([#19047](https://github.com/aws/aws-cdk/issues/19047)) ([692a0d0](https://github.com/aws/aws-cdk/commit/692a0d06f2865503d1d88b0ba8af38ecceaec871)), closes [#19041](https://github.com/aws/aws-cdk/issues/19041)
31+
532
## [1.145.0](https://github.com/aws/aws-cdk/compare/v1.144.0...v1.145.0) (2022-02-18)
633

734

packages/@aws-cdk-containers/ecs-service-extensions/test/integ.assign-public-ip.expected.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,8 @@
766766
"dynamodb:BatchWriteItem",
767767
"dynamodb:PutItem",
768768
"dynamodb:UpdateItem",
769-
"dynamodb:DeleteItem"
769+
"dynamodb:DeleteItem",
770+
"dynamodb:DescribeTable"
770771
],
771772
"Effect": "Allow",
772773
"Resource": [

packages/@aws-cdk/aws-apigateway/lib/resource.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,8 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc
311311

312312
const template = new Array<string>();
313313

314-
template.push('#set($origin = $input.params("Origin"))');
315-
template.push('#if($origin == "") #set($origin = $input.params("origin")) #end');
314+
template.push('#set($origin = $input.params().header.get("Origin"))');
315+
template.push('#if($origin == "") #set($origin = $input.params().header.get("origin")) #end');
316316

317317
const condition = origins.map(o => `$origin.matches("${o}")`).join(' || ');
318318

packages/@aws-cdk/aws-apigateway/lib/usage-plan.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { CfnUsagePlan, CfnUsagePlanKey } from './apigateway.generated';
66
import { Method } from './method';
77
import { IRestApi } from './restapi';
88
import { Stage } from './stage';
9-
import { validateInteger } from './util';
9+
import { validateDouble, validateInteger } from './util';
1010

1111
/**
1212
* Container for defining throttling parameters to API stages or methods.
@@ -316,7 +316,7 @@ export class UsagePlan extends UsagePlanBase {
316316
const burstLimit = props.burstLimit;
317317
validateInteger(burstLimit, 'Throttle burst limit');
318318
const rateLimit = props.rateLimit;
319-
validateInteger(rateLimit, 'Throttle rate limit');
319+
validateDouble(rateLimit, 'Throttle rate limit');
320320

321321
ret = {
322322
burstLimit: burstLimit,

packages/@aws-cdk/aws-apigateway/lib/util.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ export function validateInteger(property: number | undefined, messagePrefix: str
7878
}
7979
}
8080

81+
export function validateDouble(property: number | undefined, messagePrefix: string) {
82+
if (property && isNaN(property) && isNaN(parseFloat(property.toString()))) {
83+
throw new Error(`${messagePrefix} should be an double`);
84+
}
85+
}
86+
8187
export class JsonSchemaMapper {
8288
/**
8389
* Transforms naming of some properties to prefix with a $, where needed

packages/@aws-cdk/aws-apigateway/test/cors.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ describe('cors', () => {
290290
'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'",
291291
},
292292
ResponseTemplates: {
293-
'application/json': '#set($origin = $input.params("Origin"))\n#if($origin == "") #set($origin = $input.params("origin")) #end\n#if($origin.matches("https://amazon.com") || $origin.matches("https://aws.amazon.com"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end',
293+
'application/json': '#set($origin = $input.params().header.get("Origin"))\n#if($origin == "") #set($origin = $input.params().header.get("origin")) #end\n#if($origin.matches("https://amazon.com") || $origin.matches("https://aws.amazon.com"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end',
294294
},
295295
StatusCode: '204',
296296
},

packages/@aws-cdk/aws-apigateway/test/integ.cors.expected.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"corsapitest8682546E"
5252
]
5353
},
54-
"corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d": {
54+
"corsapitestDeployment2BF1633A51392cbce1ac2785bd0e53063423e203": {
5555
"Type": "AWS::ApiGateway::Deployment",
5656
"Properties": {
5757
"RestApiId": {
@@ -74,7 +74,7 @@
7474
"Ref": "corsapitest8682546E"
7575
},
7676
"DeploymentId": {
77-
"Ref": "corsapitestDeployment2BF1633A228079ea05e5799220dd4ca13512b92d"
77+
"Ref": "corsapitestDeployment2BF1633A51392cbce1ac2785bd0e53063423e203"
7878
},
7979
"StageName": "prod"
8080
},
@@ -472,7 +472,7 @@
472472
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
473473
},
474474
"ResponseTemplates": {
475-
"application/json": "#set($origin = $input.params(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params(\"origin\")) #end\n#if($origin.matches(\"https://www.test-cors.org\"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
475+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin.matches(\"https://www.test-cors.org\"))\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
476476
},
477477
"StatusCode": "204"
478478
}

packages/@aws-cdk/aws-apigateway/test/usage-plan.test.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ describe('usage plan', () => {
2727
});
2828
});
2929

30-
test('usage plan with throttling limits', () => {
30+
test('usage plan with integer throttling limits', () => {
3131
// GIVEN
3232
const stack = new cdk.Stack();
3333
const api = new apigateway.RestApi(stack, 'my-api', { cloudWatchRole: false, deploy: true, deployOptions: { stageName: 'test' } });
3434
const method: apigateway.Method = api.root.addMethod('GET'); // Need at least one method on the api
3535
const usagePlanName = 'Basic';
36-
const usagePlanDescription = 'Basic Usage Plan with throttling limits';
36+
const usagePlanDescription = 'Basic Usage Plan with integer throttling limits';
3737

3838
// WHEN
3939
new apigateway.UsagePlan(stack, 'my-usage-plan', {
@@ -78,6 +78,57 @@ describe('usage plan', () => {
7878
});
7979
});
8080

81+
test('usage plan with integer and float throttling limits', () => {
82+
// GIVEN
83+
const stack = new cdk.Stack();
84+
const api = new apigateway.RestApi(stack, 'my-api', { cloudWatchRole: false, deploy: true, deployOptions: { stageName: 'test' } });
85+
const method: apigateway.Method = api.root.addMethod('GET'); // Need at least one method on the api
86+
const usagePlanName = 'Basic';
87+
const usagePlanDescription = 'Basic Usage Plan with integer and float throttling limits';
88+
89+
// WHEN
90+
new apigateway.UsagePlan(stack, 'my-usage-plan', {
91+
name: usagePlanName,
92+
description: usagePlanDescription,
93+
apiStages: [
94+
{
95+
stage: api.deploymentStage,
96+
throttle: [
97+
{
98+
method,
99+
throttle: {
100+
burstLimit: 20,
101+
rateLimit: 10.5,
102+
},
103+
},
104+
],
105+
},
106+
],
107+
});
108+
109+
// THEN
110+
Template.fromStack(stack).hasResourceProperties(RESOURCE_TYPE, {
111+
UsagePlanName: usagePlanName,
112+
Description: usagePlanDescription,
113+
ApiStages: [
114+
{
115+
ApiId: {
116+
Ref: 'myapi4C7BF186',
117+
},
118+
Stage: {
119+
Ref: 'myapiDeploymentStagetest4A4AB65E',
120+
},
121+
Throttle: {
122+
'//GET': {
123+
BurstLimit: 20,
124+
RateLimit: 10.5,
125+
},
126+
},
127+
},
128+
],
129+
});
130+
});
131+
81132
test('usage plan with blocked methods', () => {
82133
// GIVEN
83134
const stack = new cdk.Stack();

packages/@aws-cdk/aws-appsync/test/integ.api-import.expected.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@
8585
"dynamodb:BatchWriteItem",
8686
"dynamodb:PutItem",
8787
"dynamodb:UpdateItem",
88-
"dynamodb:DeleteItem"
88+
"dynamodb:DeleteItem",
89+
"dynamodb:DescribeTable"
8990
],
9091
"Effect": "Allow",
9192
"Resource": [

packages/@aws-cdk/aws-appsync/test/integ.auth-apikey.expected.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@
6868
"dynamodb:BatchWriteItem",
6969
"dynamodb:PutItem",
7070
"dynamodb:UpdateItem",
71-
"dynamodb:DeleteItem"
71+
"dynamodb:DeleteItem",
72+
"dynamodb:DescribeTable"
7273
],
7374
"Effect": "Allow",
7475
"Resource": [

packages/@aws-cdk/aws-appsync/test/integ.graphql-iam.expected.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@
9999
"dynamodb:BatchWriteItem",
100100
"dynamodb:PutItem",
101101
"dynamodb:UpdateItem",
102-
"dynamodb:DeleteItem"
102+
"dynamodb:DeleteItem",
103+
"dynamodb:DescribeTable"
103104
],
104105
"Effect": "Allow",
105106
"Resource": [

packages/@aws-cdk/aws-appsync/test/integ.graphql-schema.expected.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
"dynamodb:BatchWriteItem",
6868
"dynamodb:PutItem",
6969
"dynamodb:UpdateItem",
70-
"dynamodb:DeleteItem"
70+
"dynamodb:DeleteItem",
71+
"dynamodb:DescribeTable"
7172
],
7273
"Effect": "Allow",
7374
"Resource": [

packages/@aws-cdk/aws-appsync/test/integ.graphql.expected.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@
147147
"dynamodb:BatchWriteItem",
148148
"dynamodb:PutItem",
149149
"dynamodb:UpdateItem",
150-
"dynamodb:DeleteItem"
150+
"dynamodb:DeleteItem",
151+
"dynamodb:DescribeTable"
151152
],
152153
"Effect": "Allow",
153154
"Resource": [
@@ -360,7 +361,8 @@
360361
"dynamodb:BatchWriteItem",
361362
"dynamodb:PutItem",
362363
"dynamodb:UpdateItem",
363-
"dynamodb:DeleteItem"
364+
"dynamodb:DeleteItem",
365+
"dynamodb:DescribeTable"
364366
],
365367
"Effect": "Allow",
366368
"Resource": [
@@ -752,7 +754,8 @@
752754
"dynamodb:BatchWriteItem",
753755
"dynamodb:PutItem",
754756
"dynamodb:UpdateItem",
755-
"dynamodb:DeleteItem"
757+
"dynamodb:DeleteItem",
758+
"dynamodb:DescribeTable"
756759
],
757760
"Effect": "Allow",
758761
"Resource": [

packages/@aws-cdk/aws-dynamodb/lib/perms.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,5 @@ export const READ_STREAM_DATA_ACTIONS = [
2929
'dynamodb:GetRecords',
3030
'dynamodb:GetShardIterator',
3131
];
32+
33+
export const DESCRIBE_TABLE = 'dynamodb:DescribeTable';

packages/@aws-cdk/aws-dynamodb/lib/table.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -675,15 +675,16 @@ abstract class TableBase extends Resource implements ITable {
675675

676676
/**
677677
* Permits an IAM principal all data read operations from this table:
678-
* BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan.
678+
* BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan, DescribeTable.
679679
*
680680
* Appropriate grants will also be added to the customer-managed KMS key
681681
* if one was configured.
682682
*
683683
* @param grantee The principal to grant access to
684684
*/
685685
public grantReadData(grantee: iam.IGrantable): iam.Grant {
686-
return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, tableActions: perms.READ_DATA_ACTIONS });
686+
const tableActions = perms.READ_DATA_ACTIONS.concat(perms.DESCRIBE_TABLE);
687+
return this.combinedGrant(grantee, { keyActions: perms.KEY_READ_ACTIONS, tableActions });
687688
}
688689

689690
/**
@@ -720,29 +721,31 @@ abstract class TableBase extends Resource implements ITable {
720721

721722
/**
722723
* Permits an IAM principal all data write operations to this table:
723-
* BatchWriteItem, PutItem, UpdateItem, DeleteItem.
724+
* BatchWriteItem, PutItem, UpdateItem, DeleteItem, DescribeTable.
724725
*
725726
* Appropriate grants will also be added to the customer-managed KMS key
726727
* if one was configured.
727728
*
728729
* @param grantee The principal to grant access to
729730
*/
730731
public grantWriteData(grantee: iam.IGrantable): iam.Grant {
731-
return this.combinedGrant(grantee, { keyActions: perms.KEY_WRITE_ACTIONS, tableActions: perms.WRITE_DATA_ACTIONS });
732+
const tableActions = perms.WRITE_DATA_ACTIONS.concat(perms.DESCRIBE_TABLE);
733+
const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS);
734+
return this.combinedGrant(grantee, { keyActions, tableActions });
732735
}
733736

734737
/**
735738
* Permits an IAM principal to all data read/write operations to this table.
736739
* BatchGetItem, GetRecords, GetShardIterator, Query, GetItem, Scan,
737-
* BatchWriteItem, PutItem, UpdateItem, DeleteItem
740+
* BatchWriteItem, PutItem, UpdateItem, DeleteItem, DescribeTable
738741
*
739742
* Appropriate grants will also be added to the customer-managed KMS key
740743
* if one was configured.
741744
*
742745
* @param grantee The principal to grant access to
743746
*/
744747
public grantReadWriteData(grantee: iam.IGrantable): iam.Grant {
745-
const tableActions = perms.READ_DATA_ACTIONS.concat(perms.WRITE_DATA_ACTIONS);
748+
const tableActions = perms.READ_DATA_ACTIONS.concat(perms.WRITE_DATA_ACTIONS).concat(perms.DESCRIBE_TABLE);
746749
const keyActions = perms.KEY_READ_ACTIONS.concat(perms.KEY_WRITE_ACTIONS);
747750
return this.combinedGrant(grantee, { keyActions, tableActions });
748751
}

0 commit comments

Comments
 (0)