Skip to content

Commit

Permalink
Merge branch 'main' into tezz-io/pipelines
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jul 14, 2022
2 parents 1c19401 + 39a7c1f commit 1c6f3b2
Show file tree
Hide file tree
Showing 27 changed files with 671 additions and 109 deletions.
7 changes: 7 additions & 0 deletions packages/@aws-cdk/aws-appsync/lib/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ export interface BaseResolverProps {
* @default - No caching configuration
*/
readonly cachingConfig?: CachingConfig;
/**
* The maximum number of elements per batch, when using batch invoke
*
* @default - No max batch size
*/
readonly maxBatchSize?: number;
}

/**
Expand Down Expand Up @@ -112,6 +118,7 @@ export class Resolver extends Construct {
requestMappingTemplate: props.requestMappingTemplate ? props.requestMappingTemplate.renderTemplate() : undefined,
responseMappingTemplate: props.responseMappingTemplate ? props.responseMappingTemplate.renderTemplate() : undefined,
cachingConfig: this.createCachingConfig(props.cachingConfig),
maxBatchSize: props.maxBatchSize,
});
props.api.addSchemaDependency(this.resolver);
if (props.dataSource) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ describe('Lambda Mapping Templates', () => {
fieldName: 'relatedPosts',
requestMappingTemplate: appsync.MappingTemplate.lambdaRequest('$util.toJson($ctx)', 'BatchInvoke'),
responseMappingTemplate: appsync.MappingTemplate.lambdaResult(),
maxBatchSize: 10,
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::AppSync::Resolver', {
FieldName: 'relatedPosts',
RequestMappingTemplate: batchMT,
MaxBatchSize: 10,
});
});
});
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-appsync/test/appsync.lambda.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ type Post {
ups: Int
downs: Int
relatedPosts: [Post]
relatedPostsMaxBatchSize: [Post]
}
8 changes: 8 additions & 0 deletions packages/@aws-cdk/aws-appsync/test/integ.appsync-lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,20 @@ lambdaDS.createResolver({
requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('addPost', { withArgs: true })),
responseMappingTemplate,
});

lambdaDS.createResolver({
typeName: 'Post',
fieldName: 'relatedPosts',
requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('relatedPosts', { withSource: true }), 'BatchInvoke'),
responseMappingTemplate,
});

lambdaDS.createResolver({
typeName: 'Post',
fieldName: 'relatedPostsMaxBatchSize',
requestMappingTemplate: appsync.MappingTemplate.lambdaRequest(requestPayload('relatedPostsMaxBatchSize', { withSource: true }), 'BatchInvoke'),
responseMappingTemplate,
maxBatchSize: 2,
});

app.synth();
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ elif [[ "$1" == "--check" ]]; then
exit 1
fi
echo THIS TEST SHOULD PRODUCE A LIST OF BOOKS
curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:$2" -d '{ "query": "query { allPosts { id author title relatedPosts { id title } } }" }" }' $3 | json_pp
curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:$2" -d '{ "query": "query { allPosts { id author title relatedPosts { id title } relatedPostsMaxBatchSize { id title } } }" }" }' $3 | json_pp
echo ""
elif [[ "$1" == "--clean" ]];then
cdk destroy --app "node integ.appsync-lambda.js"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ exports.handler = (event, context, callback) => {
console.log("Got an BatchInvoke Request. The payload has %d items to resolve.", event.length);
const field = event[0].field;
switch(field) {
case "relatedPostsMaxBatchSize":
case "relatedPosts":
var results = [];
// the response MUST contain the same number
Expand Down
33 changes: 33 additions & 0 deletions packages/@aws-cdk/aws-secretsmanager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,36 @@ Alternatively, use `addReplicaRegion()`:
const secret = new secretsmanager.Secret(this, 'Secret');
secret.addReplicaRegion('eu-west-1');
```

## Creating JSON Secrets

Sometimes it is necessary to create a secret in SecretsManager that contains a JSON object.
For example:

```json
{
"username": "myUsername",
"database": "foo",
"password": "mypassword"
}
```

In order to create this type of secret, use the `secretObjectValue` input prop.

```ts
const user = new iam.User(stack, 'User');
const accessKey = new iam.AccessKey(stack, 'AccessKey', { user });
declare const stack: Stack;

new secretsmanager.Secret(stack, 'Secret', {
secretObjectValue: {
username: SecretValue.unsafePlainText(user.userName),
database: SecretValue.unsafePlainText('foo'),
password: accessKey.secretAccessKey,
},
})
```

In this case both the `username` and `database` are not a `Secret` so `SecretValue.unsafePlainText` needs to be used.
This means that they will be rendered as plain text in the template, but in this case neither of those
are actual "secrets".
58 changes: 51 additions & 7 deletions packages/@aws-cdk/aws-secretsmanager/lib/secret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,44 @@ export interface SecretProps {
* to the CloudFormation template (via the AWS Console, SDKs, or CLI).
*
* Specifies text data that you want to encrypt and store in this new version of the secret.
* May be a simple string value, or a string representation of a JSON structure.
* May be a simple string value. To provide a string representation of JSON structure, use {@link SecretProps.secretObjectValue} instead.
*
* Only one of `secretStringBeta1`, `secretStringValue`, and `generateSecretString` can be provided.
* Only one of `secretStringBeta1`, `secretStringValue`, 'secretObjectValue', and `generateSecretString` can be provided.
*
* @default - SecretsManager generates a new secret value.
*/
readonly secretStringValue?: SecretValue;

/**
* Initial value for a JSON secret
*
* **NOTE:** *It is **highly** encouraged to leave this field undefined and allow SecretsManager to create the secret value.
* The secret object -- if provided -- will be included in the output of the cdk as part of synthesis,
* and will appear in the CloudFormation template in the console. This can be secure(-ish) if that value is merely reference to
* another resource (or one of its attributes), but if the value is a plaintext string, it will be visible to anyone with access
* to the CloudFormation template (via the AWS Console, SDKs, or CLI).
*
* Specifies a JSON object that you want to encrypt and store in this new version of the secret.
* To specify a simple string value instead, use {@link SecretProps.secretStringValue}
*
* Only one of `secretStringBeta1`, `secretStringValue`, 'secretObjectValue', and `generateSecretString` can be provided.
*
* @example
* declare const user: iam.User;
* declare const accessKey: iam.AccessKey;
* declare const stack: Stack;
* new secretsmanager.Secret(stack, 'JSONSecret', {
* secretObjectValue: {
* username: SecretValue.unsafePlainText(user.userName), // intrinsic reference, not exposed as plaintext
* database: SecretValue.unsafePlainText('foo'), // rendered as plain text, but not a secret
* password: accessKey.secretAccessKey, // SecretValue
* },
* });
*
* @default - SecretsManager generates a new secret value.
*/
readonly secretObjectValue?: { [key: string]: SecretValue };

/**
* Policy to apply when the secret is removed from this stack.
*
Expand Down Expand Up @@ -233,7 +263,7 @@ export class SecretStringValueBeta1 {
* // Creates a new IAM user, access and secret keys, and stores the secret access key in a Secret.
* const user = new iam.User(this, 'User');
* const accessKey = new iam.AccessKey(this, 'AccessKey', { user });
* const secret = new secrets.Secret(this, 'Secret', {
* const secret = new secretsmanager.Secret(this, 'Secret', {
* secretStringValue: accessKey.secretAccessKey,
* });
* ```
Expand Down Expand Up @@ -582,11 +612,17 @@ export class Secret extends SecretBase {
throw new Error('`secretStringTemplate` and `generateStringKey` must be specified together.');
}

if ((props.generateSecretString ? 1 : 0) + (props.secretStringBeta1 ? 1 : 0) + (props.secretStringValue ? 1 : 0) > 1) {
throw new Error('Cannot specify more than one of `generateSecretString`, `secretStringValue`, and `secretStringBeta1`.');
if ((props.generateSecretString ? 1 : 0)
+ (props.secretStringBeta1 ? 1 : 0)
+ (props.secretStringValue ? 1 : 0)
+ (props.secretObjectValue ? 1 : 0)
> 1) {
throw new Error('Cannot specify more than one of `generateSecretString`, `secretStringValue`, `secretObjectValue`, and `secretStringBeta1`.');
}

const secretString = props.secretStringValue?.unsafeUnwrap() ?? props.secretStringBeta1?.secretValue();
const secretString = props.secretObjectValue
? this.resolveSecretObjectValue(props.secretObjectValue)
: props.secretStringValue?.unsafeUnwrap() ?? props.secretStringBeta1?.secretValue();

const resource = new secretsmanager.CfnSecret(this, 'Resource', {
description: props.description,
Expand Down Expand Up @@ -627,6 +663,14 @@ export class Secret extends SecretBase {
this.excludeCharacters = props.generateSecretString?.excludeCharacters;
}

private resolveSecretObjectValue(secretObject: { [key: string]: SecretValue }): string {
const resolvedObject: { [key: string]: string } = {};
for (const [key, value] of Object.entries(secretObject)) {
resolvedObject[key] = value.unsafeUnwrap();
}
return JSON.stringify(resolvedObject);
}

/**
* Adds a target attachment to the secret.
*
Expand Down Expand Up @@ -968,4 +1012,4 @@ function attachmentTargetTypeToString(x: AttachmentTargetType): string {
case AttachmentTargetType.DOCDB_DB_CLUSTER:
return 'AWS::DocDB::DBCluster';
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Fixture with packages imported, but nothing else
import { Construct } from 'constructs';
import { Duration, Stack } from '@aws-cdk/core';
import { Duration, Stack, SecretValue } from '@aws-cdk/core';
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
import * as kms from '@aws-cdk/aws-kms';
import * as iam from '@aws-cdk/aws-iam';
Expand All @@ -12,4 +12,4 @@ class Fixture extends Stack {

/// here
}
}
}
11 changes: 11 additions & 0 deletions packages/@aws-cdk/aws-secretsmanager/test/integ.secret.lit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as iam from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import { SecretValue } from '@aws-cdk/core';
import * as secretsmanager from '../lib';

class SecretsManagerStack extends cdk.Stack {
Expand Down Expand Up @@ -37,10 +38,20 @@ class SecretsManagerStack extends cdk.Stack {
new secretsmanager.Secret(this, 'PredefinedSecret', {
secretStringValue: accessKey.secretAccessKey,
});

// JSON secret
new secretsmanager.Secret(this, 'JSONSecret', {
secretObjectValue: {
username: SecretValue.unsafePlainText(user.userName),
database: SecretValue.unsafePlainText('foo'),
password: accessKey.secretAccessKey,
},
});
/// !hide
}
}

const app = new cdk.App();
new SecretsManagerStack(app, 'Integ-SecretsManager-Secret');

app.synth();

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,32 @@
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"JSONSecret6FE68AEF": {
"Type": "AWS::SecretsManager::Secret",
"Properties": {
"SecretString": {
"Fn::Join": [
"",
[
"{\"username\":\"",
{
"Ref": "User00B015A1"
},
"\",\"database\":\"foo\",\"password\":\"",
{
"Fn::GetAtt": [
"AccessKeyE6B25659",
"SecretAccessKey"
]
},
"\"}"
]
]
}
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"17.0.0"}
{"version":"20.0.0"}
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
{
"version": "18.0.0",
"version": "20.0.0",
"testCases": {
"aws-secretsmanager/test/integ.secret.lit": {
"SecretTest/DefaultTest": {
"stacks": [
"Integ-SecretsManager-Secret"
],
"diffAssets": false,
"stackUpdateWorkflow": true
"assertionStack": "SecretTestDefaultTestDeployAssert519F6A06"
}
},
"synthContext": {},
"enableLookups": false
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "17.0.0",
"version": "20.0.0",
"artifacts": {
"Tree": {
"type": "cdk:tree",
Expand Down Expand Up @@ -62,9 +62,24 @@
"type": "aws:cdk:logicalId",
"data": "PredefinedSecret660AF4EC"
}
],
"/Integ-SecretsManager-Secret/JSONSecret/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "JSONSecret6FE68AEF"
}
]
},
"displayName": "Integ-SecretsManager-Secret"
},
"SecretTestDefaultTestDeployAssert519F6A06": {
"type": "aws:cloudformation:stack",
"environment": "aws://unknown-account/unknown-region",
"properties": {
"templateFile": "SecretTestDefaultTestDeployAssert519F6A06.template.json",
"validateOnSynth": false
},
"displayName": "SecretTest/DefaultTest/DeployAssert"
}
}
}
Loading

0 comments on commit 1c6f3b2

Please sign in to comment.