Skip to content

Commit b0bbd5e

Browse files
authored
fix(integ-tests): use transformToString on API call response body (#27122)
This PR fixes an issue where our assertions handler will fail when logging the response of an API call if the response body is a Blob. Specifically, the following error is thrown: ``` Converting circular structure to JSON --> starting at object with constructor 'TLSSocket' | property 'parser' -> object with constructor 'HTTPParser' --- property 'socket' closes the circle (RequestId: 50c1b6cd-47d2-494f-baf1-d22646cd4e5f) ``` The fix for this issue was to call the `transformToString` method on the response body. This is mentioned in aws-sdk-js-v3 [`UPGRADE.md`](https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md?plain=1#L573-L576) as the solution for `Lambda::Invoke`. Its unclear why `S3::GetObject` isn't mentioned as well, but it works for that too. However, instead of explicitly extracting the `Body` property from a response, we now recursively traverse the response and detect any such blob types that should be converted to strings - this should protect us against any other APIs that may exhibit this behavior. > `transformToString` is implemented as part of the [`SdkStreamMixin` interface](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-smithy-types/Interface/SdkStreamMixin/). Included in this PR is a fix for `aws-s3-deployment/test/integ.bucket-deployment-substitution.ts` which was previously failing with the error shown above. Co-authored by: @iliapolo Co-authored by: @vinayak-kukreja Co-authored by: @scanlonp Closes #27114 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 864e76a commit b0bbd5e

File tree

11 files changed

+141
-998
lines changed

11 files changed

+141
-998
lines changed
Original file line numberDiff line numberDiff line change
@@ -32605,12 +32605,32 @@ var HttpHandler = class extends CustomResourceHandler {
3260532605
var import_sdk_v2_to_v3_adapter = __toESM(require_lib5());
3260632606

3260732607
// lib/assertions/providers/lambda-handler/utils.ts
32608-
function parseJsonPayload(payload) {
32608+
async function coerceValue(v) {
32609+
if (v && typeof v === "object" && typeof v.transformToString === "function") {
32610+
const text = await v.transformToString();
32611+
return tryJsonParse(text);
32612+
}
32613+
return tryJsonParse(v);
32614+
}
32615+
function tryJsonParse(v) {
32616+
if (typeof v !== "string") {
32617+
return v;
32618+
}
3260932619
try {
32610-
const buffer = Buffer.from(payload);
32611-
return JSON.parse(new TextDecoder().decode(buffer));
32620+
return JSON.parse(v);
3261232621
} catch {
32613-
return payload;
32622+
return v;
32623+
}
32624+
}
32625+
async function coerceResponse(response) {
32626+
if (response == null) {
32627+
return;
32628+
}
32629+
for (const key of Object.keys(response)) {
32630+
response[key] = await coerceValue(response[key]);
32631+
if (typeof response[key] === "object") {
32632+
await coerceResponse(response[key]);
32633+
}
3261432634
}
3261532635
}
3261632636
function decodeParameters(obj) {
@@ -32687,9 +32707,7 @@ var AwsApiCallHandler = class extends CustomResourceHandler {
3268732707
const commandInput = (0, import_sdk_v2_to_v3_adapter.coerceApiParametersToUint8Array)(request2.service, request2.api, parameters);
3268832708
console.log(`SDK request to ${sdkPkg.service}.${request2.api} with parameters ${JSON.stringify(commandInput)}`);
3268932709
const response = await client.send(new Command(commandInput));
32690-
if (response.Payload) {
32691-
response.Payload = parseJsonPayload(response.Payload);
32692-
}
32710+
await coerceResponse(response);
3269332711
console.log(`SDK response received ${JSON.stringify(response)}`);
3269432712
delete response.$metadata;
3269532713
const respond = {

Diff for: packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment-substitution.js.snapshot/deploytimesubstitutionintegtestDefaultTestDeployAssertCBBB427B.assets.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
{
22
"version": "34.0.0",
33
"files": {
4-
"77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754": {
4+
"d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9": {
55
"source": {
6-
"path": "asset.77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754.bundle",
6+
"path": "asset.d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9.bundle",
77
"packaging": "zip"
88
},
99
"destinations": {
1010
"current_account-current_region": {
1111
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
12-
"objectKey": "77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754.zip",
12+
"objectKey": "d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9.zip",
1313
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
1414
}
1515
}
1616
},
17-
"e70bd778aadedf7f4065f219cf272b5b8a2bf42a03c1a0ccb4e7ec4859df0790": {
17+
"b8505aa6cd55c4ab32c8432e6caf98f78af39a3bfa813375fda36f3aa3f3d5b0": {
1818
"source": {
1919
"path": "deploytimesubstitutionintegtestDefaultTestDeployAssertCBBB427B.template.json",
2020
"packaging": "file"
2121
},
2222
"destinations": {
2323
"current_account-current_region": {
2424
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
25-
"objectKey": "e70bd778aadedf7f4065f219cf272b5b8a2bf42a03c1a0ccb4e7ec4859df0790.json",
25+
"objectKey": "b8505aa6cd55c4ab32c8432e6caf98f78af39a3bfa813375fda36f3aa3f3d5b0.json",
2626
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
2727
}
2828
}

Diff for: packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment-substitution.js.snapshot/deploytimesubstitutionintegtestDefaultTestDeployAssertCBBB427B.template.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"outputPaths": [
4444
"Body"
4545
],
46-
"salt": "1694452807292"
46+
"salt": "1694616200437"
4747
},
4848
"UpdateReplacePolicy": "Delete",
4949
"DeletionPolicy": "Delete"
@@ -107,7 +107,7 @@
107107
"S3Bucket": {
108108
"Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"
109109
},
110-
"S3Key": "77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754.zip"
110+
"S3Key": "d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9.zip"
111111
},
112112
"Timeout": 120,
113113
"Handler": "index.handler",

Diff for: packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment-substitution.js.snapshot/manifest.json

+1-96
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,6 @@
11
{
22
"version": "34.0.0",
33
"artifacts": {
4-
"my-stack.assets": {
5-
"type": "cdk:asset-manifest",
6-
"properties": {
7-
"file": "my-stack.assets.json",
8-
"requiresBootstrapStackVersion": 6,
9-
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
10-
}
11-
},
12-
"my-stack": {
13-
"type": "aws:cloudformation:stack",
14-
"environment": "aws://unknown-account/unknown-region",
15-
"properties": {
16-
"templateFile": "my-stack.template.json",
17-
"validateOnSynth": false,
18-
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
19-
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
20-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/5f7bf484ce84a5fb9af1c00b0e00bcb7584993fa5f836a703478a7753525a6ea.json",
21-
"requiresBootstrapStackVersion": 6,
22-
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
23-
"additionalDependencies": [
24-
"my-stack.assets"
25-
],
26-
"lookupRole": {
27-
"arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}",
28-
"requiresBootstrapStackVersion": 8,
29-
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
30-
}
31-
},
32-
"dependencies": [
33-
"my-stack.assets"
34-
],
35-
"metadata": {
36-
"/my-stack/Hello/ServiceRole/Resource": [
37-
{
38-
"type": "aws:cdk:logicalId",
39-
"data": "HelloServiceRole1E55EA16"
40-
}
41-
],
42-
"/my-stack/Hello/Resource": [
43-
{
44-
"type": "aws:cdk:logicalId",
45-
"data": "Hello4A628BD4"
46-
}
47-
],
48-
"/my-stack/substitution-bucket/Resource": [
49-
{
50-
"type": "aws:cdk:logicalId",
51-
"data": "substitutionbucket13A1BF4A"
52-
}
53-
],
54-
"/my-stack/Deployment/AwsCliLayer/Resource": [
55-
{
56-
"type": "aws:cdk:logicalId",
57-
"data": "DeploymentAwsCliLayerB82B26A3"
58-
}
59-
],
60-
"/my-stack/Deployment/CustomResource/Default": [
61-
{
62-
"type": "aws:cdk:logicalId",
63-
"data": "DeploymentCustomResource47E8B2E6"
64-
}
65-
],
66-
"/my-stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource": [
67-
{
68-
"type": "aws:cdk:logicalId",
69-
"data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265"
70-
}
71-
],
72-
"/my-stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource": [
73-
{
74-
"type": "aws:cdk:logicalId",
75-
"data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF"
76-
}
77-
],
78-
"/my-stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource": [
79-
{
80-
"type": "aws:cdk:logicalId",
81-
"data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536"
82-
}
83-
],
84-
"/my-stack/BootstrapVersion": [
85-
{
86-
"type": "aws:cdk:logicalId",
87-
"data": "BootstrapVersion"
88-
}
89-
],
90-
"/my-stack/CheckBootstrapVersion": [
91-
{
92-
"type": "aws:cdk:logicalId",
93-
"data": "CheckBootstrapVersion"
94-
}
95-
]
96-
},
97-
"displayName": "my-stack"
98-
},
994
"test-s3-deploy-substitution.assets": {
1005
"type": "cdk:asset-manifest",
1016
"properties": {
@@ -219,7 +124,7 @@
219124
"validateOnSynth": false,
220125
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
221126
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
222-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/e70bd778aadedf7f4065f219cf272b5b8a2bf42a03c1a0ccb4e7ec4859df0790.json",
127+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/b8505aa6cd55c4ab32c8432e6caf98f78af39a3bfa813375fda36f3aa3f3d5b0.json",
223128
"requiresBootstrapStackVersion": 6,
224129
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
225130
"additionalDependencies": [

Diff for: packages/@aws-cdk-testing/framework-integ/test/aws-s3-deployment/test/integ.bucket-deployment-substitution.js.snapshot/my-stack.assets.json

-58
This file was deleted.

0 commit comments

Comments
 (0)