Skip to content

Commit

Permalink
fix(integ-tests): use transformToString on API call response body (#2…
Browse files Browse the repository at this point in the history
…7122)

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*
  • Loading branch information
colifran authored and Mike Wrighton committed Sep 14, 2023
1 parent 9bafd63 commit 17e39d2
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 998 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32605,12 +32605,32 @@ var HttpHandler = class extends CustomResourceHandler {
var import_sdk_v2_to_v3_adapter = __toESM(require_lib5());

// lib/assertions/providers/lambda-handler/utils.ts
function parseJsonPayload(payload) {
async function coerceValue(v) {
if (v && typeof v === "object" && typeof v.transformToString === "function") {
const text = await v.transformToString();
return tryJsonParse(text);
}
return tryJsonParse(v);
}
function tryJsonParse(v) {
if (typeof v !== "string") {
return v;
}
try {
const buffer = Buffer.from(payload);
return JSON.parse(new TextDecoder().decode(buffer));
return JSON.parse(v);
} catch {
return payload;
return v;
}
}
async function coerceResponse(response) {
if (response == null) {
return;
}
for (const key of Object.keys(response)) {
response[key] = await coerceValue(response[key]);
if (typeof response[key] === "object") {
await coerceResponse(response[key]);
}
}
}
function decodeParameters(obj) {
Expand Down Expand Up @@ -32687,9 +32707,7 @@ var AwsApiCallHandler = class extends CustomResourceHandler {
const commandInput = (0, import_sdk_v2_to_v3_adapter.coerceApiParametersToUint8Array)(request2.service, request2.api, parameters);
console.log(`SDK request to ${sdkPkg.service}.${request2.api} with parameters ${JSON.stringify(commandInput)}`);
const response = await client.send(new Command(commandInput));
if (response.Payload) {
response.Payload = parseJsonPayload(response.Payload);
}
await coerceResponse(response);
console.log(`SDK response received ${JSON.stringify(response)}`);
delete response.$metadata;
const respond = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
{
"version": "34.0.0",
"files": {
"77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754": {
"d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9": {
"source": {
"path": "asset.77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754.bundle",
"path": "asset.d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9.bundle",
"packaging": "zip"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754.zip",
"objectKey": "d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9.zip",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
},
"e70bd778aadedf7f4065f219cf272b5b8a2bf42a03c1a0ccb4e7ec4859df0790": {
"b8505aa6cd55c4ab32c8432e6caf98f78af39a3bfa813375fda36f3aa3f3d5b0": {
"source": {
"path": "deploytimesubstitutionintegtestDefaultTestDeployAssertCBBB427B.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "e70bd778aadedf7f4065f219cf272b5b8a2bf42a03c1a0ccb4e7ec4859df0790.json",
"objectKey": "b8505aa6cd55c4ab32c8432e6caf98f78af39a3bfa813375fda36f3aa3f3d5b0.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"outputPaths": [
"Body"
],
"salt": "1694452807292"
"salt": "1694616200437"
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
Expand Down Expand Up @@ -107,7 +107,7 @@
"S3Bucket": {
"Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"
},
"S3Key": "77997674c0a10fbb65169124ad6c0d7a664b6162ad44f9abfa22fd006b33f754.zip"
"S3Key": "d64a3854b41ddbd7cf27814092bb7ddde13e5292ea05bb6912d79400ad79a5a9.zip"
},
"Timeout": 120,
"Handler": "index.handler",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,101 +1,6 @@
{
"version": "34.0.0",
"artifacts": {
"my-stack.assets": {
"type": "cdk:asset-manifest",
"properties": {
"file": "my-stack.assets.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version"
}
},
"my-stack": {
"type": "aws:cloudformation:stack",
"environment": "aws://unknown-account/unknown-region",
"properties": {
"templateFile": "my-stack.template.json",
"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}/5f7bf484ce84a5fb9af1c00b0e00bcb7584993fa5f836a703478a7753525a6ea.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
"my-stack.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": [
"my-stack.assets"
],
"metadata": {
"/my-stack/Hello/ServiceRole/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "HelloServiceRole1E55EA16"
}
],
"/my-stack/Hello/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "Hello4A628BD4"
}
],
"/my-stack/substitution-bucket/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "substitutionbucket13A1BF4A"
}
],
"/my-stack/Deployment/AwsCliLayer/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "DeploymentAwsCliLayerB82B26A3"
}
],
"/my-stack/Deployment/CustomResource/Default": [
{
"type": "aws:cdk:logicalId",
"data": "DeploymentCustomResource47E8B2E6"
}
],
"/my-stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265"
}
],
"/my-stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/ServiceRole/DefaultPolicy/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRoleDefaultPolicy88902FDF"
}
],
"/my-stack/Custom::CDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756C81C01536"
}
],
"/my-stack/BootstrapVersion": [
{
"type": "aws:cdk:logicalId",
"data": "BootstrapVersion"
}
],
"/my-stack/CheckBootstrapVersion": [
{
"type": "aws:cdk:logicalId",
"data": "CheckBootstrapVersion"
}
]
},
"displayName": "my-stack"
},
"test-s3-deploy-substitution.assets": {
"type": "cdk:asset-manifest",
"properties": {
Expand Down Expand Up @@ -219,7 +124,7 @@
"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}/e70bd778aadedf7f4065f219cf272b5b8a2bf42a03c1a0ccb4e7ec4859df0790.json",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/b8505aa6cd55c4ab32c8432e6caf98f78af39a3bfa813375fda36f3aa3f3d5b0.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
Expand Down

This file was deleted.

Loading

0 comments on commit 17e39d2

Please sign in to comment.