diff --git a/packages/aws-cdk-lib/aws-events/lib/rule.ts b/packages/aws-cdk-lib/aws-events/lib/rule.ts index 29a952bc4075f..68f6a2da27b44 100644 --- a/packages/aws-cdk-lib/aws-events/lib/rule.ts +++ b/packages/aws-cdk-lib/aws-events/lib/rule.ts @@ -295,11 +295,23 @@ export class Rule extends Resource implements IRule { } protected validateRule() { + const errors: string[] = []; + + const name = this.physicalName; + if (name !== undefined && !Token.isUnresolved(name)) { + if (name.length < 1 || name.length > 64) { + errors.push(`Event rule name must be between 1 and 64 characters. Received: ${name}`); + } + if (!/^[\.\-_A-Za-z0-9]+$/.test(name)) { + errors.push(`Event rule name ${name} can contain only letters, numbers, periods, hyphens, or underscores with no spaces.`); + } + } + if (Object.keys(this.eventPattern).length === 0 && !this.scheduleExpression) { - return ['Either \'eventPattern\' or \'schedule\' must be defined']; + errors.push('Either \'eventPattern\' or \'schedule\' must be defined'); } - return []; + return errors; } private renderTargets() { diff --git a/packages/aws-cdk-lib/aws-events/test/rule.test.ts b/packages/aws-cdk-lib/aws-events/test/rule.test.ts index ffc61ecf3112b..2260ed73a8ae0 100644 --- a/packages/aws-cdk-lib/aws-events/test/rule.test.ts +++ b/packages/aws-cdk-lib/aws-events/test/rule.test.ts @@ -203,6 +203,38 @@ describe('rule', () => { expect(() => app.synth()).toThrow(/Either 'eventPattern' or 'schedule' must be defined/); }); + test('fails synthesis when rule name is less than 1 chars', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'MyStack'); + new Rule(stack, 'Rule', { + ruleName: '', + schedule: Schedule.rate(cdk.Duration.minutes(10)), + }); + expect(() => app.synth()).toThrow(/Event rule name must be between 1 and 64 characters./); + }); + + test('fails synthesis when rule name is longer than 64 chars', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'MyStack'); + new Rule(stack, 'Rule', { + ruleName: 'a'.repeat(65), + schedule: Schedule.rate(cdk.Duration.minutes(10)), + }); + expect(() => app.synth()).toThrow(/Event rule name must be between 1 and 64 characters./); + }); + + test('fails synthesis when rule name contains invalid characters', () => { + const app = new cdk.App(); + const stack = new cdk.Stack(app, 'MyStack'); + [' ', '\n', '\r', '[', ']', '<', '>', '$'].forEach(invalidChar => { + new Rule(stack, `Rule${invalidChar}`, { + ruleName: `Rule${invalidChar}`, + schedule: Schedule.rate(cdk.Duration.minutes(10)), + }); + expect(() => app.synth()).toThrow(/can contain only letters, numbers, periods, hyphens, or underscores with no spaces./); + }); + }); + test('addEventPattern can be used to add filters', () => { const stack = new cdk.Stack();