Skip to content
Merged
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
72 changes: 67 additions & 5 deletions packages/@aws-cdk/mixins-preview/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,13 @@ distribution

## EventBridge Event Patterns

CDK Mixins automatically generates typed EventBridge event patterns for AWS resources. These patterns work with both L1 and L2 constructs, providing a consistent interface for creating EventBridge rules.
CDK Mixins automatically generates typed EventBridge event patterns for AWS resources. These patterns come in two flavors: **resource-specific** and **standalone**.

### Event Patterns Basic Usage
### Resource-Specific Event Patterns

Resource-specific patterns are created by attaching a resource reference (e.g. an S3 bucket). The resource identifier is automatically injected into the event pattern, so calling a pattern method with no arguments still filters events to that specific resource. For example, an S3 `objectCreatedPattern()` will automatically include the bucket name in the pattern, meaning it only matches events from that particular bucket.

#### Event Patterns Basic Usage

```typescript
import { BucketEvents } from '@aws-cdk/mixins-preview/aws-s3/events';
Expand Down Expand Up @@ -182,9 +186,7 @@ new events.CfnRule(scope, 'CfnRule', {
});
```

### Event Pattern Features

**Automatic Resource Injection**: Resource identifiers are automatically included in patterns
#### Event Pattern Features

```typescript
import { BucketEvents } from '@aws-cdk/mixins-preview/aws-s3/events';
Expand Down Expand Up @@ -212,6 +214,62 @@ const pattern = bucketEvents.objectCreatedPattern({
});
```

### Standalone Event Patterns

Standalone patterns are not tied to any specific resource. They match events across all resources of that type. For example, a standalone `awsAPICallViaCloudTrailPattern()` will match CloudTrail API calls for all S3 buckets in the account, not just a specific one.

#### Event Patterns Basic Usage

```typescript
import { AWSAPICallViaCloudTrail, ObjectCreated, ObjectDeleted } from '@aws-cdk/mixins-preview/aws-s3/events';
import * as events from 'aws-cdk-lib/aws-events';
import * as targets from 'aws-cdk-lib/aws-events-targets';

declare const fn: lambda.Function;

// Works with L2 Rule
new events.Rule(scope, 'Rule', {
eventPattern: AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern({
tlsDetails: { tlsVersion: ['TLSv1.3'] },
eventMetadata: { region: ['us-east-1'] },
}),
targets: [new targets.LambdaFunction(fn)]
});

// Also works with L1 CfnRule
new events.CfnRule(scope, 'CfnRule', {
state: 'ENABLED',
eventPattern: AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern({
tlsDetails: { tlsVersion: ['TLSv1.3'] },
eventMetadata: { region: ['us-east-1'] },
}),
targets: [{ arn: fn.functionArn, id: 'L1' }]
});
```

#### Event Pattern Features

```typescript
import { AWSAPICallViaCloudTrail } from '@aws-cdk/mixins-preview/aws-s3/events';

// Matches CloudTrail API calls across ALL S3 buckets
const pattern = AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern();
```

**Event Metadata Support**: Control EventBridge pattern metadata

```typescript
import { AWSAPICallViaCloudTrail } from '@aws-cdk/mixins-preview/aws-s3/events';
import * as events from 'aws-cdk-lib/aws-events';

const pattern = AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern({
eventMetadata: {
region: events.Match.prefix('us-'),
version: ['0']
}
});
```

### Available Events

Event patterns are generated for EventBridge events available in the AWS Event Schema Registry. Common examples:
Expand All @@ -226,5 +284,9 @@ Event patterns are generated for EventBridge events available in the AWS Event S
Import events from service-specific modules:

```typescript
// Resource-specific (filters to a specific bucket)
import { BucketEvents } from '@aws-cdk/mixins-preview/aws-s3/events';

// Standalone (matches across all buckets)
import { AWSAPICallViaCloudTrail, ObjectCreated, ObjectDeleted } from '@aws-cdk/mixins-preview/aws-s3/events';
```
144 changes: 144 additions & 0 deletions packages/@aws-cdk/mixins-preview/test/events/aws-s3/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Stack } from 'aws-cdk-lib';
import { CfnRule, Rule } from 'aws-cdk-lib/aws-events';
import { Template } from 'aws-cdk-lib/assertions';
import { AWSAPICallViaCloudTrail, ObjectCreated, ObjectDeleted } from '../../../lib/services/aws-s3/events.generated';

describe('with L2 Rule', () => {
let stack: Stack;
beforeEach(() => {
stack = new Stack();
});

test('awsAPICallViaCloudTrailPattern with tlsDetails and eventMetadata', () => {
new Rule(stack, 'Rule', {
eventPattern: AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern({
tlsDetails: { tlsVersion: ['TLSv1.3'] },
eventMetadata: { region: ['us-east-1'] },
}),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['AWS API Call via CloudTrail'],
'source': ['aws.s3'],
'detail': {
tlsDetails: { tlsVersion: ['TLSv1.3'] },
},
'region': ['us-east-1'],
},
});
});

test('awsAPICallViaCloudTrailPattern bare call', () => {
new Rule(stack, 'Rule', {
eventPattern: AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern(),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['AWS API Call via CloudTrail'],
'source': ['aws.s3'],
},
});
});

test('objectCreatedPattern with reason filter', () => {
new Rule(stack, 'Rule', {
eventPattern: ObjectCreated.objectCreatedPattern({ reason: ['PutObject'] }),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['Object Created'],
'source': ['aws.s3'],
'detail': { reason: ['PutObject'] },
},
});
});

test('objectDeletedPattern with reason filter', () => {
new Rule(stack, 'Rule', {
eventPattern: ObjectDeleted.objectDeletedPattern({ reason: ['DeleteObject'] }),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['Object Deleted'],
'source': ['aws.s3'],
'detail': { reason: ['DeleteObject'] },
},
});
});
});

describe('with L1 CfnRule', () => {
let stack: Stack;
beforeEach(() => {
stack = new Stack();
});

test('awsAPICallViaCloudTrailPattern with tlsDetails and eventMetadata', () => {
new CfnRule(stack, 'Rule', {
state: 'ENABLED',
eventPattern: AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern({
tlsDetails: { tlsVersion: ['TLSv1.3'] },
eventMetadata: { region: ['us-east-1'] },
}),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['AWS API Call via CloudTrail'],
'source': ['aws.s3'],
'detail': {
tlsDetails: { tlsVersion: ['TLSv1.3'] },
},
'region': ['us-east-1'],
},
});
});

test('awsAPICallViaCloudTrailPattern bare call', () => {
new CfnRule(stack, 'Rule', {
state: 'ENABLED',
eventPattern: AWSAPICallViaCloudTrail.awsAPICallViaCloudTrailPattern(),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['AWS API Call via CloudTrail'],
'source': ['aws.s3'],
},
});
});

test('objectCreatedPattern with reason filter', () => {
new CfnRule(stack, 'Rule', {
state: 'ENABLED',
eventPattern: ObjectCreated.objectCreatedPattern({ reason: ['PutObject'] }),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['Object Created'],
'source': ['aws.s3'],
'detail': { reason: ['PutObject'] },
},
});
});

test('objectDeletedPattern with reason filter', () => {
new CfnRule(stack, 'Rule', {
state: 'ENABLED',
eventPattern: ObjectDeleted.objectDeletedPattern({ reason: ['DeleteObject'] }),
});

Template.fromStack(stack).hasResourceProperties('AWS::Events::Rule', {
EventPattern: {
'detail-type': ['Object Deleted'],
'source': ['aws.s3'],
'detail': { reason: ['DeleteObject'] },
},
});
});
});
2 changes: 1 addition & 1 deletion tools/@aws-cdk/cdk-build-tools/config/markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"no-multiple-space-atx": true,
"blanks-around-headings": true,
"heading-start-left": true,
"no-duplicate-heading": true,
"no-duplicate-heading": { "siblings_only": true },
"single-title": true,
"no-trailing-punctuation": true,
"no-multiple-space-blockquote": true,
Expand Down
Loading