From 22a8cfdbd1365a5b94fdbc91d54886b1135c9682 Mon Sep 17 00:00:00 2001 From: "mariano.pizarro" Date: Tue, 12 Apr 2022 10:58:53 -0300 Subject: [PATCH 1/2] feat(s3): Add connections to iamRole, lambda, sns and sqs services --- README.md | 10 +- src/services/cloudfront/schema.graphql | 2 +- src/services/cloudtrail/schema.graphql | 2 +- src/services/iamRole/schema.graphql | 1 + src/services/lambda/schema.graphql | 1 + src/services/s3/connections.ts | 151 +++++++++++++++++++++++++ src/services/s3/data.ts | 28 +++++ src/services/s3/format.ts | 50 ++++++++ src/services/s3/index.ts | 3 + src/services/s3/schema.graphql | 76 ++++++++++--- src/services/sns/schema.graphql | 1 + src/services/sqs/schema.graphql | 1 + src/types/generated.ts | 43 ++++++- 13 files changed, 346 insertions(+), 23 deletions(-) create mode 100644 src/services/s3/connections.ts diff --git a/README.md b/README.md index f40bb1b4..44d85c30 100644 --- a/README.md +++ b/README.md @@ -122,14 +122,14 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | iamServerCertificate | | | iamUser | iamGroup | | iamPolicy | iamRole, iamGroup | -| iamRole | codebuild, configurationRecorder, iamInstanceProfile, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, sageMakerNotebookInstance, systemsManagerInstance guardDutyDetector | +| iamRole | codebuild, configurationRecorder, iamInstanceProfile, iamPolicy, eksCluster, ecsService, flowLog, glueJob, managedAirflow, s3, sageMakerNotebookInstance, systemsManagerInstance guardDutyDetector | | iamGroup | iamUser, iamPolicy | | igw | vpc | | iot | | | kinesisFirehose | kinesisStream, s3 | | kinesisStream | kinesisFirehose | | kms | cloudtrail, cloudwatchLog, codebuild, efs, eksCluster, elastiCacheReplicationGroup, elasticSearchDomain, emrCluster, lambda, rdsClusterSnapshot, sns, sageMakerNotebookInstance, dmsReplicationInstance, redshiftCluster | -| lambda | appSync, cognitoUserPool, kms, securityGroup, subnet, vpc | +| lambda | appSync, cognitoUserPool, kms, s3, securityGroup, subnet, vpc | | managedAirflow | iamRole, securityGroups, subnet, s3 | | nacl | vpc | | natGateway | networkInterface, subnet, vpc | @@ -145,12 +145,12 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | sageMakerExperiment | | | sageMakerNotebookInstance | iamRole, kms, networkInterface, subnet, securityGroup | | sageMakerProject | | -| s3 | cloudfront, cloudtrail, kinesisFirehose, managedAirflow | +| s3 | cloudfront, cloudtrail, iamRole, kinesisFirehose, lambda, managedAirflow, sns, sqs | | secretsManager | | | securityGroup | alb, asg, clientVpnEndpoint, codebuild, dmsReplicationInstance, ecsService, lambda, ec2, elasticSearchDomain, elb, rdsCluster, rdsDbInstance, eksCluster, elastiCacheCluster, managedAirflow, sageMakerNotebookInstance | | ses | | -| sns | kms, cloudtrail, cloudwatch | -| sqs | | +| sns | kms, cloudtrail, cloudwatch, s3 | +| sqs | s3 | | subnet | alb, asg, codebuild, dmsReplicationInstance, ec2, ecsService, efsMountTarget, elastiCacheCluster, elasticSearchDomain, elb, lambda, managedAirflow, natGateway, networkInterface, sageMakerNotebookInstance, routeTable, vpc, eksCluster, emrCluster, flowLog | | systemsManagerInstance | ec2, iamRole | | systemsManagerDocument | | diff --git a/src/services/cloudfront/schema.graphql b/src/services/cloudfront/schema.graphql index 5ced77b9..114276b5 100644 --- a/src/services/cloudfront/schema.graphql +++ b/src/services/cloudfront/schema.graphql @@ -21,7 +21,7 @@ type awsCloudfront @key(fields: "id") { origins: [awsCloudfrontOriginData] logging: awsCloudfrontLoggingConfig elb: [awsElb] @hasInverse(field: cloudfrontDistribution) - s3: [awsS3] @hasInverse(field: cloudfrontDistribution) + s3: [awsS3] @hasInverse(field: cloudfrontDistributions) tags: [awsRawTag] webAcl: [awsWafV2WebAcl] @hasInverse(field: cloudfront) } diff --git a/src/services/cloudtrail/schema.graphql b/src/services/cloudtrail/schema.graphql index e1867bd3..400e31e1 100644 --- a/src/services/cloudtrail/schema.graphql +++ b/src/services/cloudtrail/schema.graphql @@ -20,7 +20,7 @@ type awsCloudtrail @key(fields: "cgId") { status: awsCloudtrailStatus eventSelectors: [awsCloudtrailEventSelector] tags: [awsRawTag] - s3: [awsS3] @hasInverse(field: cloudtrail) + s3: [awsS3] @hasInverse(field: cloudtrails) sns: [awsSns] @hasInverse(field: cloudtrail) kms: [awsKms] @hasInverse(field: cloudtrail) cloudwatchLog: [awsCloudwatchLog] @hasInverse(field: cloudtrail) diff --git a/src/services/iamRole/schema.graphql b/src/services/iamRole/schema.graphql index a1bc288c..4fc1c366 100644 --- a/src/services/iamRole/schema.graphql +++ b/src/services/iamRole/schema.graphql @@ -23,4 +23,5 @@ type awsIamRole @key(fields: "id") { sageMakerNotebookInstances: [awsSageMakerNotebookInstance] @hasInverse(field: iamRole) systemsManagerInstances: [awsSystemsManagerInstance] @hasInverse(field: iamRole) iamInstanceProfiles: [awsIamInstanceProfile] @hasInverse(field: iamRole) + s3: [awsS3] @hasInverse(field: iamRole) } diff --git a/src/services/lambda/schema.graphql b/src/services/lambda/schema.graphql index 0335cd6f..d896ee80 100644 --- a/src/services/lambda/schema.graphql +++ b/src/services/lambda/schema.graphql @@ -26,6 +26,7 @@ type awsLambda @key(fields: "arn") { vpc: [awsVpc] @hasInverse(field: lambda) cognitoUserPool: [awsCognitoUserPool] @hasInverse(field: lambda) #change to plural appSync: [awsAppSync] @hasInverse(field: lambda) + s3: [awsS3] @hasInverse(field: lambdas) } type awsLambdaEnvironmentVariable diff --git a/src/services/s3/connections.ts b/src/services/s3/connections.ts new file mode 100644 index 00000000..2e5cf65d --- /dev/null +++ b/src/services/s3/connections.ts @@ -0,0 +1,151 @@ +import { ServiceConnection } from '@cloudgraph/sdk' +import isEmpty from 'lodash/isEmpty' +import services from '../../enums/services' +import { RawAwsS3 } from './data' +import { RawAwsIamRole } from '../iamRole/data' +import { RawAwsLambdaFunction } from '../lambda/data' +import { RawAwsSns } from '../sns/data' +import { AwsSqs } from '../sqs/data' +import { globalRegionName } from '../../enums/regions' + +/** + * S3 + */ + +export default ({ + service, + data, + region, +}: { + data: { name: string; data: { [property: string]: any[] } }[] + service: RawAwsS3 + region: string +}): { [key: string]: ServiceConnection[] } => { + const connections: ServiceConnection[] = [] + + const { + Id: id, + AdditionalInfo: { + ReplicationConfig: replicationConfig, + NotificationConfiguration: { + LambdaFunctionConfigurations: lambdaFunctionConfigurations, + TopicConfigurations: topicConfigurations, + QueueConfigurations: queueConfigurations, + }, + }, + } = service + + /** + * Find IAM Roles + * related to this S3 + */ + const roles: { name: string; data: { [property: string]: any[] } } = + data.find(({ name }) => name === services.iamRole) + if (replicationConfig?.Role && roles?.data?.[globalRegionName]) { + const dataAtRegion: RawAwsIamRole[] = roles.data[globalRegionName].filter( + role => role.Arn === replicationConfig.Role + ) + if (!isEmpty(dataAtRegion)) { + for (const instance of dataAtRegion) { + const { Arn: arn }: RawAwsIamRole = instance + + connections.push({ + id: arn, + resourceType: services.iamRole, + relation: 'child', + field: 'iamRole', + }) + } + } + } + + /** + * Find lambda functions + * related to this S3 + */ + const lambdaFunctions: { + name: string + data: { [property: string]: any[] } + } = data.find(({ name }) => name === services.lambda) + + const functionArns = lambdaFunctionConfigurations?.map( + lambdaConfig => lambdaConfig?.LambdaFunctionArn + ) + + if (!isEmpty(functionArns) && lambdaFunctions?.data?.[region]) { + const dataAtRegion: RawAwsLambdaFunction[] = lambdaFunctions.data[ + region + ].filter(({ FunctionArn }: RawAwsLambdaFunction) => + functionArns.includes(FunctionArn) + ) + + if (!isEmpty(dataAtRegion)) { + for (const lambdaFunction of dataAtRegion) { + const { FunctionArn: functionArn }: RawAwsLambdaFunction = + lambdaFunction + connections.push({ + id: functionArn, + resourceType: services.lambda, + relation: 'child', + field: 'lambdas', + }) + } + } + } + + /** + * Find SNS topic + * related to this S3 + */ + const snsTopics = data.find(({ name }) => name === services.sns) + const topicArns = topicConfigurations?.map(topic => topic?.TopicArn) + if (!isEmpty(topicArns) && snsTopics?.data?.[region]) { + const snsTopicsInRegion: RawAwsSns[] = snsTopics.data[region].filter( + ({ TopicArn: topicArn }: RawAwsSns) => topicArns.includes(topicArn) + ) + + if (!isEmpty(snsTopicsInRegion)) { + for (const topic of snsTopicsInRegion) { + const { TopicArn: topicArn }: RawAwsSns = topic + connections.push({ + id: topicArn, + resourceType: services.sns, + relation: 'child', + field: 'sns', + }) + } + } + } + + /** + * Find SQS + * related to this S3 + */ + const sqsQueues = data.find(({ name }) => name === services.sqs) + const sqsArns = queueConfigurations?.map(queue => queue?.QueueArn) + if (!isEmpty(sqsArns) && sqsQueues?.data?.[region]) { + const dataAtRegion: AwsSqs[] = sqsQueues.data[region].filter( + ({ sqsAttributes: { QueueArn: queueArn } }: AwsSqs) => + sqsArns.includes(queueArn) + ) + if (!isEmpty(dataAtRegion)) { + for (const instance of dataAtRegion) { + const { + sqsAttributes: { QueueArn: queueArn }, + }: AwsSqs = instance + + connections.push({ + id: queueArn, + resourceType: services.sqs, + relation: 'child', + field: 'sqs', + }) + } + } + } + + const cfStackResult = { + [id]: connections, + } + return cfStackResult +} diff --git a/src/services/s3/data.ts b/src/services/s3/data.ts index f05c8c6e..7262a6e3 100644 --- a/src/services/s3/data.ts +++ b/src/services/s3/data.ts @@ -30,6 +30,7 @@ import S3, { ListBucketsOutput, ListObjectsV2Output, LoggingEnabled, + NotificationConfiguration, Object as S3Object, Owner, Payer, @@ -301,6 +302,29 @@ const getBucketWebsite = async (s3: S3, name: BucketName) => ) }) +const getBucketNotificationConfiguration = async (s3: S3, name: BucketName) => + new Promise(resolve => { + s3.getBucketNotificationConfiguration( + { + Bucket: name, + }, + (err: AWSError, data: NotificationConfiguration) => { + if (err) { + errorLog.generateAwsErrorLog({ + functionName: 's3:getBucketNotificationConfiguration', + err, + }) + } + + if (!isEmpty(data)) { + resolve(data) + } + + resolve({}) + } + ) + }) + const getBucketAdditionalInfo = async (s3: S3, name: BucketName) => new Promise(async resolve => { const promises = [ @@ -318,6 +342,7 @@ const getBucketAdditionalInfo = async (s3: S3, name: BucketName) => getBucketTagging(s3, name), getBucketVersioning(s3, name), getBucketWebsite(s3, name), + getBucketNotificationConfiguration(s3, name), ] const [ @@ -335,6 +360,7 @@ const getBucketAdditionalInfo = async (s3: S3, name: BucketName) => Tags, VersioningInfo, WebsiteInfo, + NotificationConfig, ] = (await Promise.allSettled(promises)).map( /** We force the PromiseFulfilledResult interface * because all promises that we input to Promise.allSettled @@ -364,6 +390,7 @@ const getBucketAdditionalInfo = async (s3: S3, name: BucketName) => Tags: convertAwsTagsToTagMap(Tags), VersioningInfo, StaticWebsiteInfo: WebsiteInfo, + NotificationConfiguration: NotificationConfig, }) }) @@ -455,6 +482,7 @@ export interface RawAwsS3 { ReqPaymentConfig: Payer StaticWebsiteInfo?: GetBucketWebsiteOutput VersioningInfo?: GetBucketVersioningOutput + NotificationConfiguration?: NotificationConfiguration } Tags: TagMap Contents?: S3Object[] diff --git a/src/services/s3/format.ts b/src/services/s3/format.ts index 126bdb13..5377964e 100644 --- a/src/services/s3/format.ts +++ b/src/services/s3/format.ts @@ -3,6 +3,7 @@ import isEmpty from 'lodash/isEmpty' import { GetBucketVersioningOutput, + NotificationConfiguration, Policy, PolicyStatus, PublicAccessBlockConfiguration, @@ -47,6 +48,7 @@ export default ({ ReqPaymentConfig: reqPaymentConfig, StaticWebsiteInfo: staticWebsiteInfo, VersioningInfo: versioningInfo, + NotificationConfiguration: notificationConfiguration, } = { AccelerationConfig: '', BucketOwnerData: { DisplayName: '' }, @@ -62,6 +64,7 @@ export default ({ ReqPaymentConfig: '', StaticWebsiteInfo: {}, VersioningInfo: {}, + NotificationConfiguration: {}, }, } = rawData @@ -172,6 +175,52 @@ export default ({ }) } + let notificationConfigurationData = { + topicConfigurations: [], + queueConfigurations: [], + lambdaFunctionConfigurations: [], + } + + if (!isEmpty(notificationConfiguration)) { + const { + TopicConfigurations: topicConfigurations = [], + QueueConfigurations: queueConfigurations = [], + LambdaFunctionConfigurations: lambdaFunctionConfigurations = [], + }: NotificationConfiguration = notificationConfiguration + notificationConfigurationData = { + topicConfigurations: topicConfigurations?.map(tc => ({ + id: tc.Id || cuid(), + topicArn: tc.TopicArn, + events: tc.Events || [], + filterRules: tc.Filter?.Key?.FilterRules?.map(r => ({ + id: cuid(), + name: r.Name, + value: r.Value, + })) || [], + })) || [], + queueConfigurations: queueConfigurations?.map(qc => ({ + id: qc.Id || cuid(), + queueArn: qc.QueueArn, + events: qc.Events || [], + filterRules: qc.Filter?.Key?.FilterRules?.map(r => ({ + id: cuid(), + name: r.Name, + value: r.Value, + })) || [], + })) || [], + lambdaFunctionConfigurations: lambdaFunctionConfigurations?.map(lc => ({ + id: lc.Id || cuid(), + lambdaFunctionArn: lc.LambdaFunctionArn, + events: lc.Events || [], + filterRules: lc.Filter?.Key?.FilterRules?.map(r => ({ + id: cuid(), + name: r.Name, + value: r.Value, + })) || [], + })) || [], + } + } + // // Format S3 Tags const s3Tags = formatTagsFromMap(tags) @@ -201,6 +250,7 @@ export default ({ ? `${awsBucketItemsLimit}+` : `${total}`, transferAcceleration: accelerationStatus, + notificationConfiguration: notificationConfigurationData, } return s3 } diff --git a/src/services/s3/index.ts b/src/services/s3/index.ts index dfa1a981..7fb03148 100644 --- a/src/services/s3/index.ts +++ b/src/services/s3/index.ts @@ -2,6 +2,7 @@ import { Service } from '@cloudgraph/sdk' import BaseService from '../base' import format from './format' import getData from './data' +import getConnections from './connections' import mutation from './mutation' export default class S3 extends BaseService implements Service { @@ -9,5 +10,7 @@ export default class S3 extends BaseService implements Service { getData = getData.bind(this) + getConnections = getConnections.bind(this) + mutation = mutation } diff --git a/src/services/s3/schema.graphql b/src/services/s3/schema.graphql index a2547496..6aec93ac 100644 --- a/src/services/s3/schema.graphql +++ b/src/services/s3/schema.graphql @@ -1,3 +1,58 @@ +type awsBucketPolicy + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + policy: awsIamJSONPolicy +} + +type awsS3FilterRule + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id @search(by: [hash]) + name: String @search(by: [hash]) + value: String @search(by: [hash]) +} + +interface awsS3ConfigurationBase + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + events: [String] @search(by: [hash]) + filterRules: [awsS3FilterRule] +} + +type awsS3TopicConfiguration implements awsS3ConfigurationBase { + topicArn: String @search(by: [hash]) +} + +type awsS3QueueConfiguration implements awsS3ConfigurationBase { + queueArn: String @search(by: [hash]) +} + +type awsS3LambdaFunctionConfiguration implements awsS3ConfigurationBase { + lambdaFunctionArn: String @search(by: [hash]) +} + +type awsS3NotificationConfiguration + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + topicConfigurations: [awsS3TopicConfiguration] + queueConfigurations: [awsS3QueueConfiguration] + lambdaFunctionConfigurations: [awsS3LambdaFunctionConfiguration] +} + type awsS3 @key(fields: "arn") { id: String! @id @search(by: [hash]) accountId: String! @search(by: [hash]) @@ -21,22 +76,15 @@ type awsS3 @key(fields: "arn") { mfa: String @search(by: [hash, regexp]) versioning: String @search(by: [hash, regexp]) staticWebsiteHosting: String @search(by: [hash, regexp]) + notificationConfiguration: awsS3NotificationConfiguration bucketPolicies: [awsBucketPolicy] kinesisFirehose: [awsKinesisFirehose] @hasInverse(field: s3) tags: [awsRawTag] - cloudfrontDistribution: [awsCloudfront] @hasInverse(field: s3) #change to plural - cloudtrail: [awsCloudtrail] @hasInverse(field: s3) #change to plural + cloudfrontDistributions: [awsCloudfront] @hasInverse(field: s3) + cloudtrails: [awsCloudtrail] @hasInverse(field: s3) managedAirflows: [awsManagedAirflow] @hasInverse(field: s3) -} - -# TODO: use getBucketReplication and getBucketNotificationConfiguration to make connections to lambda, sns, iamRole, SQS - -type awsBucketPolicy - @generate( - query: { get: false, query: true, aggregate: false } - mutation: { add: false, delete: false } - subscription: false - ) { - id: String! @id - policy: awsIamJSONPolicy + iamRole: [awsIamRole] @hasInverse(field: s3) + lambdas: [awsLambda] @hasInverse(field: s3) + sns: [awsSns] @hasInverse(field: s3) + sqs: [awsSqs] @hasInverse(field: s3) } diff --git a/src/services/sns/schema.graphql b/src/services/sns/schema.graphql index e68e5cdf..84323c41 100644 --- a/src/services/sns/schema.graphql +++ b/src/services/sns/schema.graphql @@ -12,6 +12,7 @@ type awsSns @key(fields: "arn") { kms: [awsKms] @hasInverse(field: sns) cloudwatch: [awsCloudwatch] @hasInverse(field: sns) cloudFormationStack: [awsCloudFormationStack] @hasInverse(field: sns) + s3: [awsS3] @hasInverse(field: sns) } type awsSnsSubscription diff --git a/src/services/sqs/schema.graphql b/src/services/sqs/schema.graphql index 1d659b4b..d44591ef 100644 --- a/src/services/sqs/schema.graphql +++ b/src/services/sqs/schema.graphql @@ -22,4 +22,5 @@ type awsSqs @key(fields: "arn"){ fifoThroughputLimit: String @search(by: [hash, regexp]) contentBasedDeduplication: Boolean @search tags: [awsRawTag] + s3: [awsS3] @hasInverse(field: sqs) } diff --git a/src/types/generated.ts b/src/types/generated.ts index 2e759360..fe619af8 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -3203,6 +3203,7 @@ export type AwsIamRole = { maxSessionDuration?: Maybe; name?: Maybe; path?: Maybe; + s3?: Maybe>>; sageMakerNotebookInstances?: Maybe>>; systemsManagerInstances?: Maybe>>; tags?: Maybe>>; @@ -3385,6 +3386,7 @@ export type AwsLambda = { reservedConcurrentExecutions?: Maybe; role?: Maybe; runtime?: Maybe; + s3?: Maybe>>; securityGroups?: Maybe>>; sourceCodeSize?: Maybe; subnet?: Maybe>>; @@ -3881,22 +3883,27 @@ export type AwsS3 = { blockPublicPolicy?: Maybe; bucketOwnerName?: Maybe; bucketPolicies?: Maybe>>; - cloudfrontDistribution?: Maybe>>; - cloudtrail?: Maybe>>; + cloudfrontDistributions?: Maybe>>; + cloudtrails?: Maybe>>; corsConfiguration?: Maybe; crossRegionReplication?: Maybe; encrypted?: Maybe; + iamRole?: Maybe>>; id: Scalars['String']; ignorePublicAcls?: Maybe; kinesisFirehose?: Maybe>>; + lambdas?: Maybe>>; lifecycle?: Maybe; logging?: Maybe; managedAirflows?: Maybe>>; mfa?: Maybe; + notificationConfiguration?: Maybe; region?: Maybe; requesterPays?: Maybe; restrictPublicBuckets?: Maybe; size?: Maybe; + sns?: Maybe>>; + sqs?: Maybe>>; staticWebsiteHosting?: Maybe; tags?: Maybe>>; totalNumberOfObjectsInBucket?: Maybe; @@ -3904,6 +3911,36 @@ export type AwsS3 = { versioning?: Maybe; }; +export type AwsS3ConfigurationBase = { + events?: Maybe>>; + filterRules?: Maybe>>; + id: Scalars['String']; +}; + +export type AwsS3FilterRule = { + id: Scalars['String']; + name?: Maybe; + value?: Maybe; +}; + +export type AwsS3LambdaFunctionConfiguration = AwsS3ConfigurationBase & { + lambdaFunctionArn?: Maybe; +}; + +export type AwsS3NotificationConfiguration = { + lambdaFunctionConfigurations?: Maybe>>; + queueConfigurations?: Maybe>>; + topicConfigurations?: Maybe>>; +}; + +export type AwsS3QueueConfiguration = AwsS3ConfigurationBase & { + queueArn?: Maybe; +}; + +export type AwsS3TopicConfiguration = AwsS3ConfigurationBase & { + topicArn?: Maybe; +}; + export type AwsSageMakerExperiment = { accountId: Scalars['String']; arn: Scalars['String']; @@ -4092,6 +4129,7 @@ export type AwsSns = { kms?: Maybe>>; policy?: Maybe; region: Scalars['String']; + s3?: Maybe>>; subscriptions?: Maybe>>; tags?: Maybe>>; }; @@ -4124,6 +4162,7 @@ export type AwsSqs = { queueUrl: Scalars['String']; receiveMessageWaitTimeSeconds?: Maybe; region?: Maybe; + s3?: Maybe>>; sqsManagedSseEnabled?: Maybe; tags?: Maybe>>; visibilityTimeout?: Maybe; From 1ca01fd9b1dabc110b87e0c74e3e63b5c0cb1099 Mon Sep 17 00:00:00 2001 From: "mariano.pizarro" Date: Tue, 12 Apr 2022 12:21:39 -0300 Subject: [PATCH 2/2] feat(s3): Add connections to iamRole, lambda, sns and sqs services --- src/services/s3/connections.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/s3/connections.ts b/src/services/s3/connections.ts index 2e5cf65d..4f927cc2 100644 --- a/src/services/s3/connections.ts +++ b/src/services/s3/connections.ts @@ -144,8 +144,8 @@ export default ({ } } - const cfStackResult = { + const s3Result = { [id]: connections, } - return cfStackResult + return s3Result }