Commit graph

84 commits

Author SHA1 Message Date
dependabot[bot]
1e35876db7
Bump aws-cdk-lib from 2.260.0 to 2.261.0 (#41)
Some checks failed
Deploy / deploy (push) Has been cancelled
2026-07-04 05:54:33 +00:00
seahaven-openswe[bot]
0eff9ff829
fix: pin @types/node to CI runtime major and block Dependabot major bumps (#40) 2026-07-04 01:48:51 -04:00
dependabot[bot]
4c7b29e1ed
Bump aws-cdk from 2.1128.1 to 2.1129.0 (#37)
Some checks failed
Deploy / deploy (push) Has been cancelled
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1128.1 to 2.1129.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1129.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1129.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-02 15:24:10 -04:00
Copilot
36c5e17ab8
fix: extend S3 lifecycle rule to cover root-level backup objects across all stacks (#36)
Some checks failed
Deploy / deploy (push) Has been cancelled
* Initial plan

* fix: remove archive/ prefix from S3 lifecycle rule to cover root-level objects

The archive-to-glacier rule had prefix: "archive/" which caused pre-migration
backup files written to the bucket root to be excluded from any transition
policy. Removing the prefix makes the rule apply to all objects in the bucket,
ensuring root-level dump files also transition to Glacier after 30 days.

Closes #4

* fix: remove archive/ prefix from lifecycle rule in forgejo-replica-stack.ts

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-06-25 11:22:12 -04:00
dependabot[bot]
bd90e90d7c
Bump aws-cdk from 2.1128.0 to 2.1128.1 (#35)
Some checks are pending
Deploy / deploy (push) Waiting to run
2026-06-24 22:21:44 -04:00
dependabot[bot]
8fa63891ab
Update google-cloud-storage requirement in /lambda/backup-verification (#33)
Some checks failed
Deploy / deploy (push) Has been cancelled
Updates the requirements on [google-cloud-storage](https://github.com/googleapis/google-cloud-python) to permit the latest version.
- [Release notes](https://github.com/googleapis/google-cloud-python/releases)
- [Changelog](https://github.com/googleapis/google-cloud-python/blob/main/packages/google-cloud-documentai/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-cloud-python/compare/google-cloud-storage-v3.11.0...google-cloud-storage-v3.12.0)

---
updated-dependencies:
- dependency-name: google-cloud-storage
  dependency-version: 3.12.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-18 12:09:21 -04:00
dependabot[bot]
cc55dc50f4
Bump aws-cdk-lib from 2.258.1 to 2.260.0 (#32)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk/tree/HEAD/packages/aws-cdk-lib) from 2.258.1 to 2.260.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.260.0/packages/aws-cdk-lib)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-18 12:02:02 -04:00
dependabot[bot]
48375d5441
Bump aws-cdk from 2.1126.0 to 2.1128.0 (#31)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1126.0 to 2.1128.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1128.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1128.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-18 11:55:11 -04:00
dependabot[bot]
211ef970f6
Update google-cloud-storage requirement in /lambda/backup-verification (#30)
Some checks failed
Deploy / deploy (push) Has been cancelled
Updates the requirements on [google-cloud-storage](https://github.com/googleapis/google-cloud-python) to permit the latest version.
- [Release notes](https://github.com/googleapis/google-cloud-python/releases)
- [Changelog](https://github.com/googleapis/google-cloud-python/blob/main/packages/google-cloud-documentai/CHANGELOG.md)
- [Commits](https://github.com/googleapis/google-cloud-python/compare/google-cloud-iam-v2.18.0...google-cloud-storage-v3.11.0)

---
updated-dependencies:
- dependency-name: google-cloud-storage
  dependency-version: 3.11.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-11 14:37:46 -04:00
Adam Moussa
e32401e554
Repo hygiene: PR labeler + README badges + dependabot (INFRA-56/57/66) (#29)
Some checks are pending
Deploy / deploy (push) Waiting to run
2026-06-11 14:13:26 -04:00
dependabot[bot]
36efdb4472
Bump @types/node from 25.9.1 to 25.9.3 (#28)
Some checks are pending
Deploy / deploy (push) Waiting to run
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.9.1 to 25.9.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.9.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-11 12:00:14 -04:00
dependabot[bot]
ba99103978
Bump aws-cdk-lib from 2.258.0 to 2.258.1 (#27)
Bumps [aws-cdk-lib](https://github.com/aws/aws-cdk/tree/HEAD/packages/aws-cdk-lib) from 2.258.0 to 2.258.1.
- [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.1/packages/aws-cdk-lib)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-11 11:54:27 -04:00
Adam Moussa
891dc0831b
docs: document persistent data volume, restore-on-boot, cached AMI, alarms (#25)
Some checks failed
Deploy / deploy (push) Has been cancelled
Storage architecture changed 2026-06-05: state moved off the root
volume onto a standalone RETAIN data volume with automatic S3 restore
on empty boot.
2026-06-05 15:54:26 -04:00
dependabot[bot]
b75b4cc130
Bump aws-cdk-lib from 2.257.0 to 2.258.0 (#16)
Some checks are pending
Deploy / deploy (push) Waiting to run
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>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-05 15:06:04 -04:00
Adam Moussa
149178e1e2
fix(monitoring): wire backup-verification alarms to site-alerts topic (#24)
Both alarms changed state but notified nobody (no AlarmActions). Wire
each to the org operational alarm topic (site-alerts, CMK-encrypted)
with an ALARM action only — no OK action per org convention.
2026-06-05 14:47:09 -04:00
Adam Moussa
a7536f0bd7
Fix daily flapping of backup-verification errors alarm (#23)
The forgejo-backup-verification Lambda runs once per day, so its Errors
metric has data for only one hour and is missing for the other ~23h.
The errors alarm used TreatMissingData=BREACHING, which treated those
23h of missing data as a breach and flipped the alarm OK->ALARM every
day around 11:01 UTC despite zero actual errors.

Changes (alarm-only, no instance changes):
- ErrorAlarm: TreatMissingData BREACHING -> NOT_BREACHING. No data now
  means "no errors = healthy" instead of a false breach.
- Add forgejo-backup-verification-not-running: Invocations Sum over a
  24h period, alarms when < 1 invocation. This is the real "the daily
  verification never ran" guard that the BREACHING setting was trying
  (incorrectly) to provide.

Both alarms keep the existing action wiring (no SNS/OK actions), per the
org convention of never notifying on recovery.
2026-06-05 14:34:45 -04:00
Adam Moussa
f6b105a9fd
fix(infra): persistent data volume + restore-on-boot + cached AMI (#22)
Some checks are pending
Deploy / deploy (push) Waiting to run
Today's instance replacement (uncached AMI lookup resolved a new AL2023
release) destroyed the root volume holding all Forgejo state; restored
manually from the 05:00 S3 dump. This makes replacement harmless:

- New 50 GiB standalone volume (RemovalPolicy.RETAIN) mounted at
  /var/lib/forgejo — sqlite db, repositories, and logs all survive
  instance replacement and stack deletion. No app.ini path changes.
- Restore-on-boot: if the data volume has no database (first boot or
  total volume loss), userdata restores the latest S3 dump
  automatically before starting the service. Volume loss self-heals
  to <=24h-old state.
- blkid guard: an existing filesystem is mounted, never formatted.
- cachedInContext: true + committed cdk.context.json — AMI changes
  (and the instance replacement they force) become deliberate.
- Root volume 50 -> 20 GiB; state no longer lives there.
- forgejo-backup tag on the data volume brings it under the existing
  DLM snapshot policy.

Deploy replaces the instance once; restore-on-boot pulls the fresh
17:43 UTC dump.
2026-06-05 13:47:51 -04:00
Adam Moussa
8d520f844b
fix(deps): bump aws-cdk-lib pin to 2.257.0 (#21) 2026-06-05 12:58:26 -04:00
Adam Moussa
6754ceaa42
Add dependency-review caller workflow (#20)
* Add dependency-review caller workflow

Add a pull_request-triggered caller that invokes the org-level
callable-dependency-review workflow to scan dependency changes and
fail on high-severity advisories.

* chore: retrigger checks

* chore: retrigger dep review (post-fix)
2026-06-05 12:26:38 -04:00
dependabot[bot]
0ff128a0a6
Bump aws-cdk from 2.1121.0 to 2.1122.0 (#11)
Some checks failed
Deploy / deploy (push) Has been cancelled
aws-cdk CLI 2.1122.0 — patch bump, CI passes. Claude Code Review check didn't register on Dependabot rebase.
2026-05-18 17:36:30 -04:00
dependabot[bot]
425bc86cc7
Bump @types/node from 22.19.18 to 25.9.0 (#9)
Some checks are pending
Deploy / deploy (push) Waiting to run
@types/node 25.9.0 — validated locally: tsc --noEmit passes.
2026-05-18 17:27:53 -04:00
dependabot[bot]
c0ac1e3fc3
Bump typescript from 5.7.3 to 6.0.3 (#8)
TypeScript 6.0.3 — validated locally: tsc --noEmit and cdk synth both pass.
2026-05-18 17:27:47 -04:00
Adam Moussa
d2b718a126
Fix compliance audit violations from issue #6 (#7)
Pin aws-cdk-lib to blessed 2.253.1, add dependabot.yml, export
backup verification Lambda ARN, pin node-version: 24 in workflows,
add __pycache__ to .gitignore.
2026-05-18 16:35:23 -04:00
Adam Moussa
45a63e8552 Restore overrideLogicalId on GcsTransferCredentials secret
Some checks are pending
Deploy / deploy (push) Waiting to run
Removing this changed the CloudFormation logical ID from
GcsTransferCredentials to GcsTransferCredentials35DA7E5D,
triggering a replacement that fails because the named secret
already exists.
2026-05-15 18:08:14 -04:00
Adam Moussa
5ed1db788e
Add 3-2-1 backup strategy with cross-region and GCS offsite (#5)
* Add 3-2-1 backup strategy with cross-region replication and GCS offsite

Implements a fully compliant 3-2-1 backup architecture:
- Copy 1 (live): Harden existing EBS snapshots to 30-day retention
- Copy 2 (near-site): S3 cross-region replication to us-west-2 with
  Object Lock (governance 90d) and versioning
- Copy 3 (offsite): GCS bucket in dedicated seahaven-backups GCP project
  with 2-year irreversible retention lock

Also adds a verification Lambda that checks all 3 locations daily and
runs monthly restore tests with SQLite integrity checks.

* Enable QEMU in CI for arm64 Lambda Docker builds

* Commit cdk.context.json for CI synth without AWS credentials

Vpc.fromLookup requires cached context to synthesize without
AWS credentials. Required for CI which runs cdk synth without
an OIDC role.

* Fix GCP project ID to sea-haven-backups

* Address code review findings for backup verification

Fix 4 critical issues:
- Add filter/priority/deleteMarkerReplication to S3 CRR rule (deploy would fail without)
- Add stack dependency so replica deploys before main stack
- Fix DB file extension matching (.sqlite3/.sql instead of .db)
- Replace nonexistent `forgejo restore` command with actual restore steps in README

Fix 4 moderate issues:
- Add timeout=10 to Slack webhook urlopen call
- Add filter='data' to tarfile.extract for PEP 706 compliance
- Add explicit ValueError for unknown handler mode
- Use date-scoped S3/GCS prefix instead of unbounded listing

* Fix backup strategy bug findings

* Handle SQL text dumps separately from binary SQLite in restore test

Forgejo dump produces gitea-db.sql as a text SQL dump (XORM export),
not a binary SQLite file. Opening it directly with sqlite3.connect()
throws DatabaseError. Now imports the SQL dump into a temp DB first.

* Fix GCS backup check: align staleness cutoff and add size validation

GCS check used a 72h cutoff but only listed 2 days of prefixes (~48h),
making the staleness check unreachable. Also added 1MB minimum file
size validation to match the S3 check.

* Rename SECRET_ARN env vars to SECRET_NAME to match actual values

* Fix EBS snapshot state check, drop unused GCS write grant and dead lifecycle rule

* Fix restore runbook, DLM snapshot tagging, README cleanup, and gsutil prompt

* Fix restore runbook: trailing-dot cp idiom and Glacier restore step

* Rename GCS service account to match read-only permissions

* Add 4 GiB ephemeral storage to verification Lambda

Monthly restore-test downloads and extracts the full dump tarball
in /tmp. As the dump grows with LFS data, the default 512 MB will
eventually cause ENOSPC failures.

* Replace hardcoded instance ID in README with CloudFormation lookup

The instance ID changes on every instance replacement (version
upgrades, stack updates). Using a dynamic query prevents stale
references and removes a manual update step from the deploy process.

* Read backup S3 prefix from SSM parameter at runtime

Adds /forgejo/backup-s3-prefix SSM parameter (value: archive)
and updates the backup script to fetch it instead of hardcoding
the prefix. Eliminates the manual post-deploy sed step.

* Address cross-review findings for backup verification

- Add size guard before downloading dump in restore test (3.5 GB cap)
- Use paginator for list_objects_v2 in S3 checks and restore test
- Remove unnecessary overrideLogicalId on GcsTransferCredentials secret
- Pass explicit { mode: "daily" } to daily EventBridge rule target
- Add fallback for SSM parameter fetch in backup script
- Export replica bucket ARN/name from replica stack, consume via props

* Add CloudWatch alarm for backup verification Lambda errors

Fires on any Lambda error and on missing data (missed schedule).
Catches silent failures where the Slack notification never fires.

* Add .env to .gitignore

Required by org CI conventions check.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-15 17:59:31 -04:00
Adam Moussa
cfda99927b
Add 3-2-1 backup strategy (#2)
* Add 3-2-1 backup strategy with cross-region replication and GCS offsite

Implements a fully compliant 3-2-1 backup architecture:
- Copy 1 (live): Harden existing EBS snapshots to 30-day retention
- Copy 2 (near-site): S3 cross-region replication to us-west-2 with
  Object Lock (governance 90d) and versioning
- Copy 3 (offsite): GCS bucket in dedicated seahaven-backups GCP project
  with 2-year irreversible retention lock

Also adds a verification Lambda that checks all 3 locations daily and
runs monthly restore tests with SQLite integrity checks.

* Enable QEMU in CI for arm64 Lambda Docker builds

* Commit cdk.context.json for CI synth without AWS credentials

Vpc.fromLookup requires cached context to synthesize without
AWS credentials. Required for CI which runs cdk synth without
an OIDC role.

* Fix GCP project ID to sea-haven-backups

* Address code review findings for backup verification

Fix 4 critical issues:
- Add filter/priority/deleteMarkerReplication to S3 CRR rule (deploy would fail without)
- Add stack dependency so replica deploys before main stack
- Fix DB file extension matching (.sqlite3/.sql instead of .db)
- Replace nonexistent `forgejo restore` command with actual restore steps in README

Fix 4 moderate issues:
- Add timeout=10 to Slack webhook urlopen call
- Add filter='data' to tarfile.extract for PEP 706 compliance
- Add explicit ValueError for unknown handler mode
- Use date-scoped S3/GCS prefix instead of unbounded listing

* Fix backup strategy bug findings

* Handle SQL text dumps separately from binary SQLite in restore test

Forgejo dump produces gitea-db.sql as a text SQL dump (XORM export),
not a binary SQLite file. Opening it directly with sqlite3.connect()
throws DatabaseError. Now imports the SQL dump into a temp DB first.

* Fix GCS backup check: align staleness cutoff and add size validation

GCS check used a 72h cutoff but only listed 2 days of prefixes (~48h),
making the staleness check unreachable. Also added 1MB minimum file
size validation to match the S3 check.

* Rename SECRET_ARN env vars to SECRET_NAME to match actual values

* Fix EBS snapshot state check, drop unused GCS write grant and dead lifecycle rule

* Fix restore runbook, DLM snapshot tagging, README cleanup, and gsutil prompt

* Fix restore runbook: trailing-dot cp idiom and Glacier restore step

* Rename GCS service account to match read-only permissions

* Add 4 GiB ephemeral storage to verification Lambda

Monthly restore-test downloads and extracts the full dump tarball
in /tmp. As the dump grows with LFS data, the default 512 MB will
eventually cause ENOSPC failures.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-14 18:08:06 -04:00
Adam Moussa
6ccfc1c506
Update README with backup, autodiscovery, and token management docs (#1)
Some checks failed
Deploy / deploy (push) Has been cancelled
Add documentation for S3 backups with Glacier lifecycle, hourly
autodiscovery of new GitHub org repos, daily PAT token refresh,
PAT rotation procedure, and Secrets Manager secret inventory.
2026-05-11 19:03:42 -04:00
Adam Moussa
ba937f1b83 Add autodiscovery and token refresh crons
Autodiscovery runs hourly — creates Forgejo mirrors for new GitHub
org repos. Token refresh runs daily — propagates the current PAT
from Secrets Manager to all mirror git remotes.
2026-05-11 18:46:25 -04:00
Adam Moussa
2f344ac7c0 Add nightly S3 backups with Glacier lifecycle
Some checks are pending
Deploy / deploy (push) Waiting to run
S3 bucket for Forgejo dumps (Standard 30d → Glacier, expire 365d).
Cron runs forgejo dump at 5 AM UTC and uploads to S3.
2026-05-11 18:26:26 -04:00
Adam Moussa
0a4119880e Update README for ALB-backed HTTPS setup 2026-05-11 18:13:54 -04:00
Adam Moussa
ed41fd4eac Add ALB egress rule for Forgejo target group
ALB security group has restricted outbound — needed explicit
egress to the Forgejo SG on port 3000 for health checks.
2026-05-11 18:13:21 -04:00
Adam Moussa
9e0a14e5b8 Route through seahaven-com ALB for HTTPS
Add target group, listener rule (forgejo.seahaven.com), and alias
the Route53 record to the ALB. SSL termination via wildcard cert.
2026-05-11 18:08:36 -04:00
Adam Moussa
83c381b1da Fix subnet import to include availability zone
CDK requires availabilityZone when using fromSubnetAttributes
for EC2 instance placement.
2026-05-11 17:58:14 -04:00
Adam Moussa
a500d69716 Add Forgejo CDK stack
EC2 (t4g.small, arm64) in private subnet with VPN-only access,
DLM nightly snapshots, and Route53 DNS at forgejo.seahaven.com.
2026-05-11 17:52:37 -04:00