From 48542f4ecaa65b9cfd05c1418c905e8385d78fca Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 18 Jun 2019 15:19:32 +0300 Subject: [PATCH 1/3] refactor(ssm): API cleanups BREAKING CHANGE: `ParameterStoreString` has been removed. Use `StringParameter.fromStringParameterAttributes`. * **ssm:** `ParameterStoreSecureString` has been removed. Use `StringParameter.fromSecureStringParameterAttributes`. * **ssm:** `ParameterOptions.name` was renamed to `parameterName`. --- packages/@aws-cdk/aws-ssm/lib/index.ts | 1 - .../aws-ssm/lib/parameter-store-string.ts | 90 ------------------- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 63 +++++++++++-- .../test/integ.parameter-store-string.lit.ts | 6 +- .../test/test.parameter-store-string.ts | 16 ++-- .../@aws-cdk/aws-ssm/test/test.parameter.ts | 14 +-- 6 files changed, 75 insertions(+), 115 deletions(-) delete mode 100644 packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts diff --git a/packages/@aws-cdk/aws-ssm/lib/index.ts b/packages/@aws-cdk/aws-ssm/lib/index.ts index e1ed1ca33b93a..dd7718ab70fd8 100644 --- a/packages/@aws-cdk/aws-ssm/lib/index.ts +++ b/packages/@aws-cdk/aws-ssm/lib/index.ts @@ -1,5 +1,4 @@ export * from './parameter'; -export * from './parameter-store-string'; // AWS::SSM CloudFormation Resources: export * from './ssm.generated'; diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts b/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts deleted file mode 100644 index 0a17bba387c4f..0000000000000 --- a/packages/@aws-cdk/aws-ssm/lib/parameter-store-string.ts +++ /dev/null @@ -1,90 +0,0 @@ -import cdk = require('@aws-cdk/cdk'); - -/** - * Properties for a ParameterStoreValue - */ -export interface ParameterStoreStringProps { - /** - * The name of the parameter store value - */ - readonly parameterName: string; - - /** - * The version number of the value you wish to retrieve. - * - * @default The latest version will be retrieved. - */ - readonly version?: number; -} - -/** - * References a public value in AWS Systems Manager Parameter Store - * - * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html - */ -export class ParameterStoreString extends cdk.Construct { - public readonly stringValue: string; - - constructor(scope: cdk.Construct, id: string, props: ParameterStoreStringProps) { - super(scope, id); - - // If we don't validate this here it will lead to a very unclear - // error message in CloudFormation, so better do it. - if (!props.parameterName) { - throw new Error('ParameterStoreString: parameterName cannot be empty'); - } - - // We use a different inner construct depend on whether we want the latest - // or a specific version. - // - // * Latest - generate a Parameter and reference that. - // * Specific - use a Dynamic Reference. - if (props.version === undefined) { - // Construct/get a singleton parameter under the stack - const param = new cdk.CfnParameter(this, 'Parameter', { - type: 'AWS::SSM::Parameter::Value', - default: props.parameterName - }); - this.stringValue = param.valueAsString; - } else { - // Use a dynamic reference - const dynRef = new cdk.CfnDynamicReference(cdk.CfnDynamicReferenceService.Ssm, `${props.parameterName}:${props.version}`); - this.stringValue = dynRef.toString(); - } - } -} - -/** - * Properties for a ParameterStoreValue - */ -export interface ParameterStoreSecureStringProps { - /** - * The name of the parameter store secure string value - */ - readonly parameterName: string; - - /** - * The version number of the value you wish to retrieve. - */ - readonly version: number; -} - -/** - * References a secret value in AWS Systems Manager Parameter Store - * - * It is not possible to retrieve the "latest" value of a secret. - * Use Secrets Manager if you need that ability. - * - * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html - */ -export class ParameterStoreSecureString extends cdk.CfnDynamicReference { - constructor(props: ParameterStoreSecureStringProps) { - super(cdk.CfnDynamicReferenceService.SsmSecure, `${props.parameterName}:${props.version}`); - - // If we don't validate this here it will lead to a very unclear - // error message in CloudFormation, so better do it. - if (!props.parameterName) { - throw new Error('ParameterStoreSecureString: parameterName cannot be empty'); - } - } -} diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 12f6cab9541a9..1f2f3fcab2361 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -1,5 +1,5 @@ import iam = require('@aws-cdk/aws-iam'); -import { CfnDynamicReference, CfnDynamicReferenceService, Construct, Fn, IResource, Resource, Stack, Token } from '@aws-cdk/cdk'; +import { CfnDynamicReference, CfnDynamicReferenceService, Construct, Fn, IResource, Resource, Stack, Token, CfnParameter } from '@aws-cdk/cdk'; import ssm = require('./ssm.generated'); /** @@ -86,9 +86,9 @@ export interface ParameterOptions { /** * The name of the parameter. * - * @default a name will be generated by CloudFormation + * @default - a name will be generated by CloudFormation */ - readonly name?: string; + readonly parameterName?: string; } /** @@ -145,8 +145,35 @@ abstract class ParameterBase extends Resource implements IParameter { } const STRING_PARAM_TYPE = 'String'; +const SECURE_STRING_PARAM_TYPE = 'SecureString'; const STRINGLIST_PARAM_TYPE = 'StringList'; +export interface ParameterAttributes { + /** + * The name of the parameter store value + */ + readonly parameterName: string; + + /** + * The version number of the value you wish to retrieve. + * + * @default The latest version will be retrieved. + */ + readonly version?: number; +} + +export interface SecureStringParameterAttributes { + /** + * The name of the parameter store value + */ + readonly parameterName: string; + + /** + * The version number of the value you wish to retrieve. This is required for secure strings. + */ + readonly version: number; +} + /** * Creates a new String SSM Parameter. * @resource AWS::SSM::Parameter @@ -156,11 +183,31 @@ export class StringParameter extends ParameterBase implements IStringParameter { /** * Imports an external string parameter. */ - public static fromStringParameterName(scope: Construct, id: string, stringParameterName: string): IStringParameter { + public static fromStringParameterAttributes(scope: Construct, id: string, attributes: ParameterAttributes): IStringParameter { + if (!attributes.parameterName) { + throw new Error(`parameterName cannot be an empty string`); + } + + const stringValue = attributes.version + ? new CfnDynamicReference(CfnDynamicReferenceService.Ssm, `${attributes.parameterName}:${attributes.version}`).toString() + : new CfnParameter(scope, `${id}.Parameter`, { type: 'AWS::SSM::Parameter::Value', default: attributes.parameterName }).valueAsString; + class Import extends ParameterBase { - public readonly parameterName = stringParameterName; + public readonly parameterName = attributes.parameterName; public readonly parameterType = STRING_PARAM_TYPE; - public readonly stringValue = new CfnDynamicReference(CfnDynamicReferenceService.Ssm, stringParameterName).toString(); + public readonly stringValue = stringValue; + } + + return new Import(scope, id); + } + + public static fromSecureStringParameterAttributes(scope: Construct, id: string, attributes: SecureStringParameterAttributes): IStringParameter { + const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SsmSecure, `${attributes.parameterName}:${attributes.version}`).toString(); + + class Import extends ParameterBase { + public readonly parameterName = attributes.parameterName; + public readonly parameterType = SECURE_STRING_PARAM_TYPE; + public readonly stringValue = stringValue; } return new Import(scope, id); @@ -180,7 +227,7 @@ export class StringParameter extends ParameterBase implements IStringParameter { const resource = new ssm.CfnParameter(this, 'Resource', { allowedPattern: props.allowedPattern, description: props.description, - name: props.name, + name: props.parameterName, type: STRING_PARAM_TYPE, value: props.stringValue, }); @@ -228,7 +275,7 @@ export class StringListParameter extends ParameterBase implements IStringListPar const resource = new ssm.CfnParameter(this, 'Resource', { allowedPattern: props.allowedPattern, description: props.description, - name: props.name, + name: props.parameterName, type: STRINGLIST_PARAM_TYPE, value: props.stringListValue.join(','), }); diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts index f9e79e408af4e..dd5580f9f3177 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts @@ -7,7 +7,7 @@ class CreatingStack extends cdk.Stack { super(scope, id); new ssm.StringParameter(this, 'String', { - name: '/My/Public/Parameter', + parameterName: '/My/Public/Parameter', stringValue: 'abcdef' }); } @@ -20,14 +20,14 @@ class UsingStack extends cdk.Stack { /// !show // Retrieve the latest value of the non-secret parameter // with name "/My/String/Parameter". - const stringValue = new ssm.ParameterStoreString(this, 'MyValue', { + const stringValue = ssm.StringParameter.fromStringParameterAttributes(this, 'MyValue', { parameterName: '/My/Public/Parameter', // 'version' can be specified but is optional. }).stringValue; // Retrieve a specific version of the secret (SecureString) parameter. // 'version' is always required. - const secretValue = new ssm.ParameterStoreSecureString({ + const secretValue = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'MyValue', { parameterName: '/My/Secret/Parameter', version: 5 }); diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts index 05b1fb9759c35..50aba31e32e6b 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter-store-string.ts @@ -9,7 +9,7 @@ export = { const stack = new cdk.Stack(); // WHEN - const ref = new ssm.ParameterStoreString(stack, 'Ref', { + const ref = ssm.StringParameter.fromStringParameterAttributes(stack, 'Ref', { parameterName: '/some/key', version: 123 }); @@ -25,21 +25,21 @@ export = { const stack = new cdk.Stack(); // WHEN - const ref = new ssm.ParameterStoreString(stack, 'Ref', { + const ref = ssm.StringParameter.fromStringParameterAttributes(stack, 'Ref', { parameterName: '/some/key', }); // THEN expect(stack).toMatch({ Parameters: { - RefParameter407AF5C8: { + RefParameter: { Type: "AWS::SSM::Parameter::Value", Default: "/some/key" } } }); - test.deepEqual(stack.resolve(ref.stringValue), { Ref: 'RefParameter407AF5C8' }); + test.deepEqual(stack.resolve(ref.stringValue), { Ref: 'RefParameter' }); test.done(); }, @@ -49,10 +49,10 @@ export = { const stack = new cdk.Stack(); // WHEN - const ref = new ssm.ParameterStoreSecureString({ + const ref = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'Ref', { parameterName: '/some/key', version: 123 - }); + }).stringValue; // THEN test.equal(stack.resolve(ref), '{{resolve:ssm-secure:/some/key:123}}'); @@ -66,10 +66,10 @@ export = { // WHEN test.throws(() => { - new ssm.ParameterStoreString(stack, 'Ref', { + ssm.StringParameter.fromStringParameterAttributes(stack, 'Ref', { parameterName: '', }); - }, /parameterName cannot be empty/); + }, /parameterName cannot be an empty string/); test.done(); }, diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts index 71d9af9245c0a..080700b315b24 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts @@ -3,6 +3,7 @@ import cdk = require('@aws-cdk/cdk'); import { Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; import ssm = require('../lib'); +import { version } from 'punycode'; export = { 'creating a String SSM Parameter'(test: Test) { @@ -13,7 +14,7 @@ export = { new ssm.StringParameter(stack, 'Parameter', { allowedPattern: '.*', description: 'The value Foo', - name: 'FooParameter', + parameterName: 'FooParameter', stringValue: 'Foo', }); @@ -60,7 +61,7 @@ export = { new ssm.StringListParameter(stack, 'Parameter', { allowedPattern: '(Foo|Bar)', description: 'The values Foo and Bar', - name: 'FooParameter', + parameterName: 'FooParameter', stringListValue: ['Foo', 'Bar'], }); @@ -128,12 +129,15 @@ export = { test.done(); }, - 'StringParameter.fromName'(test: Test) { + 'StringParameter.fromStringParameterAttributes'(test: Test) { // GIVEN const stack = new Stack(); // WHEN - const param = ssm.StringParameter.fromStringParameterName(stack, 'MyParamName', 'MyParamName'); + const param = ssm.StringParameter.fromStringParameterAttributes(stack, 'MyParamName', { + parameterName: 'MyParamName', + version: 2 + }); // THEN test.deepEqual(stack.resolve(param.parameterArn), { @@ -148,7 +152,7 @@ export = { }); test.deepEqual(stack.resolve(param.parameterName), 'MyParamName'); test.deepEqual(stack.resolve(param.parameterType), 'String'); - test.deepEqual(stack.resolve(param.stringValue), '{{resolve:ssm:MyParamName}}'); + test.deepEqual(stack.resolve(param.stringValue), '{{resolve:ssm:MyParamName:2}}'); test.done(); }, From 848cf720ef825f4ce49c0d94c6f5e998a0cfeed0 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 18 Jun 2019 15:47:33 +0300 Subject: [PATCH 2/3] fixes --- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 18 +++++++--- .../@aws-cdk/aws-ssm/test/test.parameter.ts | 33 ++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 1f2f3fcab2361..83bece61ec967 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -1,5 +1,5 @@ import iam = require('@aws-cdk/aws-iam'); -import { CfnDynamicReference, CfnDynamicReferenceService, Construct, Fn, IResource, Resource, Stack, Token, CfnParameter } from '@aws-cdk/cdk'; +import { CfnDynamicReference, CfnDynamicReferenceService, CfnParameter, Construct, Fn, IResource, Resource, Stack, Token } from '@aws-cdk/cdk'; import ssm = require('./ssm.generated'); /** @@ -148,7 +148,7 @@ const STRING_PARAM_TYPE = 'String'; const SECURE_STRING_PARAM_TYPE = 'SecureString'; const STRINGLIST_PARAM_TYPE = 'StringList'; -export interface ParameterAttributes { +export interface StringParameterAttributes { /** * The name of the parameter store value */ @@ -181,9 +181,16 @@ export interface SecureStringParameterAttributes { export class StringParameter extends ParameterBase implements IStringParameter { /** - * Imports an external string parameter. + * Imports an external string parameter by name. */ - public static fromStringParameterAttributes(scope: Construct, id: string, attributes: ParameterAttributes): IStringParameter { + public static fromStringParameterName(scope: Construct, id: string, parameterName: string): IStringParameter { + return this.fromStringParameterAttributes(scope, id, { parameterName }); + } + + /** + * Imports an external string parameter with name and optional version. + */ + public static fromStringParameterAttributes(scope: Construct, id: string, attributes: StringParameterAttributes): IStringParameter { if (!attributes.parameterName) { throw new Error(`parameterName cannot be an empty string`); } @@ -201,6 +208,9 @@ export class StringParameter extends ParameterBase implements IStringParameter { return new Import(scope, id); } + /** + * Imports a secure string parameter from the SSM parameter store. + */ public static fromSecureStringParameterAttributes(scope: Construct, id: string, attributes: SecureStringParameterAttributes): IStringParameter { const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SsmSecure, `${attributes.parameterName}:${attributes.version}`).toString(); diff --git a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts index 080700b315b24..5fcaebf1b679f 100644 --- a/packages/@aws-cdk/aws-ssm/test/test.parameter.ts +++ b/packages/@aws-cdk/aws-ssm/test/test.parameter.ts @@ -3,7 +3,6 @@ import cdk = require('@aws-cdk/cdk'); import { Stack } from '@aws-cdk/cdk'; import { Test } from 'nodeunit'; import ssm = require('../lib'); -import { version } from 'punycode'; export = { 'creating a String SSM Parameter'(test: Test) { @@ -129,6 +128,38 @@ export = { test.done(); }, + 'StringParameter.fromStringParameterName'(test: Test) { + // GIVEN + const stack = new Stack(); + + // WHEN + const param = ssm.StringParameter.fromStringParameterName(stack, 'MyParamName', 'MyParamName'); + + // THEN + test.deepEqual(stack.resolve(param.parameterArn), { + 'Fn::Join': [ '', [ + 'arn:', + { Ref: 'AWS::Partition' }, + ':ssm:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':parameterMyParamName' ] ] + }); + test.deepEqual(stack.resolve(param.parameterName), 'MyParamName'); + test.deepEqual(stack.resolve(param.parameterType), 'String'); + test.deepEqual(stack.resolve(param.stringValue), { Ref: 'MyParamNameParameter' }); + expect(stack).toMatch({ + Parameters: { + MyParamNameParameter: { + Type: "AWS::SSM::Parameter::Value", + Default: "MyParamName" + } + } + }); + test.done(); + }, + 'StringParameter.fromStringParameterAttributes'(test: Test) { // GIVEN const stack = new Stack(); From a4d7c48e1d31caa51f9b2630a06e8e5172d9205a Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Tue, 18 Jun 2019 16:16:25 +0300 Subject: [PATCH 3/3] fixes --- packages/@aws-cdk/aws-ssm/lib/parameter.ts | 22 +++++++++---------- ...g.parameter-store-string.lit.expected.json | 11 +++++++--- .../test/integ.parameter-store-string.lit.ts | 3 ++- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/@aws-cdk/aws-ssm/lib/parameter.ts b/packages/@aws-cdk/aws-ssm/lib/parameter.ts index 83bece61ec967..e79729cf26120 100644 --- a/packages/@aws-cdk/aws-ssm/lib/parameter.ts +++ b/packages/@aws-cdk/aws-ssm/lib/parameter.ts @@ -183,24 +183,24 @@ export class StringParameter extends ParameterBase implements IStringParameter { /** * Imports an external string parameter by name. */ - public static fromStringParameterName(scope: Construct, id: string, parameterName: string): IStringParameter { - return this.fromStringParameterAttributes(scope, id, { parameterName }); + public static fromStringParameterName(scope: Construct, id: string, stringParameterName: string): IStringParameter { + return this.fromStringParameterAttributes(scope, id, { parameterName: stringParameterName }); } /** * Imports an external string parameter with name and optional version. */ - public static fromStringParameterAttributes(scope: Construct, id: string, attributes: StringParameterAttributes): IStringParameter { - if (!attributes.parameterName) { + public static fromStringParameterAttributes(scope: Construct, id: string, attrs: StringParameterAttributes): IStringParameter { + if (!attrs.parameterName) { throw new Error(`parameterName cannot be an empty string`); } - const stringValue = attributes.version - ? new CfnDynamicReference(CfnDynamicReferenceService.Ssm, `${attributes.parameterName}:${attributes.version}`).toString() - : new CfnParameter(scope, `${id}.Parameter`, { type: 'AWS::SSM::Parameter::Value', default: attributes.parameterName }).valueAsString; + const stringValue = attrs.version + ? new CfnDynamicReference(CfnDynamicReferenceService.Ssm, `${attrs.parameterName}:${attrs.version}`).toString() + : new CfnParameter(scope, `${id}.Parameter`, { type: 'AWS::SSM::Parameter::Value', default: attrs.parameterName }).valueAsString; class Import extends ParameterBase { - public readonly parameterName = attributes.parameterName; + public readonly parameterName = attrs.parameterName; public readonly parameterType = STRING_PARAM_TYPE; public readonly stringValue = stringValue; } @@ -211,11 +211,11 @@ export class StringParameter extends ParameterBase implements IStringParameter { /** * Imports a secure string parameter from the SSM parameter store. */ - public static fromSecureStringParameterAttributes(scope: Construct, id: string, attributes: SecureStringParameterAttributes): IStringParameter { - const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SsmSecure, `${attributes.parameterName}:${attributes.version}`).toString(); + public static fromSecureStringParameterAttributes(scope: Construct, id: string, attrs: SecureStringParameterAttributes): IStringParameter { + const stringValue = new CfnDynamicReference(CfnDynamicReferenceService.SsmSecure, `${attrs.parameterName}:${attrs.version}`).toString(); class Import extends ParameterBase { - public readonly parameterName = attributes.parameterName; + public readonly parameterName = attrs.parameterName; public readonly parameterType = SECURE_STRING_PARAM_TYPE; public readonly stringValue = stringValue; } diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json index 85a93ef6c2476..1d3d7baba28e0 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.expected.json @@ -13,17 +13,22 @@ }, { "Parameters": { - "MyValueParameterCCC58B13": { + "MyValueParameter": { "Type": "AWS::SSM::Parameter::Value", "Default": "/My/Public/Parameter" } }, + "Resources": { + "Dummy": { + "Type": "AWS::SNS::Topic" + } + }, "Outputs": { "TheValue": { "Value": { - "Ref": "MyValueParameterCCC58B13" + "Ref": "MyValueParameter" } } } } -] +] \ No newline at end of file diff --git a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts index dd5580f9f3177..9066582ff5513 100644 --- a/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts +++ b/packages/@aws-cdk/aws-ssm/test/integ.parameter-store-string.lit.ts @@ -27,12 +27,13 @@ class UsingStack extends cdk.Stack { // Retrieve a specific version of the secret (SecureString) parameter. // 'version' is always required. - const secretValue = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'MyValue', { + const secretValue = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'MySecureValue', { parameterName: '/My/Secret/Parameter', version: 5 }); /// !hide + new cdk.CfnResource(this, 'Dummy', { type: 'AWS::SNS::Topic' }); new cdk.CfnOutput(this, 'TheValue', { value: stringValue }); // Cannot be provisioned so cannot be actually used