rds-database-auto-start-preventer 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.editorconfig ADDED
@@ -0,0 +1,12 @@
1
+ # ~~ Generated by projen. To modify, edit .projenrc.ts and run "npx projen".
2
+
3
+ root=true
4
+
5
+ [*]
6
+ end_of_line=lf
7
+ charset=utf-8
8
+
9
+ [*\.{js,ts}]
10
+ indent_style=space
11
+ indent_size=2
12
+ max_line_length=120
package/.jsii CHANGED
@@ -8459,7 +8459,7 @@
8459
8459
  },
8460
8460
  "name": "rds-database-auto-start-preventer",
8461
8461
  "readme": {
8462
- "markdown": "# RDS Database Auto Start Preventer (AWS CDK v2)\n\n[![GitHub](https://img.shields.io/github/license/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer?style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/blob/main/LICENSE)\n[![npm](https://img.shields.io/npm/v/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)\n[![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/release.yml?branch=main&label=release&style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/actions/workflows/release.yml)\n[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer?sort=semver&style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/releases)\n\n[![View on Construct Hub](https://constructs.dev/badge?package=rds-database-auto-start-preventer)](https://constructs.dev/packages/rds-database-auto-start-preventer)\n\nCDK construct library that stops RDS DB instances and clusters after they are auto-started by AWS (RDS-EVENT-0154 / RDS-EVENT-0153). It uses EventBridge rules and a Durable Lambda to detect auto-start events, filter resources by tags in the handler, stop matching resources when they are `available`, and post a Slack notification only when this Lambda invoked the stop API successfully.\n\n## Features\n\n- **EventBridge integration** – Listens for RDS DB Instance (RDS-EVENT-0154) and DB Cluster (RDS-EVENT-0153) auto-start events\n- **Handler-side tag filtering** – EventBridge rules match all auto-start events; the Lambda evaluates `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters` and skips resources that do not match `tagKey` / `tagValues`\n- **Durable Lambda** – Uses AWS Lambda Durable Execution for reliable, long-running workflow (initial wait, status wait, stop, and post-stop wait)\n- **Least-privilege IAM** – Grants RDS describe and stop actions only (no Resource Groups Tagging API)\n- **Slack notifications** – Sends a message when this invocation called `StopDBInstance` / `StopDBCluster` and the resource reached `stopped` (no notification when the resource was already stopped or tags did not match)\n- **Optional rule toggle** – EventBridge rules can be enabled or disabled via `enableRule`\n\n## Installation\n\n**npm**\n\n```bash\nnpm install rds-database-auto-start-preventer\n```\n\n**yarn**\n\n```bash\nyarn add rds-database-auto-start-preventer\n```\n\n## Usage\n\n### How it works\n\n1. EventBridge invokes the Durable Lambda with the RDS auto-start event and tag filter parameters (`tagKey`, `tagValues`).\n2. The handler waits 1 minute, then waits on DescribeDB* until the resource leaves transitional statuses.\n3. If the resource tag does not match, the handler exits with no stop action.\n4. If the resource is `available` and tags match, the handler calls StopDB* and waits until `stopped`.\n5. If the resource is already `stopped` (for example, stopped by another process), the handler exits without calling StopDB* and without posting to Slack.\n6. Slack is notified only when StopDB* was invoked by this invocation and the resource reached `stopped`.\n\nTag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running.\n\n### Construct\n\nUse `RDSDatabaseAutoStartPreventer` when you want to add auto-start prevention to an existing stack or compose it with other constructs.\n\n```typescript\nimport { Stack } from 'aws-cdk-lib';\nimport { RDSDatabaseAutoStartPreventer } from 'rds-database-auto-start-preventer';\n\nconst stack = new Stack(app, 'MyStack');\n\nnew RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {\n targetResource: {\n tagKey: 'AutoStartPrevent',\n tagValues: ['YES'],\n },\n enableRule: true, // optional, defaults to true\n secrets: {\n slackSecretName: 'my-app/slack',\n },\n});\n```\n\n### Stack\n\nUse `RDSDatabaseAutoStartPreventStack` when you want a dedicated stack that only deploys the RDS auto-start prevent resources.\n\n```typescript\nimport { RDSDatabaseAutoStartPreventStack } from 'rds-database-auto-start-preventer';\n\nnew RDSDatabaseAutoStartPreventStack(app, 'RDSDatabaseAutoStartPreventStack', {\n stackName: 'rds-database-auto-start-prevent',\n targetResource: {\n tagKey: 'AutoStartPrevent',\n tagValues: ['YES'],\n },\n enableRule: true, // optional, defaults to true\n secrets: {\n slackSecretName: 'my-app/slack',\n },\n});\n```\n\n### Slack secret (AWS Secrets Manager)\n\nStore a JSON object in AWS Secrets Manager with the Slack Bot Token and channel ID:\n\n| Key | Value |\n|-----|-------|\n| `token` | Slack Bot Token (e.g. `xoxb-...`) |\n| `channel` | Slack channel ID (e.g. `C01234ABCD`) |\n\nExample secret value:\n\n```json\n{\n \"token\": \"xoxb-...\",\n \"channel\": \"C01234ABCD\"\n}\n```\n\n## Options\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `targetResource` | `TargetResource` | Yes | Tag-based criteria evaluated in the Lambda handler. |\n| `targetResource.tagKey` | `string` | Yes | Tag key to match (e.g. `AutoStartPrevent`, `Environment`). |\n| `targetResource.tagValues` | `string[]` | Yes | Tag values that indicate the resource should be stopped (e.g. `['YES']`, `['production']`). |\n| `enableRule` | `boolean` | No | Whether the EventBridge rules are enabled. Defaults to `true` if omitted. |\n| `secrets` | `Secrets` | Yes | External secrets for notifications. |\n| `secrets.slackSecretName` | `string` | Yes | Name of the Secrets Manager secret containing Slack `token` and `channel`. |\n\n## Requirements\n\n- **Node.js** >= 20.0.0 (for your CDK app)\n- **AWS CDK** ^2.232.0\n- **constructs** ^10.5.1\n- **AWS Lambda** runtime Node.js 24.x with Durable Execution (deployed by the construct)\n\n## License\n\nThis project is licensed under the Apache-2.0 License.\n"
8462
+ "markdown": "# RDS Database Auto Start Preventer (CDK v2)\n\n[![npm version](https://img.shields.io/npm/v/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)\n[![license](https://img.shields.io/npm/l/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)\n[![Node.js](https://img.shields.io/node/v/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)\n[![build](https://img.shields.io/github/actions/workflow/status/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/build.yml?label=build&style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/actions/workflows/build.yml)\n\n[![View on Construct Hub](https://constructs.dev/badge?package=rds-database-auto-start-preventer)](https://constructs.dev/packages/rds-database-auto-start-preventer)\n\nCDK construct library that stops RDS DB instances and clusters after they are auto-started by AWS (RDS-EVENT-0154 / RDS-EVENT-0153). It uses EventBridge rules and a Durable Lambda to detect auto-start events, filter resources by tags in the handler, stop matching resources when they are `available`, and post a Slack notification only when this Lambda invoked the stop API successfully and a Slack secret name is set.\n\n## Features\n\n- **EventBridge integration** – Listens for RDS DB Instance (RDS-EVENT-0154) and DB Cluster (RDS-EVENT-0153) auto-start events\n- **Handler-side tag filtering** – EventBridge rules match all auto-start events; the Lambda evaluates `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters` and skips resources that do not match `tagKey` / `tagValues`\n- **Durable Lambda** – Uses AWS Lambda Durable Execution for reliable, long-running workflow (initial wait, status wait, stop, and post-stop wait)\n- **Least-privilege IAM** – Grants RDS describe and stop actions only (no Resource Groups Tagging API)\n- **Slack notifications** – When `slackSecretName` is set, sends a message when this invocation called `StopDBInstance` / `StopDBCluster` and the resource reached `stopped` (no notification when the secret name is omitted, the resource was already stopped, or tags did not match)\n- **Optional rule toggle** – EventBridge rules can be enabled or disabled via `enableRule`\n\n## How it works\n\n1. EventBridge invokes the Durable Lambda with the RDS auto-start event and tag filter parameters (`tagKey`, `tagValues`).\n2. The handler waits 1 minute, then waits on DescribeDB* until the resource leaves transitional statuses.\n3. If the resource tag does not match, the handler exits with no stop action.\n4. If the resource is `available` and tags match, the handler calls StopDB* and waits until `stopped`.\n5. If the resource is already `stopped` (for example, stopped by another process), the handler exits without calling StopDB* and without posting to Slack.\n6. When `slackSecretName` is set, Slack is notified only when StopDB* was invoked by this invocation and the resource reached `stopped`. When it is omitted, the handler does not post to Slack.\n\nTag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running.\n\n## Installation\n\n### npm\n\n```bash\nnpm install rds-database-auto-start-preventer\n```\n\n### yarn\n\n```bash\nyarn add rds-database-auto-start-preventer\n```\n\n### pnpm\n\n```bash\npnpm add rds-database-auto-start-preventer\n```\n\n## Usage\n\nUse `RDSDatabaseAutoStartPreventer` when you want to add auto-start prevention to an existing stack or compose it with other constructs. Omit `slackSecretName` to stop matching resources without Slack.\n\n```typescript\nimport { App, Stack } from 'aws-cdk-lib';\nimport { RDSDatabaseAutoStartPreventer } from 'rds-database-auto-start-preventer';\n\nconst app = new App();\nconst stack = new Stack(app, 'MyStack');\n\nnew RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {\n targetResource: {\n tagKey: 'AutoStartPrevent',\n tagValues: ['YES'],\n },\n secrets: {},\n});\n```\n\nPass `slackSecretName` when a successful stop should post to Slack. `enableRule` defaults to `true`.\n\n```typescript\nnew RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {\n targetResource: {\n tagKey: 'AutoStartPrevent',\n tagValues: ['YES'],\n },\n enableRule: true,\n secrets: {\n slackSecretName: 'my-app/slack',\n },\n});\n```\n\n### Stack\n\nUse `RDSDatabaseAutoStartPreventStack` when you want a dedicated stack that only deploys the RDS auto-start prevent resources.\n\n```typescript\nimport { App } from 'aws-cdk-lib';\nimport { RDSDatabaseAutoStartPreventStack } from 'rds-database-auto-start-preventer';\n\nconst app = new App();\n\nnew RDSDatabaseAutoStartPreventStack(app, 'RDSDatabaseAutoStartPreventStack', {\n stackName: 'rds-database-auto-start-prevent',\n targetResource: {\n tagKey: 'AutoStartPrevent',\n tagValues: ['YES'],\n },\n secrets: {\n slackSecretName: 'my-app/slack',\n },\n});\n```\n\n### Slack secret (AWS Secrets Manager)\n\nStore a JSON object in AWS Secrets Manager with the Slack Bot Token and channel ID:\n\n| Key | Value |\n|-----|-------|\n| `token` | Slack Bot Token (e.g. `xoxb-...`) |\n| `channel` | Slack channel ID (e.g. `C01234ABCD`) |\n\nExample secret value:\n\n```json\n{\n \"token\": \"xoxb-...\",\n \"channel\": \"C01234ABCD\"\n}\n```\n\n## Options\n\n| Option | Type | Required | Description |\n|--------|------|----------|-------------|\n| `targetResource` | `TargetResource` | Yes | Tag-based criteria evaluated in the Lambda handler. |\n| `targetResource.tagKey` | `string` | Yes | Tag key to match (e.g. `AutoStartPrevent`, `Environment`). |\n| `targetResource.tagValues` | `string[]` | Yes | Tag values that indicate the resource should be stopped (e.g. `['YES']`, `['production']`). |\n| `enableRule` | `boolean` | No | Whether the EventBridge rules are enabled. Defaults to `true` if omitted. |\n| `secrets` | `Secrets` | Yes | External secrets for notifications. |\n| `secrets.slackSecretName` | `string` | No | Name of the Secrets Manager secret containing Slack `token` and `channel`. Omit it to skip Slack notifications. |\n\nEmpty `tagKey`, an empty `tagValues` array (or blank entries), and a blank `slackSecretName` fail at synthesis. Omitting `slackSecretName` is allowed. Unresolved CDK tokens are not checked.\n\n## API\n\nSee [API.md](./API.md).\n\n## Requirements\n\n- **Node.js** >= 20.0.0 (for your CDK app)\n- **AWS CDK** ^2.232.0\n- **constructs** ^10.5.1\n- **AWS Lambda** runtime Node.js 24.x with Durable Execution (deployed by the construct)\n\n## License\n\nThis project is licensed under the Apache-2.0 License.\n"
8463
8463
  },
8464
8464
  "repository": {
8465
8465
  "type": "git",
@@ -8548,8 +8548,9 @@
8548
8548
  {
8549
8549
  "abstract": true,
8550
8550
  "docs": {
8551
+ "remarks": "Omit slackSecretName to skip Slack.",
8551
8552
  "stability": "stable",
8552
- "summary": "Secrets (e.g. Slack) for notifications."
8553
+ "summary": "Secrets for notifications."
8553
8554
  },
8554
8555
  "immutable": true,
8555
8556
  "locationInModule": {
@@ -8609,13 +8610,16 @@
8609
8610
  "fqn": "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventer",
8610
8611
  "initializer": {
8611
8612
  "docs": {
8613
+ "custom": {
8614
+ "throws": "When tagKey or a tag value is blank, tagValues is empty, or slackSecretName is present but blank."
8615
+ },
8612
8616
  "remarks": "The Lambda receives `{ event, params }` where `params` carries `tagKey` and `tagValues`\nfrom {@link RDSDatabaseAutoStartPreventerProps.targetResource}. Tag filters are passed\nonly via that payload (not via `TAG_KEY` / `TAG_VALUES` environment variables).",
8613
8617
  "stability": "stable",
8614
8618
  "summary": "Creates the Durable Lambda, EventBridge rules, and IAM policies."
8615
8619
  },
8616
8620
  "locationInModule": {
8617
8621
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8618
- "line": 64
8622
+ "line": 103
8619
8623
  },
8620
8624
  "parameters": [
8621
8625
  {
@@ -8650,7 +8654,7 @@
8650
8654
  "kind": "class",
8651
8655
  "locationInModule": {
8652
8656
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8653
- "line": 51
8657
+ "line": 89
8654
8658
  },
8655
8659
  "name": "RDSDatabaseAutoStartPreventer",
8656
8660
  "symbolId": "src/constructs/rds-database-auto-start-preventer:RDSDatabaseAutoStartPreventer"
@@ -8666,7 +8670,7 @@
8666
8670
  "kind": "interface",
8667
8671
  "locationInModule": {
8668
8672
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8669
- "line": 34
8673
+ "line": 38
8670
8674
  },
8671
8675
  "name": "RDSDatabaseAutoStartPreventerProps",
8672
8676
  "properties": [
@@ -8679,7 +8683,7 @@
8679
8683
  "immutable": true,
8680
8684
  "locationInModule": {
8681
8685
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8682
- "line": 40
8686
+ "line": 44
8683
8687
  },
8684
8688
  "name": "secrets",
8685
8689
  "type": {
@@ -8695,7 +8699,7 @@
8695
8699
  "immutable": true,
8696
8700
  "locationInModule": {
8697
8701
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8698
- "line": 36
8702
+ "line": 40
8699
8703
  },
8700
8704
  "name": "targetResource",
8701
8705
  "type": {
@@ -8712,7 +8716,7 @@
8712
8716
  "immutable": true,
8713
8717
  "locationInModule": {
8714
8718
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8715
- "line": 38
8719
+ "line": 42
8716
8720
  },
8717
8721
  "name": "enableRule",
8718
8722
  "optional": true,
@@ -8728,28 +8732,30 @@
8728
8732
  "datatype": true,
8729
8733
  "docs": {
8730
8734
  "stability": "stable",
8731
- "summary": "External secrets required for notifications (e.g. Slack)."
8735
+ "summary": "External secrets for notifications (e.g. Slack). Omit {@link Secrets.slackSecretName} to skip Slack notifications."
8732
8736
  },
8733
8737
  "fqn": "rds-database-auto-start-preventer.Secrets",
8734
8738
  "kind": "interface",
8735
8739
  "locationInModule": {
8736
8740
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8737
- "line": 26
8741
+ "line": 27
8738
8742
  },
8739
8743
  "name": "Secrets",
8740
8744
  "properties": [
8741
8745
  {
8742
8746
  "abstract": true,
8743
8747
  "docs": {
8748
+ "remarks": "When omitted, the handler stops matching RDS resources and does not post to Slack.",
8744
8749
  "stability": "stable",
8745
8750
  "summary": "Name of the Secrets Manager secret containing Slack token and channel."
8746
8751
  },
8747
8752
  "immutable": true,
8748
8753
  "locationInModule": {
8749
8754
  "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8750
- "line": 28
8755
+ "line": 32
8751
8756
  },
8752
8757
  "name": "slackSecretName",
8758
+ "optional": true,
8753
8759
  "type": {
8754
8760
  "primitive": "string"
8755
8761
  }
@@ -8814,6 +8820,6 @@
8814
8820
  "symbolId": "src/constructs/rds-database-auto-start-preventer:TargetResource"
8815
8821
  }
8816
8822
  },
8817
- "version": "0.3.6",
8818
- "fingerprint": "CpZgka4XwfgWfTHcmJD29ZpROZIm2u/1nLwewv8oTqU="
8823
+ "version": "0.4.0",
8824
+ "fingerprint": "lHihG95VC2qiyCGzTr9eHerH7bSCZZVie3gc1cHgtN8="
8819
8825
  }
package/API.md CHANGED
@@ -1196,7 +1196,7 @@ const rDSDatabaseAutoStartPreventStackProps: RDSDatabaseAutoStartPreventStackPro
1196
1196
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.synthesizer">synthesizer</a></code> | <code>aws-cdk-lib.IStackSynthesizer</code> | Synthesis method to use while deploying this stack. |
1197
1197
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.tags">tags</a></code> | <code>{[ key: string ]: string}</code> | Tags that will be applied to the Stack. |
1198
1198
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.terminationProtection">terminationProtection</a></code> | <code>boolean</code> | Whether to enable termination protection for this stack. |
1199
- | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.secrets">secrets</a></code> | <code><a href="#rds-database-auto-start-preventer.Secrets">Secrets</a></code> | Secrets (e.g. Slack) for notifications. |
1199
+ | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.secrets">secrets</a></code> | <code><a href="#rds-database-auto-start-preventer.Secrets">Secrets</a></code> | Secrets for notifications. |
1200
1200
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.targetResource">targetResource</a></code> | <code><a href="#rds-database-auto-start-preventer.TargetResource">TargetResource</a></code> | Tag-based target resource criteria for RDS instances/clusters to protect. |
1201
1201
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.enableRule">enableRule</a></code> | <code>boolean</code> | Whether the EventBridge rules are enabled. |
1202
1202
 
@@ -1454,7 +1454,9 @@ public readonly secrets: Secrets;
1454
1454
 
1455
1455
  - *Type:* <a href="#rds-database-auto-start-preventer.Secrets">Secrets</a>
1456
1456
 
1457
- Secrets (e.g. Slack) for notifications.
1457
+ Secrets for notifications.
1458
+
1459
+ Omit slackSecretName to skip Slack.
1458
1460
 
1459
1461
  ---
1460
1462
 
@@ -1486,7 +1488,7 @@ Defaults to true if omitted.
1486
1488
 
1487
1489
  ### Secrets <a name="Secrets" id="rds-database-auto-start-preventer.Secrets"></a>
1488
1490
 
1489
- External secrets required for notifications (e.g. Slack).
1491
+ External secrets for notifications (e.g. Slack). Omit {@link Secrets.slackSecretName} to skip Slack notifications.
1490
1492
 
1491
1493
  #### Initializer <a name="Initializer" id="rds-database-auto-start-preventer.Secrets.Initializer"></a>
1492
1494
 
@@ -1504,7 +1506,7 @@ const secrets: Secrets = { ... }
1504
1506
 
1505
1507
  ---
1506
1508
 
1507
- ##### `slackSecretName`<sup>Required</sup> <a name="slackSecretName" id="rds-database-auto-start-preventer.Secrets.property.slackSecretName"></a>
1509
+ ##### `slackSecretName`<sup>Optional</sup> <a name="slackSecretName" id="rds-database-auto-start-preventer.Secrets.property.slackSecretName"></a>
1508
1510
 
1509
1511
  ```typescript
1510
1512
  public readonly slackSecretName: string;
@@ -1514,6 +1516,8 @@ public readonly slackSecretName: string;
1514
1516
 
1515
1517
  Name of the Secrets Manager secret containing Slack token and channel.
1516
1518
 
1519
+ When omitted, the handler stops matching RDS resources and does not post to Slack.
1520
+
1517
1521
  ---
1518
1522
 
1519
1523
  ### TargetResource <a name="TargetResource" id="rds-database-auto-start-preventer.TargetResource"></a>
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
- # RDS Database Auto Start Preventer (AWS CDK v2)
1
+ # RDS Database Auto Start Preventer (CDK v2)
2
2
 
3
- [![GitHub](https://img.shields.io/github/license/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer?style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/blob/main/LICENSE)
4
- [![npm](https://img.shields.io/npm/v/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)
5
- [![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/release.yml?branch=main&label=release&style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/actions/workflows/release.yml)
6
- [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer?sort=semver&style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/releases)
3
+ [![npm version](https://img.shields.io/npm/v/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)
4
+ [![license](https://img.shields.io/npm/l/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)
5
+ [![Node.js](https://img.shields.io/node/v/rds-database-auto-start-preventer?style=flat-square)](https://www.npmjs.com/package/rds-database-auto-start-preventer)
6
+ [![build](https://img.shields.io/github/actions/workflow/status/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/build.yml?label=build&style=flat-square)](https://github.com/gammarers-aws-cdk-constructs/rds-database-auto-start-preventer/actions/workflows/build.yml)
7
7
 
8
8
  [![View on Construct Hub](https://constructs.dev/badge?package=rds-database-auto-start-preventer)](https://constructs.dev/packages/rds-database-auto-start-preventer)
9
9
 
10
- CDK construct library that stops RDS DB instances and clusters after they are auto-started by AWS (RDS-EVENT-0154 / RDS-EVENT-0153). It uses EventBridge rules and a Durable Lambda to detect auto-start events, filter resources by tags in the handler, stop matching resources when they are `available`, and post a Slack notification only when this Lambda invoked the stop API successfully.
10
+ CDK construct library that stops RDS DB instances and clusters after they are auto-started by AWS (RDS-EVENT-0154 / RDS-EVENT-0153). It uses EventBridge rules and a Durable Lambda to detect auto-start events, filter resources by tags in the handler, stop matching resources when they are `available`, and post a Slack notification only when this Lambda invoked the stop API successfully and a Slack secret name is set.
11
11
 
12
12
  ## Features
13
13
 
@@ -15,44 +15,49 @@ CDK construct library that stops RDS DB instances and clusters after they are au
15
15
  - **Handler-side tag filtering** – EventBridge rules match all auto-start events; the Lambda evaluates `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters` and skips resources that do not match `tagKey` / `tagValues`
16
16
  - **Durable Lambda** – Uses AWS Lambda Durable Execution for reliable, long-running workflow (initial wait, status wait, stop, and post-stop wait)
17
17
  - **Least-privilege IAM** – Grants RDS describe and stop actions only (no Resource Groups Tagging API)
18
- - **Slack notifications** – Sends a message when this invocation called `StopDBInstance` / `StopDBCluster` and the resource reached `stopped` (no notification when the resource was already stopped or tags did not match)
18
+ - **Slack notifications** – When `slackSecretName` is set, sends a message when this invocation called `StopDBInstance` / `StopDBCluster` and the resource reached `stopped` (no notification when the secret name is omitted, the resource was already stopped, or tags did not match)
19
19
  - **Optional rule toggle** – EventBridge rules can be enabled or disabled via `enableRule`
20
20
 
21
+ ## How it works
22
+
23
+ 1. EventBridge invokes the Durable Lambda with the RDS auto-start event and tag filter parameters (`tagKey`, `tagValues`).
24
+ 2. The handler waits 1 minute, then waits on DescribeDB* until the resource leaves transitional statuses.
25
+ 3. If the resource tag does not match, the handler exits with no stop action.
26
+ 4. If the resource is `available` and tags match, the handler calls StopDB* and waits until `stopped`.
27
+ 5. If the resource is already `stopped` (for example, stopped by another process), the handler exits without calling StopDB* and without posting to Slack.
28
+ 6. When `slackSecretName` is set, Slack is notified only when StopDB* was invoked by this invocation and the resource reached `stopped`. When it is omitted, the handler does not post to Slack.
29
+
30
+ Tag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running.
31
+
21
32
  ## Installation
22
33
 
23
- **npm**
34
+ ### npm
24
35
 
25
36
  ```bash
26
37
  npm install rds-database-auto-start-preventer
27
38
  ```
28
39
 
29
- **yarn**
40
+ ### yarn
30
41
 
31
42
  ```bash
32
43
  yarn add rds-database-auto-start-preventer
33
44
  ```
34
45
 
35
- ## Usage
36
-
37
- ### How it works
46
+ ### pnpm
38
47
 
39
- 1. EventBridge invokes the Durable Lambda with the RDS auto-start event and tag filter parameters (`tagKey`, `tagValues`).
40
- 2. The handler waits 1 minute, then waits on DescribeDB* until the resource leaves transitional statuses.
41
- 3. If the resource tag does not match, the handler exits with no stop action.
42
- 4. If the resource is `available` and tags match, the handler calls StopDB* and waits until `stopped`.
43
- 5. If the resource is already `stopped` (for example, stopped by another process), the handler exits without calling StopDB* and without posting to Slack.
44
- 6. Slack is notified only when StopDB* was invoked by this invocation and the resource reached `stopped`.
45
-
46
- Tag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running.
48
+ ```bash
49
+ pnpm add rds-database-auto-start-preventer
50
+ ```
47
51
 
48
- ### Construct
52
+ ## Usage
49
53
 
50
- Use `RDSDatabaseAutoStartPreventer` when you want to add auto-start prevention to an existing stack or compose it with other constructs.
54
+ Use `RDSDatabaseAutoStartPreventer` when you want to add auto-start prevention to an existing stack or compose it with other constructs. Omit `slackSecretName` to stop matching resources without Slack.
51
55
 
52
56
  ```typescript
53
- import { Stack } from 'aws-cdk-lib';
57
+ import { App, Stack } from 'aws-cdk-lib';
54
58
  import { RDSDatabaseAutoStartPreventer } from 'rds-database-auto-start-preventer';
55
59
 
60
+ const app = new App();
56
61
  const stack = new Stack(app, 'MyStack');
57
62
 
58
63
  new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
@@ -60,7 +65,19 @@ new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
60
65
  tagKey: 'AutoStartPrevent',
61
66
  tagValues: ['YES'],
62
67
  },
63
- enableRule: true, // optional, defaults to true
68
+ secrets: {},
69
+ });
70
+ ```
71
+
72
+ Pass `slackSecretName` when a successful stop should post to Slack. `enableRule` defaults to `true`.
73
+
74
+ ```typescript
75
+ new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
76
+ targetResource: {
77
+ tagKey: 'AutoStartPrevent',
78
+ tagValues: ['YES'],
79
+ },
80
+ enableRule: true,
64
81
  secrets: {
65
82
  slackSecretName: 'my-app/slack',
66
83
  },
@@ -72,15 +89,17 @@ new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
72
89
  Use `RDSDatabaseAutoStartPreventStack` when you want a dedicated stack that only deploys the RDS auto-start prevent resources.
73
90
 
74
91
  ```typescript
92
+ import { App } from 'aws-cdk-lib';
75
93
  import { RDSDatabaseAutoStartPreventStack } from 'rds-database-auto-start-preventer';
76
94
 
95
+ const app = new App();
96
+
77
97
  new RDSDatabaseAutoStartPreventStack(app, 'RDSDatabaseAutoStartPreventStack', {
78
98
  stackName: 'rds-database-auto-start-prevent',
79
99
  targetResource: {
80
100
  tagKey: 'AutoStartPrevent',
81
101
  tagValues: ['YES'],
82
102
  },
83
- enableRule: true, // optional, defaults to true
84
103
  secrets: {
85
104
  slackSecretName: 'my-app/slack',
86
105
  },
@@ -114,7 +133,13 @@ Example secret value:
114
133
  | `targetResource.tagValues` | `string[]` | Yes | Tag values that indicate the resource should be stopped (e.g. `['YES']`, `['production']`). |
115
134
  | `enableRule` | `boolean` | No | Whether the EventBridge rules are enabled. Defaults to `true` if omitted. |
116
135
  | `secrets` | `Secrets` | Yes | External secrets for notifications. |
117
- | `secrets.slackSecretName` | `string` | Yes | Name of the Secrets Manager secret containing Slack `token` and `channel`. |
136
+ | `secrets.slackSecretName` | `string` | No | Name of the Secrets Manager secret containing Slack `token` and `channel`. Omit it to skip Slack notifications. |
137
+
138
+ Empty `tagKey`, an empty `tagValues` array (or blank entries), and a blank `slackSecretName` fail at synthesis. Omitting `slackSecretName` is allowed. Unresolved CDK tokens are not checked.
139
+
140
+ ## API
141
+
142
+ See [API.md](./API.md).
118
143
 
119
144
  ## Requirements
120
145