Compare commits

..

1 commit

Author SHA1 Message Date
dependabot[bot]
91f35d8450
Bump aws-cdk-lib from 2.257.0 to 2.258.0
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk/tree/HEAD/packages/aws-cdk-lib) from 2.257.0 to 2.258.0.
- [Release notes](https://github.com/aws/aws-cdk/releases)
- [Changelog](https://github.com/aws/aws-cdk/blob/main/CHANGELOG.v2.alpha.md)
- [Commits](https://github.com/aws/aws-cdk/commits/v2.258.0/packages/aws-cdk-lib)

---
updated-dependencies:
- dependency-name: aws-cdk-lib
  dependency-version: 2.257.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-05 17:01:22 +00:00
3 changed files with 4 additions and 98 deletions

View file

@ -43,6 +43,5 @@
]
}
]
},
"ssm:account=328440206208:parameterName=/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64:region=us-east-1": "ami-0b183bb1259186479"
}
}

View file

@ -1,7 +1,5 @@
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";
@ -101,48 +99,15 @@ export class BackupVerification extends Construct {
],
});
// Errors alarm: only fires when the function actually runs and errors.
// The function runs once daily, so for ~23h there is no data. Treating
// missing data as BREACHING flipped this alarm OK->ALARM every day around
// 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.
// 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", {
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) }),
threshold: 1,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
treatMissingData: cloudwatch.TreatMissingData.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.
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({
period: cdk.Duration.hours(24),
statistic: cloudwatch.Stats.SUM,
}),
threshold: 1,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.BREACHING,
comparisonOperator: cloudwatch.ComparisonOperator.LESS_THAN_THRESHOLD,
});
notRunningAlarm.addAlarmAction(new cloudwatch_actions.SnsAction(alertTopic));
this.functionArn = fn.functionArn;
}

View file

@ -182,19 +182,6 @@ export class ForgejoStack extends cdk.Stack {
"",
"useradd --system --shell /bin/bash --home-dir /home/forgejo --create-home forgejo",
"",
"# ── Persistent data volume (wait for CfnVolumeAttachment) ──",
"until lsblk -dno NAME | grep -v $(lsblk -no PKNAME $(findmnt -n -o SOURCE /) 2>/dev/null || echo xvda) | grep -q .; do",
" echo 'Waiting for data volume...'",
" sleep 5",
"done",
"DATA_DEVICE=/dev/$(lsblk -dno NAME | grep -v $(lsblk -no PKNAME $(findmnt -n -o SOURCE /) 2>/dev/null || echo xvda) | head -1)",
"if ! blkid \"$DATA_DEVICE\"; then",
" mkfs.ext4 -L forgejo-data \"$DATA_DEVICE\"",
"fi",
"mkdir -p /var/lib/forgejo",
"echo \"LABEL=forgejo-data /var/lib/forgejo ext4 defaults,nofail 0 2\" >> /etc/fstab",
"mount -a",
"",
"mkdir -p /var/lib/forgejo/{data,log}",
"chown -R forgejo:forgejo /var/lib/forgejo",
"chmod 750 /var/lib/forgejo",
@ -261,27 +248,6 @@ export class ForgejoStack extends cdk.Stack {
"SVCEOF",
"",
"systemctl daemon-reload",
"",
"# ── Restore from latest S3 dump if the data volume is empty (first boot or volume loss) ──",
"if [ ! -f /var/lib/forgejo/data/forgejo.db ]; then",
" echo 'No database on data volume - restoring latest backup from S3'",
" S3_PREFIX=$(aws ssm get-parameter --name /forgejo/backup-s3-prefix --query Parameter.Value --output text --region us-east-1 || echo 'archive')",
" LATEST=$(aws s3 ls s3://forgejo-backups-328440206208/${S3_PREFIX}/ --region us-east-1 | awk '{print $2}' | sort | tail -1 | tr -d '/')",
" if [ -n \"$LATEST\" ]; then",
" FILE=$(aws s3 ls s3://forgejo-backups-328440206208/${S3_PREFIX}/${LATEST}/ --region us-east-1 | awk '{print $4}' | tail -1)",
" RESTORE_DIR=$(mktemp -d)",
" aws s3 cp \"s3://forgejo-backups-328440206208/${S3_PREFIX}/${LATEST}/${FILE}\" \"$RESTORE_DIR/dump.tar.gz\" --region us-east-1",
" tar xzf \"$RESTORE_DIR/dump.tar.gz\" -C \"$RESTORE_DIR\"",
" cp -a \"$RESTORE_DIR\"/data/. /var/lib/forgejo/data/",
" mkdir -p /var/lib/forgejo/data/repositories",
" cp -a \"$RESTORE_DIR\"/repos/. /var/lib/forgejo/data/repositories/",
" chown -R forgejo:forgejo /var/lib/forgejo",
" rm -rf \"$RESTORE_DIR\"",
" else",
" echo 'No backup found in S3 - starting fresh'",
" fi",
"fi",
"",
"systemctl enable --now forgejo",
"",
"cat > /usr/local/bin/forgejo-backup.sh << 'BAKEOF'",
@ -394,17 +360,13 @@ export class ForgejoStack extends cdk.Stack {
instanceType: ec2.InstanceType.of(ec2.InstanceClass.T4G, ec2.InstanceSize.SMALL),
machineImage: ec2.MachineImage.latestAmazonLinux2023({
cpuType: ec2.AmazonLinuxCpuType.ARM_64,
// Cache the resolved AMI in cdk.context.json so deploys don't pick up
// new AL2023 releases implicitly (AMI change forces instance replacement).
// Refresh deliberately with: cdk context --reset <ami key> && cdk synth
cachedInContext: true,
}),
securityGroup: sg,
role,
userData,
blockDevices: [{
deviceName: "/dev/xvda",
volume: ec2.BlockDeviceVolume.ebs(20, {
volume: ec2.BlockDeviceVolume.ebs(50, {
volumeType: ec2.EbsDeviceVolumeType.GP3,
encrypted: true,
}),
@ -413,26 +375,6 @@ export class ForgejoStack extends cdk.Stack {
cdk.Tags.of(instance).add("forgejo-backup", "true");
// All Forgejo state (sqlite db, repositories, logs) lives on this volume,
// mounted at /var/lib/forgejo. RETAIN means it survives instance
// replacement and stack deletion; userdata mounts the existing filesystem
// (blkid guard prevents formatting) and restores from S3 only when empty.
const dataVolume = new ec2.Volume(this, "DataVolume", {
availabilityZone: "us-east-1a",
size: cdk.Size.gibibytes(50),
volumeType: ec2.EbsDeviceVolumeType.GP3,
encrypted: true,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
cdk.Tags.of(dataVolume).add("Name", "forgejo-data");
cdk.Tags.of(dataVolume).add("forgejo-backup", "true");
new ec2.CfnVolumeAttachment(this, "DataVolumeAttachment", {
instanceId: instance.instanceId,
volumeId: dataVolume.volumeId,
device: "/dev/xvdf",
});
const dlmRole = new iam.Role(this, "DlmRole", {
roleName: "forgejo-dlm",
assumedBy: new iam.ServicePrincipal("dlm.amazonaws.com"),