Amazon.CDK.AWS.Lex: Property that used to be untyped and is now typed is easy to misuse
Describe the bug
It seems that there is a PascalCase / camelCase issue when deploying a new Lex Bot using the CfnBot class. There is a mandatory property called "DataPrivacy". This property must be of type "CfnBot.DataPrivacyProperty", which also contains a mandatory property called "ChildDirected". Even this property has been set to "true", when deploying the stack it throws an error like this:
UPDATE_ROLLBACK_COMPLETE: Properties validation failed for resource MyResourceA629FA55 with message: [#/DataPrivacy: extraneous key [childDirected] is not permitted]
Regression Issue
- [ ] Select this option if this issue appears to be a regression.
Last Known Working CDK Version
No response
Expected Behavior
It should deploy the Lex bot without any issues.
Current Behavior
The deployment of the Lex bot is failing, so the entire changeset gets rolled back.
Reproduction Steps
Define a CfnBot like this:
var bot = new CfnBot(this, $"{id}-{botName}", new CfnBotProps
{
Name = $"{botName}",
RoleArn = lexRole.RoleArn,
DataPrivacy = new CfnBot.DataPrivacyProperty
{
ChildDirected = false
},
IdleSessionTtlInSeconds = 300, // 5 minutes
Description = $"Bot for the {id} application.",
BotFileS3Location = new CfnBot.S3LocationProperty
{
S3Bucket = importBucket.BucketName,
S3ObjectKey = botKey,
}
});
Possible Solution
Fix the JsiiProperty attribute of the property ChildDirected of the class Amazon.CDK.AWS.Lex.CfnBot.DataPrivacyProperty by changing its name from "childDirected" to "ChildDirected".
Additional Information/Context
No response
CDK CLI Version
2.1003.0 (build b242c23)
Framework Version
.net 8
Node.js Version
v20.9.0
OS
Windows 11 23H2
Language
.NET
Language Version
No response
Other information
No response
Reproducible. It synthesizes into below CFN template (for example):
Resources:
CdktestDotnetStackTestBot:
Type: AWS::Lex::Bot
Properties:
BotFileS3Location:
S3Bucket: testbucket
S3ObjectKey: testkey
DataPrivacy:
childDirected: false
Description: Bot for the CdktestDotnetStack application.
IdleSessionTTLInSeconds: 300
Name: TestBot
RoleArn: arn:aws:iam::<<ACCOUNT-ID>>:role/TestEC2ReadOnlyRole
Metadata:
aws:cdk:path: CdktestDotnetStack/CdktestDotnetStack-TestBot
...
Refer AWS::Lex::Bot DataPrivacy, there is a casing difference.
This appears to be JSII issue.
This is not a jsii bug, but an unfortunate side effect of CloudFormation type refinement that we have to fix in CDK.
There is a mandatory property called "DataPrivacy". This property must be of type "CfnBot.DataPrivacyProperty",
You would expect so, but unfortunately it must not be of type CfnBot.DataPrivacyProperty.
Untyped data
At some point in the past, the CloudFormation schema defined the type of dataPrivacy to be "an arbitray JSON object".
In CDK, this leads to dataPrivacy being typed as any (or in the case of .NET, object).
That means we cannot know what fields are expected by CloudFormation. So when you write:
{
childDirected: true
}
We can't know if it's actually childDirected or intended to be ChildDirected. We have to be conservative, and emit properties of untyped objects as the same input that we receive.
Refining types
At some time after that, the Lex team introduced types for DataPrivacy. Yay...
Backwards compatibility
...except we can't change the type of dataPrivacy: any into dataPrivacy: DataPrivacyProperty, because it would change the meaning of existing programs!
new CfnBot(..., {
dataPrivacy: {
ChildDirected: true, // <-- ❌ is now a compilation error because the property is named childDirected
},
})
To make matters worse
To make matters worse, we are emitting type definitions for the new DataPrivacyProperty type, and that's the definitions you are using... but we're not accepting properties of that type anywhere...
...except that in .NET the type is public object DataPrivacy, which accepts any object including DataPrivacyProperty, which renders over the jsii wire to { childDirected: true } (notice the lowercase), because that is what a field that would have expected a DataPrivacyProperty type to have rendered to.
Bottom line
The bottom line is that dataPrivacy is actually of type Map<string, object>, and it expects literal keys.
The long-term solution would be to recognize these situations when typing is added onto an object whose properties used to have been typed as any, and render the following instead:
interface CfnBotProps {
/** @deprecated use dataPrivacyV2 instead */
dataPrivacy?: any;
dataPrivacyV2?: DataPrivacyProperty;
}
Hi, @rix0rrr, do you know if this issue is going to be fixed in the near future?
Many thanks,
Jordi