diff --git a/lib/constructs/backup-verification.ts b/lib/constructs/backup-verification.ts index b9e9935..3602a57 100644 --- a/lib/constructs/backup-verification.ts +++ b/lib/constructs/backup-verification.ts @@ -1,5 +1,7 @@ import * as cdk from "aws-cdk-lib"; import * as cloudwatch from "aws-cdk-lib/aws-cloudwatch"; +import * as cloudwatch_actions from "aws-cdk-lib/aws-cloudwatch-actions"; +import * as sns from "aws-cdk-lib/aws-sns"; import * as events from "aws-cdk-lib/aws-events"; import * as events_targets from "aws-cdk-lib/aws-events-targets"; import * as iam from "aws-cdk-lib/aws-iam"; @@ -105,7 +107,16 @@ export class BackupVerification extends Construct { // 11:01 UTC even though no error ever occurred. NOT_BREACHING means "no // data = no errors = healthy"; the separate not-running alarm below covers // the "verification never ran" case. - new cloudwatch.Alarm(this, "ErrorAlarm", { + // Org operational alarm topic (site-alerts, CMK-encrypted — never + // alias/aws/sns, which CloudWatch cannot publish to). Alarm action only, + // no OK action, per org convention. + const alertTopic = sns.Topic.fromTopicArn( + this, + "AlertTopic", + "arn:aws:sns:us-east-1:328440206208:site-alerts" + ); + + const errorAlarm = new cloudwatch.Alarm(this, "ErrorAlarm", { alarmName: "forgejo-backup-verification-errors", alarmDescription: "Backup verification Lambda is failing — Slack notifications may not be firing", metric: fn.metricErrors({ period: cdk.Duration.hours(1) }), @@ -114,11 +125,12 @@ export class BackupVerification extends Construct { treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING, comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, }); + errorAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(alertTopic)); // Not-running alarm: fires if the daily verification did not invoke at all // in a 24h window. This is the real "missing run" guard that the errors // alarm's BREACHING setting was previously (and incorrectly) providing. - new cloudwatch.Alarm(this, "NotRunningAlarm", { + const notRunningAlarm = new cloudwatch.Alarm(this, "NotRunningAlarm", { alarmName: "forgejo-backup-verification-not-running", alarmDescription: "Backup verification Lambda has not run in the last 24h — daily verification may be broken", metric: fn.metricInvocations({ @@ -130,6 +142,7 @@ export class BackupVerification extends Construct { treatMissingData: cloudwatch.TreatMissingData.BREACHING, comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD, }); + notRunningAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(alertTopic)); this.functionArn = fn.functionArn; }