rds-database-auto-start-preventer 0.4.4 → 0.5.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 CHANGED
@@ -9,4 +9,4 @@ charset=utf-8
9
9
  [*\.{js,ts}]
10
10
  indent_style=space
11
11
  indent_size=2
12
- max_line_length=120
12
+ max_line_length=160
package/.jsii CHANGED
@@ -8435,7 +8435,7 @@
8435
8435
  }
8436
8436
  }
8437
8437
  },
8438
- "description": "CDK stack 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, optionally filter by tags, stop the resource if it matches, and post a notification to Slack.",
8438
+ "description": "CDK construct library that stops RDS DB instances and clusters after they are auto-started by AWS (RDS-EVENT-0154 / RDS-EVENT-0153), using EventBridge and a Durable Lambda to filter by tags in the handler, stop matching available resources, and post to Slack only after a successful stop when a Slack secret name is set.",
8439
8439
  "docs": {
8440
8440
  "stability": "stable"
8441
8441
  },
@@ -8459,7 +8459,7 @@
8459
8459
  },
8460
8460
  "name": "rds-database-auto-start-preventer",
8461
8461
  "readme": {
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"
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`. Tag mismatch is a no-op (no StopDB*, no Slack)\n- **Durable Lambda** – Uses AWS Lambda Durable Execution for a long-running workflow (initial wait, status wait, stop, and post-stop wait) with a 2-hour execution timeout\n- **Least-privilege IAM** – Describe is scoped to account/region `db` / `cluster` ARNs; Stop is further limited by `aws:ResourceTag` matching `tagKey` / `tagValues` (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 calls DescribeDB* until the resource leaves transitional statuses. While the status stays transitional (or stopping after StopDB*), it waits up to **5 minutes** between describes.\n3. If the resource tag does not match, the handler exits as a **no-op** (no StopDB*, no Slack).\n4. If the resource is `available` and tags match, the handler calls StopDB* and waits until `stopped` (again using up to 5-minute intervals while transitional).\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\nTiming defaults (not configurable via props today):\n\n| Setting | Value |\n|---------|-------|\n| Initial wait before the first describe | 1 minute |\n| Wait between describes while status is transitional / stopping | up to 5 minutes |\n| Lambda invocation `timeout` | 15 minutes |\n| Durable `executionTimeout` | 2 hours |\n| Durable history `retentionPeriod` | 1 day |\n\nTag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running (no-op).\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\n### Minimal deployable app\n\nUse `RDSDatabaseAutoStartPreventStack` when you want a dedicated stack you can deploy as-is. Put this in your CDK app entry (for example `bin/app.ts`), then deploy.\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 env: {\n account: process.env.CDK_DEFAULT_ACCOUNT,\n region: process.env.CDK_DEFAULT_REGION,\n },\n stackName: 'rds-database-auto-start-prevent',\n targetResource: {\n tagKey: 'AutoStartPrevent',\n tagValues: ['YES'],\n },\n // Omit slackSecretName to skip Slack; set it when stop should notify Slack.\n secrets: {\n slackSecretName: 'my-app/slack',\n },\n});\n\napp.synth();\n```\n\nDeploy checklist:\n\n1. Install this package and peers (`aws-cdk-lib`, `constructs`) in your CDK app.\n2. Tag the RDS instances or clusters to protect (for example `AutoStartPrevent=YES`).\n3. Optional: create the Secrets Manager secret described in [Slack secret](#slack-secret-aws-secrets-manager). Omit `slackSecretName` if you do not need Slack.\n4. From the CDK app: `npx cdk deploy RDSDatabaseAutoStartPreventStack`\n\n### Construct in an existing stack\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### Slack secret (AWS Secrets Manager)\n\nCreate the secret **before** deploy when you want Slack notifications. Omit `slackSecretName` to skip Slack entirely (no secret and no Secrets Manager IAM are required in that case).\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\nWhen `slackSecretName` is set, the construct grants the Lambda role read access to that secret and attaches the AWS Parameters and Secrets Extension. You do not need to add a separate Secrets Manager policy yourself for this secret.\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## Notes\n\n- **Aurora / dual events:** An Aurora auto-start can emit both a DB cluster event (`RDS-EVENT-0153`) and DB instance event(s) (`RDS-EVENT-0154`). This package listens for both and may run separate Durable executions. Tag mismatch remains a no-op; if the resource is already `stopped`, the handler does not call StopDB* and does not post to Slack.\n- **IAM:** RDS Describe is limited to account/region `db` / `cluster` ARNs. Stop requires a matching `aws:ResourceTag` for your `tagKey` / `tagValues`. Slack secret read is granted only when `slackSecretName` is set.\n\n## Troubleshooting\n\n- **CloudWatch Logs:** The construct creates a dedicated Log Group for the Durable Lambda (JSON logs, 3-month retention). After a successful create, the log group uses `RetainExceptOnCreate` so it remains available for incident review after stack delete or replace.\n- **Nothing stopped / no Slack:** Confirm the resource tag matches `tagKey` / `tagValues`. Mismatch is intentional no-op with no Slack message.\n- **Stop attempted but Slack missing:** Slack runs only when this invocation called StopDB* and the resource reached `stopped`, and only when `slackSecretName` is set. Already-stopped resources skip Slack.\n- **Secret errors:** Ensure the secret exists before deploy, JSON has non-empty `token` and `channel`, and the name passed as `slackSecretName` matches Secrets Manager.\n\n## License\n\nThis project is licensed under the Apache-2.0 License.\n"
8463
8463
  },
8464
8464
  "repository": {
8465
8465
  "type": "git",
@@ -8486,8 +8486,8 @@
8486
8486
  "summary": "Creates the stack and the RDSDatabaseAutoStartPreventer construct."
8487
8487
  },
8488
8488
  "locationInModule": {
8489
- "filename": "src/stacks/rds-database-auto-start-prevent-stack.ts",
8490
- "line": 29
8489
+ "filename": "src/rds-database-auto-start-prevent-stack.ts",
8490
+ "line": 24
8491
8491
  },
8492
8492
  "parameters": [
8493
8493
  {
@@ -8521,11 +8521,11 @@
8521
8521
  },
8522
8522
  "kind": "class",
8523
8523
  "locationInModule": {
8524
- "filename": "src/stacks/rds-database-auto-start-prevent-stack.ts",
8525
- "line": 21
8524
+ "filename": "src/rds-database-auto-start-prevent-stack.ts",
8525
+ "line": 16
8526
8526
  },
8527
8527
  "name": "RDSDatabaseAutoStartPreventStack",
8528
- "symbolId": "src/stacks/rds-database-auto-start-prevent-stack:RDSDatabaseAutoStartPreventStack"
8528
+ "symbolId": "src/rds-database-auto-start-prevent-stack:RDSDatabaseAutoStartPreventStack"
8529
8529
  },
8530
8530
  "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps": {
8531
8531
  "assembly": "rds-database-auto-start-preventer",
@@ -8536,74 +8536,22 @@
8536
8536
  },
8537
8537
  "fqn": "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps",
8538
8538
  "interfaces": [
8539
+ "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventerProps",
8539
8540
  "aws-cdk-lib.StackProps"
8540
8541
  ],
8541
8542
  "kind": "interface",
8542
8543
  "locationInModule": {
8543
- "filename": "src/stacks/rds-database-auto-start-prevent-stack.ts",
8544
- "line": 9
8544
+ "filename": "src/rds-database-auto-start-prevent-stack.ts",
8545
+ "line": 11
8545
8546
  },
8546
8547
  "name": "RDSDatabaseAutoStartPreventStackProps",
8547
- "properties": [
8548
- {
8549
- "abstract": true,
8550
- "docs": {
8551
- "remarks": "Omit slackSecretName to skip Slack.",
8552
- "stability": "stable",
8553
- "summary": "Secrets for notifications."
8554
- },
8555
- "immutable": true,
8556
- "locationInModule": {
8557
- "filename": "src/stacks/rds-database-auto-start-prevent-stack.ts",
8558
- "line": 15
8559
- },
8560
- "name": "secrets",
8561
- "type": {
8562
- "fqn": "rds-database-auto-start-preventer.Secrets"
8563
- }
8564
- },
8565
- {
8566
- "abstract": true,
8567
- "docs": {
8568
- "stability": "stable",
8569
- "summary": "Tag-based target resource criteria for RDS instances/clusters to protect."
8570
- },
8571
- "immutable": true,
8572
- "locationInModule": {
8573
- "filename": "src/stacks/rds-database-auto-start-prevent-stack.ts",
8574
- "line": 11
8575
- },
8576
- "name": "targetResource",
8577
- "type": {
8578
- "fqn": "rds-database-auto-start-preventer.TargetResource"
8579
- }
8580
- },
8581
- {
8582
- "abstract": true,
8583
- "docs": {
8584
- "remarks": "Defaults to true if omitted.",
8585
- "stability": "stable",
8586
- "summary": "Whether the EventBridge rules are enabled."
8587
- },
8588
- "immutable": true,
8589
- "locationInModule": {
8590
- "filename": "src/stacks/rds-database-auto-start-prevent-stack.ts",
8591
- "line": 13
8592
- },
8593
- "name": "enableRule",
8594
- "optional": true,
8595
- "type": {
8596
- "primitive": "boolean"
8597
- }
8598
- }
8599
- ],
8600
- "symbolId": "src/stacks/rds-database-auto-start-prevent-stack:RDSDatabaseAutoStartPreventStackProps"
8548
+ "symbolId": "src/rds-database-auto-start-prevent-stack:RDSDatabaseAutoStartPreventStackProps"
8601
8549
  },
8602
8550
  "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventer": {
8603
8551
  "assembly": "rds-database-auto-start-preventer",
8604
8552
  "base": "constructs.Construct",
8605
8553
  "docs": {
8606
- "remarks": "EventBridge rules match all auto-start events; tag filtering runs in the handler\nusing `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters`.\nIAM grants RDS describe and stop actions only (no Resource Groups Tagging API).",
8554
+ "remarks": "EventBridge rules match all auto-start events; tag filtering runs in the handler\nusing `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters`.\nIAM grants account/region-scoped describe on `db` / `cluster` ARNs, and stop only\nwhen `aws:ResourceTag` matches {@link TargetResource} (no Resource Groups Tagging API).",
8607
8555
  "stability": "stable",
8608
8556
  "summary": "Deploys EventBridge rules and a Durable Lambda to stop matching RDS resources after auto-start events (RDS-EVENT-0154 / RDS-EVENT-0153)."
8609
8557
  },
@@ -8618,8 +8566,8 @@
8618
8566
  "summary": "Creates the Durable Lambda, EventBridge rules, and IAM policies."
8619
8567
  },
8620
8568
  "locationInModule": {
8621
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8622
- "line": 103
8569
+ "filename": "src/rds-database-auto-start-preventer.ts",
8570
+ "line": 104
8623
8571
  },
8624
8572
  "parameters": [
8625
8573
  {
@@ -8653,11 +8601,11 @@
8653
8601
  },
8654
8602
  "kind": "class",
8655
8603
  "locationInModule": {
8656
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8657
- "line": 89
8604
+ "filename": "src/rds-database-auto-start-preventer.ts",
8605
+ "line": 90
8658
8606
  },
8659
8607
  "name": "RDSDatabaseAutoStartPreventer",
8660
- "symbolId": "src/constructs/rds-database-auto-start-preventer:RDSDatabaseAutoStartPreventer"
8608
+ "symbolId": "src/rds-database-auto-start-preventer:RDSDatabaseAutoStartPreventer"
8661
8609
  },
8662
8610
  "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventerProps": {
8663
8611
  "assembly": "rds-database-auto-start-preventer",
@@ -8669,7 +8617,7 @@
8669
8617
  "fqn": "rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventerProps",
8670
8618
  "kind": "interface",
8671
8619
  "locationInModule": {
8672
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8620
+ "filename": "src/rds-database-auto-start-preventer.ts",
8673
8621
  "line": 38
8674
8622
  },
8675
8623
  "name": "RDSDatabaseAutoStartPreventerProps",
@@ -8682,7 +8630,7 @@
8682
8630
  },
8683
8631
  "immutable": true,
8684
8632
  "locationInModule": {
8685
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8633
+ "filename": "src/rds-database-auto-start-preventer.ts",
8686
8634
  "line": 44
8687
8635
  },
8688
8636
  "name": "secrets",
@@ -8698,7 +8646,7 @@
8698
8646
  },
8699
8647
  "immutable": true,
8700
8648
  "locationInModule": {
8701
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8649
+ "filename": "src/rds-database-auto-start-preventer.ts",
8702
8650
  "line": 40
8703
8651
  },
8704
8652
  "name": "targetResource",
@@ -8715,7 +8663,7 @@
8715
8663
  },
8716
8664
  "immutable": true,
8717
8665
  "locationInModule": {
8718
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8666
+ "filename": "src/rds-database-auto-start-preventer.ts",
8719
8667
  "line": 42
8720
8668
  },
8721
8669
  "name": "enableRule",
@@ -8725,7 +8673,7 @@
8725
8673
  }
8726
8674
  }
8727
8675
  ],
8728
- "symbolId": "src/constructs/rds-database-auto-start-preventer:RDSDatabaseAutoStartPreventerProps"
8676
+ "symbolId": "src/rds-database-auto-start-preventer:RDSDatabaseAutoStartPreventerProps"
8729
8677
  },
8730
8678
  "rds-database-auto-start-preventer.Secrets": {
8731
8679
  "assembly": "rds-database-auto-start-preventer",
@@ -8737,7 +8685,7 @@
8737
8685
  "fqn": "rds-database-auto-start-preventer.Secrets",
8738
8686
  "kind": "interface",
8739
8687
  "locationInModule": {
8740
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8688
+ "filename": "src/rds-database-auto-start-preventer.ts",
8741
8689
  "line": 27
8742
8690
  },
8743
8691
  "name": "Secrets",
@@ -8751,7 +8699,7 @@
8751
8699
  },
8752
8700
  "immutable": true,
8753
8701
  "locationInModule": {
8754
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8702
+ "filename": "src/rds-database-auto-start-preventer.ts",
8755
8703
  "line": 32
8756
8704
  },
8757
8705
  "name": "slackSecretName",
@@ -8761,7 +8709,7 @@
8761
8709
  }
8762
8710
  }
8763
8711
  ],
8764
- "symbolId": "src/constructs/rds-database-auto-start-preventer:Secrets"
8712
+ "symbolId": "src/rds-database-auto-start-preventer:Secrets"
8765
8713
  },
8766
8714
  "rds-database-auto-start-preventer.TargetResource": {
8767
8715
  "assembly": "rds-database-auto-start-preventer",
@@ -8774,7 +8722,7 @@
8774
8722
  "fqn": "rds-database-auto-start-preventer.TargetResource",
8775
8723
  "kind": "interface",
8776
8724
  "locationInModule": {
8777
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8725
+ "filename": "src/rds-database-auto-start-preventer.ts",
8778
8726
  "line": 16
8779
8727
  },
8780
8728
  "name": "TargetResource",
@@ -8787,7 +8735,7 @@
8787
8735
  },
8788
8736
  "immutable": true,
8789
8737
  "locationInModule": {
8790
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8738
+ "filename": "src/rds-database-auto-start-preventer.ts",
8791
8739
  "line": 18
8792
8740
  },
8793
8741
  "name": "tagKey",
@@ -8803,7 +8751,7 @@
8803
8751
  },
8804
8752
  "immutable": true,
8805
8753
  "locationInModule": {
8806
- "filename": "src/constructs/rds-database-auto-start-preventer.ts",
8754
+ "filename": "src/rds-database-auto-start-preventer.ts",
8807
8755
  "line": 20
8808
8756
  },
8809
8757
  "name": "tagValues",
@@ -8817,9 +8765,9 @@
8817
8765
  }
8818
8766
  }
8819
8767
  ],
8820
- "symbolId": "src/constructs/rds-database-auto-start-preventer:TargetResource"
8768
+ "symbolId": "src/rds-database-auto-start-preventer:TargetResource"
8821
8769
  }
8822
8770
  },
8823
- "version": "0.4.4",
8824
- "fingerprint": "Ma7/fFGl2OmzwiEKzpwd1zN8oHuxcTuVbuOtR4Ca6IM="
8771
+ "version": "0.5.0",
8772
+ "fingerprint": "9sN1LILaadPIhBLYlDBY7yP/xKkSyy83hdp7G50Qa1s="
8825
8773
  }
package/API.md CHANGED
@@ -8,7 +8,8 @@ Deploys EventBridge rules and a Durable Lambda to stop matching RDS resources af
8
8
 
9
9
  EventBridge rules match all auto-start events; tag filtering runs in the handler
10
10
  using `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters`.
11
- IAM grants RDS describe and stop actions only (no Resource Groups Tagging API).
11
+ IAM grants account/region-scoped describe on `db` / `cluster` ARNs, and stop only
12
+ when `aws:ResourceTag` matches {@link TargetResource} (no Resource Groups Tagging API).
12
13
 
13
14
  #### Initializers <a name="Initializers" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventer.Initializer"></a>
14
15
 
@@ -1184,6 +1185,9 @@ const rDSDatabaseAutoStartPreventStackProps: RDSDatabaseAutoStartPreventStackPro
1184
1185
 
1185
1186
  | **Name** | **Type** | **Description** |
1186
1187
  | --- | --- | --- |
1188
+ | <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 used for notifications (e.g. Slack). |
1189
+ | <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. |
1190
+ | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.enableRule">enableRule</a></code> | <code>boolean</code> | Whether the EventBridge rules are enabled. |
1187
1191
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.analyticsReporting">analyticsReporting</a></code> | <code>boolean</code> | Include runtime versioning information in this Stack. |
1188
1192
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.crossRegionReferences">crossRegionReferences</a></code> | <code>boolean</code> | Enable this flag to allow native cross region stack references. |
1189
1193
  | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.description">description</a></code> | <code>string</code> | A description of the stack. |
@@ -1196,9 +1200,44 @@ const rDSDatabaseAutoStartPreventStackProps: RDSDatabaseAutoStartPreventStackPro
1196
1200
  | <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
1201
  | <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
1202
  | <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 for notifications. |
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
- | <code><a href="#rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.enableRule">enableRule</a></code> | <code>boolean</code> | Whether the EventBridge rules are enabled. |
1203
+
1204
+ ---
1205
+
1206
+ ##### `secrets`<sup>Required</sup> <a name="secrets" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.secrets"></a>
1207
+
1208
+ ```typescript
1209
+ public readonly secrets: Secrets;
1210
+ ```
1211
+
1212
+ - *Type:* <a href="#rds-database-auto-start-preventer.Secrets">Secrets</a>
1213
+
1214
+ Secrets used for notifications (e.g. Slack).
1215
+
1216
+ ---
1217
+
1218
+ ##### `targetResource`<sup>Required</sup> <a name="targetResource" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.targetResource"></a>
1219
+
1220
+ ```typescript
1221
+ public readonly targetResource: TargetResource;
1222
+ ```
1223
+
1224
+ - *Type:* <a href="#rds-database-auto-start-preventer.TargetResource">TargetResource</a>
1225
+
1226
+ Tag-based target resource criteria for RDS instances/clusters to protect.
1227
+
1228
+ ---
1229
+
1230
+ ##### `enableRule`<sup>Optional</sup> <a name="enableRule" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.enableRule"></a>
1231
+
1232
+ ```typescript
1233
+ public readonly enableRule: boolean;
1234
+ ```
1235
+
1236
+ - *Type:* boolean
1237
+
1238
+ Whether the EventBridge rules are enabled.
1239
+
1240
+ Defaults to true if omitted.
1202
1241
 
1203
1242
  ---
1204
1243
 
@@ -1446,46 +1485,6 @@ Whether to enable termination protection for this stack.
1446
1485
 
1447
1486
  ---
1448
1487
 
1449
- ##### `secrets`<sup>Required</sup> <a name="secrets" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.secrets"></a>
1450
-
1451
- ```typescript
1452
- public readonly secrets: Secrets;
1453
- ```
1454
-
1455
- - *Type:* <a href="#rds-database-auto-start-preventer.Secrets">Secrets</a>
1456
-
1457
- Secrets for notifications.
1458
-
1459
- Omit slackSecretName to skip Slack.
1460
-
1461
- ---
1462
-
1463
- ##### `targetResource`<sup>Required</sup> <a name="targetResource" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.targetResource"></a>
1464
-
1465
- ```typescript
1466
- public readonly targetResource: TargetResource;
1467
- ```
1468
-
1469
- - *Type:* <a href="#rds-database-auto-start-preventer.TargetResource">TargetResource</a>
1470
-
1471
- Tag-based target resource criteria for RDS instances/clusters to protect.
1472
-
1473
- ---
1474
-
1475
- ##### `enableRule`<sup>Optional</sup> <a name="enableRule" id="rds-database-auto-start-preventer.RDSDatabaseAutoStartPreventStackProps.property.enableRule"></a>
1476
-
1477
- ```typescript
1478
- public readonly enableRule: boolean;
1479
- ```
1480
-
1481
- - *Type:* boolean
1482
-
1483
- Whether the EventBridge rules are enabled.
1484
-
1485
- Defaults to true if omitted.
1486
-
1487
- ---
1488
-
1489
1488
  ### Secrets <a name="Secrets" id="rds-database-auto-start-preventer.Secrets"></a>
1490
1489
 
1491
1490
  External secrets for notifications (e.g. Slack). Omit {@link Secrets.slackSecretName} to skip Slack notifications.
package/README.md CHANGED
@@ -12,22 +12,32 @@ CDK construct library that stops RDS DB instances and clusters after they are au
12
12
  ## Features
13
13
 
14
14
  - **EventBridge integration** – Listens for RDS DB Instance (RDS-EVENT-0154) and DB Cluster (RDS-EVENT-0153) auto-start events
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
- - **Durable Lambda** – Uses AWS Lambda Durable Execution for reliable, long-running workflow (initial wait, status wait, stop, and post-stop wait)
17
- - **Least-privilege IAM** – Grants RDS describe and stop actions only (no Resource Groups Tagging API)
15
+ - **Handler-side tag filtering** – EventBridge rules match all auto-start events; the Lambda evaluates `TagList` from `rds:DescribeDBInstances` / `rds:DescribeDBClusters`. Tag mismatch is a no-op (no StopDB*, no Slack)
16
+ - **Durable Lambda** – Uses AWS Lambda Durable Execution for a long-running workflow (initial wait, status wait, stop, and post-stop wait) with a 2-hour execution timeout
17
+ - **Least-privilege IAM** – Describe is scoped to account/region `db` / `cluster` ARNs; Stop is further limited by `aws:ResourceTag` matching `tagKey` / `tagValues` (no Resource Groups Tagging API)
18
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
21
  ## How it works
22
22
 
23
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`.
24
+ 2. The handler waits **1 minute**, then calls DescribeDB* until the resource leaves transitional statuses. While the status stays transitional (or stopping after StopDB*), it waits up to **5 minutes** between describes.
25
+ 3. If the resource tag does not match, the handler exits as a **no-op** (no StopDB*, no Slack).
26
+ 4. If the resource is `available` and tags match, the handler calls StopDB* and waits until `stopped` (again using up to 5-minute intervals while transitional).
27
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
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
29
 
30
- Tag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running.
30
+ Timing defaults (not configurable via props today):
31
+
32
+ | Setting | Value |
33
+ |---------|-------|
34
+ | Initial wait before the first describe | 1 minute |
35
+ | Wait between describes while status is transitional / stopping | up to 5 minutes |
36
+ | Lambda invocation `timeout` | 15 minutes |
37
+ | Durable `executionTimeout` | 2 hours |
38
+ | Durable history `retentionPeriod` | 1 day |
39
+
40
+ Tag the RDS instances or clusters you want to protect (for example, `AutoStartPrevent=YES`). Resources without a matching tag are left running (no-op).
31
41
 
32
42
  ## Installation
33
43
 
@@ -51,55 +61,71 @@ pnpm add rds-database-auto-start-preventer
51
61
 
52
62
  ## Usage
53
63
 
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.
64
+ ### Minimal deployable app
65
+
66
+ Use `RDSDatabaseAutoStartPreventStack` when you want a dedicated stack you can deploy as-is. Put this in your CDK app entry (for example `bin/app.ts`), then deploy.
55
67
 
56
68
  ```typescript
57
- import { App, Stack } from 'aws-cdk-lib';
58
- import { RDSDatabaseAutoStartPreventer } from 'rds-database-auto-start-preventer';
69
+ import { App } from 'aws-cdk-lib';
70
+ import { RDSDatabaseAutoStartPreventStack } from 'rds-database-auto-start-preventer';
59
71
 
60
72
  const app = new App();
61
- const stack = new Stack(app, 'MyStack');
62
73
 
63
- new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
74
+ new RDSDatabaseAutoStartPreventStack(app, 'RDSDatabaseAutoStartPreventStack', {
75
+ env: {
76
+ account: process.env.CDK_DEFAULT_ACCOUNT,
77
+ region: process.env.CDK_DEFAULT_REGION,
78
+ },
79
+ stackName: 'rds-database-auto-start-prevent',
64
80
  targetResource: {
65
81
  tagKey: 'AutoStartPrevent',
66
82
  tagValues: ['YES'],
67
83
  },
68
- secrets: {},
84
+ // Omit slackSecretName to skip Slack; set it when stop should notify Slack.
85
+ secrets: {
86
+ slackSecretName: 'my-app/slack',
87
+ },
69
88
  });
89
+
90
+ app.synth();
70
91
  ```
71
92
 
72
- Pass `slackSecretName` when a successful stop should post to Slack. `enableRule` defaults to `true`.
93
+ Deploy checklist:
94
+
95
+ 1. Install this package and peers (`aws-cdk-lib`, `constructs`) in your CDK app.
96
+ 2. Tag the RDS instances or clusters to protect (for example `AutoStartPrevent=YES`).
97
+ 3. Optional: create the Secrets Manager secret described in [Slack secret](#slack-secret-aws-secrets-manager). Omit `slackSecretName` if you do not need Slack.
98
+ 4. From the CDK app: `npx cdk deploy RDSDatabaseAutoStartPreventStack`
99
+
100
+ ### Construct in an existing stack
101
+
102
+ 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.
73
103
 
74
104
  ```typescript
105
+ import { App, Stack } from 'aws-cdk-lib';
106
+ import { RDSDatabaseAutoStartPreventer } from 'rds-database-auto-start-preventer';
107
+
108
+ const app = new App();
109
+ const stack = new Stack(app, 'MyStack');
110
+
75
111
  new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
76
112
  targetResource: {
77
113
  tagKey: 'AutoStartPrevent',
78
114
  tagValues: ['YES'],
79
115
  },
80
- enableRule: true,
81
- secrets: {
82
- slackSecretName: 'my-app/slack',
83
- },
116
+ secrets: {},
84
117
  });
85
118
  ```
86
119
 
87
- ### Stack
88
-
89
- Use `RDSDatabaseAutoStartPreventStack` when you want a dedicated stack that only deploys the RDS auto-start prevent resources.
120
+ Pass `slackSecretName` when a successful stop should post to Slack. `enableRule` defaults to `true`.
90
121
 
91
122
  ```typescript
92
- import { App } from 'aws-cdk-lib';
93
- import { RDSDatabaseAutoStartPreventStack } from 'rds-database-auto-start-preventer';
94
-
95
- const app = new App();
96
-
97
- new RDSDatabaseAutoStartPreventStack(app, 'RDSDatabaseAutoStartPreventStack', {
98
- stackName: 'rds-database-auto-start-prevent',
123
+ new RDSDatabaseAutoStartPreventer(stack, 'RDSDatabaseAutoStartPreventer', {
99
124
  targetResource: {
100
125
  tagKey: 'AutoStartPrevent',
101
126
  tagValues: ['YES'],
102
127
  },
128
+ enableRule: true,
103
129
  secrets: {
104
130
  slackSecretName: 'my-app/slack',
105
131
  },
@@ -108,6 +134,8 @@ new RDSDatabaseAutoStartPreventStack(app, 'RDSDatabaseAutoStartPreventStack', {
108
134
 
109
135
  ### Slack secret (AWS Secrets Manager)
110
136
 
137
+ Create the secret **before** deploy when you want Slack notifications. Omit `slackSecretName` to skip Slack entirely (no secret and no Secrets Manager IAM are required in that case).
138
+
111
139
  Store a JSON object in AWS Secrets Manager with the Slack Bot Token and channel ID:
112
140
 
113
141
  | Key | Value |
@@ -124,6 +152,8 @@ Example secret value:
124
152
  }
125
153
  ```
126
154
 
155
+ When `slackSecretName` is set, the construct grants the Lambda role read access to that secret and attaches the AWS Parameters and Secrets Extension. You do not need to add a separate Secrets Manager policy yourself for this secret.
156
+
127
157
  ## Options
128
158
 
129
159
  | Option | Type | Required | Description |
@@ -148,6 +178,18 @@ See [API.md](./API.md).
148
178
  - **constructs** ^10.5.1
149
179
  - **AWS Lambda** runtime Node.js 24.x with Durable Execution (deployed by the construct)
150
180
 
181
+ ## Notes
182
+
183
+ - **Aurora / dual events:** An Aurora auto-start can emit both a DB cluster event (`RDS-EVENT-0153`) and DB instance event(s) (`RDS-EVENT-0154`). This package listens for both and may run separate Durable executions. Tag mismatch remains a no-op; if the resource is already `stopped`, the handler does not call StopDB* and does not post to Slack.
184
+ - **IAM:** RDS Describe is limited to account/region `db` / `cluster` ARNs. Stop requires a matching `aws:ResourceTag` for your `tagKey` / `tagValues`. Slack secret read is granted only when `slackSecretName` is set.
185
+
186
+ ## Troubleshooting
187
+
188
+ - **CloudWatch Logs:** The construct creates a dedicated Log Group for the Durable Lambda (JSON logs, 3-month retention). After a successful create, the log group uses `RetainExceptOnCreate` so it remains available for incident review after stack delete or replace.
189
+ - **Nothing stopped / no Slack:** Confirm the resource tag matches `tagKey` / `tagValues`. Mismatch is intentional no-op with no Slack message.
190
+ - **Stop attempted but Slack missing:** Slack runs only when this invocation called StopDB* and the resource reached `stopped`, and only when `slackSecretName` is set. Already-stopped resources skip Slack.
191
+ - **Secret errors:** Ensure the secret exists before deploy, JSON has non-empty `token` and `channel`, and the name passed as `slackSecretName` matches Secrets Manager.
192
+
151
193
  ## License
152
194
 
153
195
  This project is licensed under the Apache-2.0 License.
@@ -25080,7 +25080,7 @@ var import_web_api = __toESM(require_dist5());
25080
25080
  var import_aws_lambda_secret_fetcher = __toESM(require_lib4());
25081
25081
  var import_strict_env_resolver = __toESM(require_lib2());
25082
25082
 
25083
- // src/funcs/auto-start-prevent.predicates.ts
25083
+ // src/funcs/core/auto-start-prevent.predicates.ts
25084
25084
  var WAIT_INTERVAL_MINUTES = 5;
25085
25085
  var TRANSITIONAL_STATUSES = /* @__PURE__ */ new Set([
25086
25086
  "starting",