Skip to content

Commit 451d54b

Browse files
committed
feat: Add JSON Schema validation for cdk.json
1 parent 2f0cfc4 commit 451d54b

File tree

4 files changed

+300
-0
lines changed

4 files changed

+300
-0
lines changed

.projenrc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,7 @@ const cli = configureProject(
11691169
'wrap-ansi@^7', // Last non-ESM version
11701170
'yaml@^1',
11711171
'yargs@^15',
1172+
'jsonschema',
11721173
],
11731174
tsconfig: {
11741175
compilerOptions: {

packages/aws-cdk/lib/cli/user-configuration.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import * as os from 'os';
22
import * as fs_path from 'path';
33
import { ToolkitError } from '@aws-cdk/toolkit-lib';
44
import * as fs from 'fs-extra';
5+
import { validate } from 'jsonschema';
56
import { Context, PROJECT_CONTEXT } from '../api/context';
67
import { Settings } from '../api/settings';
78
import type { Tag } from '../api/tags';
89
import type { IoHelper } from '../api-private';
10+
import { cdkConfigSchema } from '../schema';
911

1012
export const PROJECT_CONFIG = 'cdk.json';
1113
export { PROJECT_CONTEXT } from '../api/context';
@@ -210,6 +212,9 @@ async function settingsFromFile(ioHelper: IoHelper, fileName: string): Promise<S
210212
const expanded = expandHomeDir(fileName);
211213
if (await fs.pathExists(expanded)) {
212214
const data = await fs.readJson(expanded);
215+
216+
await validateConfigurationFile(data, fileName, ioHelper);
217+
213218
settings = new Settings(data);
214219
} else {
215220
settings = new Settings();
@@ -408,3 +413,54 @@ async function parseStringTagsListToObject(
408413
}
409414
return tags.length > 0 ? tags : undefined;
410415
}
416+
417+
/**
418+
* Validates configuration data against the CDK JSON Schema
419+
*
420+
* @param data - The configuration object to validate
421+
* @param fileName - The file name for error reporting
422+
* @param ioHelper - IoHelper for logging warnings
423+
*/
424+
async function validateConfigurationFile(data: any, fileName: string, ioHelper: IoHelper): Promise<void> {
425+
try {
426+
const schema = cdkConfigSchema;
427+
428+
// Validate configuration against jsonschema, log warnings
429+
const result = validate(data, schema);
430+
431+
if (result.errors && result.errors.length > 0) {
432+
for (const error of result.errors) {
433+
const propertyPath = error.property ? error.property.replace('instance.', '') : 'root';
434+
435+
// Provide warning messages
436+
if (error.name === 'additionalProperties') {
437+
await ioHelper.defaults.warning(
438+
`Unknown property '${error.argument}' in ${fileName}. This property is not recognized by the CDK CLI.`
439+
);
440+
} else {
441+
await ioHelper.defaults.warning(
442+
`Configuration validation warning in ${fileName}: ${error.message} at '${propertyPath}'`
443+
);
444+
}
445+
}
446+
}
447+
448+
// Custom validation for unknown properties
449+
if (data && typeof data === 'object' && !Array.isArray(data)) {
450+
const knownProperties = Object.keys(schema.properties || {});
451+
const configProperties = Object.keys(data);
452+
const unknownProperties = configProperties.filter(prop => !knownProperties.includes(prop));
453+
454+
if (unknownProperties.length > 0) {
455+
for (const prop of unknownProperties) {
456+
await ioHelper.defaults.warning(
457+
`Unknown configuration property '${prop}' in ${fileName}. This property will be preserved but may not be recognized by CDK. ` +
458+
`Check for typos in property names.`
459+
);
460+
}
461+
}
462+
}
463+
} catch (error) {
464+
await ioHelper.defaults.debug(`Schema validation failed for ${fileName}: ${error}`);
465+
}
466+
}
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"$id": "https://raw.githubusercontent.com/aws/aws-cdk-cli/main/packages/aws-cdk/lib/schema/cdk-config.schema.json",
4+
"title": "CDK Configuration",
5+
"description": "Schema for cdk.json configuration files used by the AWS CDK CLI",
6+
"type": "object",
7+
"properties": {
8+
"app": {
9+
"type": "string",
10+
"description": "The command that executes the CDK application"
11+
},
12+
"build": {
13+
"type": "string",
14+
"description": "The command that compiles or builds the CDK application before synthesis (not permitted in ~/.cdk.json)"
15+
},
16+
"language": {
17+
"type": "string",
18+
"description": "The language to be used for initializing new projects",
19+
"enum": ["typescript", "javascript", "python", "java", "csharp", "go", "fsharp"]
20+
},
21+
"output": {
22+
"type": "string",
23+
"default": "cdk.out",
24+
"description": "The name of the directory into which the synthesized cloud assembly will be emitted"
25+
},
26+
"outputsFile": {
27+
"type": "string",
28+
"description": "The file to which AWS CloudFormation outputs from deployed stacks will be written (in JSON format)"
29+
},
30+
"profile": {
31+
"type": "string",
32+
"description": "Name of the default AWS profile used for specifying Region and account credentials"
33+
},
34+
"toolkitStackName": {
35+
"type": "string",
36+
"description": "The name of the bootstrap stack"
37+
},
38+
"toolkitBucketName": {
39+
"type": "string",
40+
"description": "The name of the Amazon S3 bucket used for deploying assets such as Lambda functions and container images"
41+
},
42+
"bootstrapKmsKeyId": {
43+
"type": "string",
44+
"description": "Overrides the ID of the AWS KMS key used to encrypt the Amazon S3 deployment bucket"
45+
},
46+
"requireApproval": {
47+
"type": "string",
48+
"description": "Default approval level for security changes",
49+
"enum": ["never", "any-change", "broadening"]
50+
},
51+
"assetMetadata": {
52+
"type": "boolean",
53+
"default": true,
54+
"description": "If false, CDK does not add metadata to resources that use assets"
55+
},
56+
"pathMetadata": {
57+
"type": "boolean",
58+
"default": true,
59+
"description": "If false, CDK path metadata is not added to synthesized templates"
60+
},
61+
"notices": {
62+
"type": "boolean",
63+
"description": "If false, suppresses the display of messages about security vulnerabilities, regressions, and unsupported versions"
64+
},
65+
"versionReporting": {
66+
"type": "boolean",
67+
"default": true,
68+
"description": "If false, opts out of version reporting"
69+
},
70+
"debug": {
71+
"type": "boolean",
72+
"description": "If true, CDK CLI emits more detailed information useful for debugging"
73+
},
74+
"staging": {
75+
"type": "boolean",
76+
"description": "If false, assets are not copied to the output directory"
77+
},
78+
"lookups": {
79+
"type": "boolean",
80+
"description": "If false, no context lookups are permitted"
81+
},
82+
"rollback": {
83+
"type": "boolean",
84+
"description": "If false, failed deployments are not rolled back"
85+
},
86+
"progress": {
87+
"type": "string",
88+
"description": "If set to 'events', the CDK CLI displays all AWS CloudFormation events during deployment, rather than a progress bar",
89+
"enum": ["bar", "events"]
90+
},
91+
"browser": {
92+
"type": "string",
93+
"description": "The command for launching a Web browser for the cdk docs subcommand"
94+
},
95+
"context": {
96+
"type": "object",
97+
"description": "Context values and feature flags (values in configuration file will not be erased by cdk context --clear)",
98+
"additionalProperties": true
99+
},
100+
"plugin": {
101+
"type": "array",
102+
"items": {
103+
"type": "string"
104+
},
105+
"description": "JSON array specifying the package names or local paths of packages that extend the CDK"
106+
},
107+
"tags": {
108+
"type": "array",
109+
"items": {
110+
"type": "object",
111+
"properties": {
112+
"Key": {
113+
"type": "string"
114+
},
115+
"Value": {
116+
"type": "string"
117+
}
118+
},
119+
"required": ["Key", "Value"],
120+
"additionalProperties": false
121+
},
122+
"description": "JSON array containing tags (key-value pairs) for the stack"
123+
},
124+
"watch": {
125+
"type": "object",
126+
"properties": {
127+
"include": {
128+
"oneOf": [
129+
{
130+
"type": "string"
131+
},
132+
{
133+
"type": "array",
134+
"items": {
135+
"type": "string"
136+
}
137+
}
138+
],
139+
"description": "Files or directories that should trigger a rebuild when changed"
140+
},
141+
"exclude": {
142+
"oneOf": [
143+
{
144+
"type": "string"
145+
},
146+
{
147+
"type": "array",
148+
"items": {
149+
"type": "string"
150+
}
151+
}
152+
],
153+
"description": "Files or directories that should not trigger a rebuild when changed"
154+
}
155+
},
156+
"additionalProperties": false,
157+
"description": "Configuration for watch mode file monitoring"
158+
},
159+
"proxy": {
160+
"type": "string",
161+
"description": "Proxy server URL for HTTP requests"
162+
},
163+
"caBundlePath": {
164+
"type": "string",
165+
"description": "Path to CA certificate bundle for HTTPS requests"
166+
},
167+
"assetParallelism": {
168+
"type": "integer",
169+
"minimum": 1,
170+
"description": "Number of parallel asset uploads"
171+
},
172+
"assetPrebuild": {
173+
"type": "boolean",
174+
"description": "Whether to prebuild all assets before deployment"
175+
},
176+
"ignoreNoStacks": {
177+
"type": "boolean",
178+
"description": "Whether to ignore the error when no stacks are selected"
179+
},
180+
"hotswap": {
181+
"type": "object",
182+
"properties": {
183+
"ecs": {
184+
"type": "object",
185+
"properties": {
186+
"minimumHealthyPercent": {
187+
"type": "integer",
188+
"minimum": 0,
189+
"maximum": 100,
190+
"description": "Minimum healthy percent for ECS hotswap deployments"
191+
},
192+
"maximumHealthyPercent": {
193+
"type": "integer",
194+
"minimum": 100,
195+
"description": "Maximum healthy percent for ECS hotswap deployments"
196+
},
197+
"stabilizationTimeoutSeconds": {
198+
"type": "integer",
199+
"minimum": 0,
200+
"description": "Stabilization timeout in seconds for ECS hotswap deployments"
201+
}
202+
},
203+
"additionalProperties": false
204+
}
205+
},
206+
"additionalProperties": false,
207+
"description": "Configuration for hotswap deployments"
208+
},
209+
"unstable": {
210+
"type": "array",
211+
"items": {
212+
"type": "string"
213+
},
214+
"description": "List of unstable features to enable"
215+
},
216+
"quiet": {
217+
"type": "boolean",
218+
"description": "Suppress output during synthesis"
219+
},
220+
"custom": {
221+
"type": "object",
222+
"description": "Area for user-defined custom properties that won't trigger validation warnings",
223+
"additionalProperties": true
224+
}
225+
},
226+
"additionalProperties": true
227+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
* CDK Configuration Schema
3+
*
4+
* This module exports the JSON Schema for cdk.json configuration files
5+
* for use by external tooling.
6+
*/
7+
8+
import * as fs from 'fs';
9+
import * as path from 'path';
10+
11+
/**
12+
* The JSON Schema for CDK configuration files
13+
*/
14+
export const cdkConfigSchema = JSON.parse(
15+
fs.readFileSync(path.join(__dirname, 'cdk-config.schema.json'), 'utf8')
16+
);

0 commit comments

Comments
 (0)