Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .projenrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,7 @@ const cli = configureProject(
'wrap-ansi@^7', // Last non-ESM version
'yaml@^1',
'yargs@^15',
'jsonschema',
],
tsconfig: {
compilerOptions: {
Expand Down
56 changes: 56 additions & 0 deletions packages/aws-cdk/lib/cli/user-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import * as os from 'os';
import * as fs_path from 'path';
import { ToolkitError } from '@aws-cdk/toolkit-lib';
import * as fs from 'fs-extra';
import { validate } from 'jsonschema';
import { Context, PROJECT_CONTEXT } from '../api/context';
import { Settings } from '../api/settings';
import type { Tag } from '../api/tags';
import type { IoHelper } from '../api-private';
import { cdkConfigSchema } from '../schema';

export const PROJECT_CONFIG = 'cdk.json';
export { PROJECT_CONTEXT } from '../api/context';
Expand Down Expand Up @@ -210,6 +212,9 @@ async function settingsFromFile(ioHelper: IoHelper, fileName: string): Promise<S
const expanded = expandHomeDir(fileName);
if (await fs.pathExists(expanded)) {
const data = await fs.readJson(expanded);

await validateConfigurationFile(data, fileName, ioHelper);

settings = new Settings(data);
} else {
settings = new Settings();
Expand Down Expand Up @@ -408,3 +413,54 @@ async function parseStringTagsListToObject(
}
return tags.length > 0 ? tags : undefined;
}

/**
* Validates configuration data against the CDK JSON Schema
*
* @param data - The configuration object to validate
* @param fileName - The file name for error reporting
* @param ioHelper - IoHelper for logging warnings
*/
async function validateConfigurationFile(data: any, fileName: string, ioHelper: IoHelper): Promise<void> {
try {
const schema = cdkConfigSchema;

// Validate configuration against jsonschema, log warnings
const result = validate(data, schema);

if (result.errors && result.errors.length > 0) {
for (const error of result.errors) {
const propertyPath = error.property ? error.property.replace('instance.', '') : 'root';

// Provide warning messages
if (error.name === 'additionalProperties') {
await ioHelper.defaults.warning(
`Unknown property '${error.argument}' in ${fileName}. This property is not recognized by the CDK CLI.`
);
} else {
await ioHelper.defaults.warning(
`Configuration validation warning in ${fileName}: ${error.message} at '${propertyPath}'`
);
}
}
}

// Custom validation for unknown properties
if (data && typeof data === 'object' && !Array.isArray(data)) {
const knownProperties = Object.keys(schema.properties || {});
const configProperties = Object.keys(data);
const unknownProperties = configProperties.filter(prop => !knownProperties.includes(prop));

if (unknownProperties.length > 0) {
for (const prop of unknownProperties) {
await ioHelper.defaults.warning(
`Unknown configuration property '${prop}' in ${fileName}. This property will be preserved but may not be recognized by CDK. ` +
`Check for typos in property names.`
);
}
}
}
} catch (error) {
await ioHelper.defaults.debug(`Schema validation failed for ${fileName}: ${error}`);
}
}
227 changes: 227 additions & 0 deletions packages/aws-cdk/lib/schema/cdk-config.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/aws/aws-cdk-cli/main/packages/aws-cdk/lib/schema/cdk-config.schema.json",
"title": "CDK Configuration",
"description": "Schema for cdk.json configuration files used by the AWS CDK CLI",
"type": "object",
"properties": {
"app": {
"type": "string",
"description": "The command that executes the CDK application"
},
"build": {
"type": "string",
"description": "The command that compiles or builds the CDK application before synthesis (not permitted in ~/.cdk.json)"
},
"language": {
"type": "string",
"description": "The language to be used for initializing new projects",
"enum": ["typescript", "javascript", "python", "java", "csharp", "go", "fsharp"]
},
"output": {
"type": "string",
"default": "cdk.out",
"description": "The name of the directory into which the synthesized cloud assembly will be emitted"
},
"outputsFile": {
"type": "string",
"description": "The file to which AWS CloudFormation outputs from deployed stacks will be written (in JSON format)"
},
"profile": {
"type": "string",
"description": "Name of the default AWS profile used for specifying Region and account credentials"
},
"toolkitStackName": {
"type": "string",
"description": "The name of the bootstrap stack"
},
"toolkitBucketName": {
"type": "string",
"description": "The name of the Amazon S3 bucket used for deploying assets such as Lambda functions and container images"
},
"bootstrapKmsKeyId": {
"type": "string",
"description": "Overrides the ID of the AWS KMS key used to encrypt the Amazon S3 deployment bucket"
},
"requireApproval": {
"type": "string",
"description": "Default approval level for security changes",
"enum": ["never", "any-change", "broadening"]
},
"assetMetadata": {
"type": "boolean",
"default": true,
"description": "If false, CDK does not add metadata to resources that use assets"
},
"pathMetadata": {
"type": "boolean",
"default": true,
"description": "If false, CDK path metadata is not added to synthesized templates"
},
"notices": {
"type": "boolean",
"description": "If false, suppresses the display of messages about security vulnerabilities, regressions, and unsupported versions"
},
"versionReporting": {
"type": "boolean",
"default": true,
"description": "If false, opts out of version reporting"
},
"debug": {
"type": "boolean",
"description": "If true, CDK CLI emits more detailed information useful for debugging"
},
"staging": {
"type": "boolean",
"description": "If false, assets are not copied to the output directory"
},
"lookups": {
"type": "boolean",
"description": "If false, no context lookups are permitted"
},
"rollback": {
"type": "boolean",
"description": "If false, failed deployments are not rolled back"
},
"progress": {
"type": "string",
"description": "If set to 'events', the CDK CLI displays all AWS CloudFormation events during deployment, rather than a progress bar",
"enum": ["bar", "events"]
},
"browser": {
"type": "string",
"description": "The command for launching a Web browser for the cdk docs subcommand"
},
"context": {
"type": "object",
"description": "Context values and feature flags (values in configuration file will not be erased by cdk context --clear)",
"additionalProperties": true
},
"plugin": {
"type": "array",
"items": {
"type": "string"
},
"description": "JSON array specifying the package names or local paths of packages that extend the CDK"
},
"tags": {
"type": "array",
"items": {
"type": "object",
"properties": {
"Key": {
"type": "string"
},
"Value": {
"type": "string"
}
},
"required": ["Key", "Value"],
"additionalProperties": false
},
"description": "JSON array containing tags (key-value pairs) for the stack"
},
"watch": {
"type": "object",
"properties": {
"include": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "Files or directories that should trigger a rebuild when changed"
},
"exclude": {
"oneOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "Files or directories that should not trigger a rebuild when changed"
}
},
"additionalProperties": false,
"description": "Configuration for watch mode file monitoring"
},
"proxy": {
"type": "string",
"description": "Proxy server URL for HTTP requests"
},
"caBundlePath": {
"type": "string",
"description": "Path to CA certificate bundle for HTTPS requests"
},
"assetParallelism": {
"type": "integer",
"minimum": 1,
"description": "Number of parallel asset uploads"
},
"assetPrebuild": {
"type": "boolean",
"description": "Whether to prebuild all assets before deployment"
},
"ignoreNoStacks": {
"type": "boolean",
"description": "Whether to ignore the error when no stacks are selected"
},
"hotswap": {
"type": "object",
"properties": {
"ecs": {
"type": "object",
"properties": {
"minimumHealthyPercent": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"description": "Minimum healthy percent for ECS hotswap deployments"
},
"maximumHealthyPercent": {
"type": "integer",
"minimum": 100,
"description": "Maximum healthy percent for ECS hotswap deployments"
},
"stabilizationTimeoutSeconds": {
"type": "integer",
"minimum": 0,
"description": "Stabilization timeout in seconds for ECS hotswap deployments"
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"description": "Configuration for hotswap deployments"
},
"unstable": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of unstable features to enable"
},
"quiet": {
"type": "boolean",
"description": "Suppress output during synthesis"
},
"custom": {
"type": "object",
"description": "Area for user-defined custom properties that won't trigger validation warnings",
"additionalProperties": true
}
},
"additionalProperties": true
}
16 changes: 16 additions & 0 deletions packages/aws-cdk/lib/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* CDK Configuration Schema
*
* This module exports the JSON Schema for cdk.json configuration files
* for use by external tooling.
*/

import * as fs from 'fs';
import * as path from 'path';

/**
* The JSON Schema for CDK configuration files
*/
export const cdkConfigSchema = JSON.parse(
fs.readFileSync(path.join(__dirname, 'cdk-config.schema.json'), 'utf8')
);
Loading