Files
shared-memory/docker-compose.external-db.yml
T
shadowdaoandClaude Opus 4.7 d1d4c60f2d fix: address Phase-5 code review (4 findings)
Reviewer flagged two security-relevant items and two operational bugs
on the external-DB + Terraform module merge.

1. Terraform: `enable_execute_command = true` was hardcoded on the app
   and embedder services. Production attack surface (anyone with
   `ecs:ExecuteCommand` on the service gets a container shell) AND
   non-functional today since the task roles have no `ssmmessages:*`
   permission. Added a new `enable_execute_command` boolean input
   variable defaulting to `false`; when flipped on, the SSM messages
   policy is conditionally attached to both task roles so the feature
   actually works. README's variable description tells operators to
   flip on for incidents, off afterward.

2. Terraform: `secret_arns` output was not marked `sensitive`. The ARNs
   themselves aren't secrets, but the embedded secret names print to
   `terraform apply` stdout and CI logs. Marked sensitive on both the
   module output and the example output. Operators wanting the values
   can still `terraform output -json secret_arns`.

3. Terraform: embedder task definition was missing `HOST=0.0.0.0` and
   `PORT=8080`. Fargate awsvpc tasks each get their own ENI; default
   Node HTTP servers bind 127.0.0.1, which would make every
   app→embedder Service Connect call time out. Added both vars to
   `embedder_environment`. Also added `NEXT_TELEMETRY_DISABLED=1` to
   `app_environment` per the spec's hardening checklist.

4. Compose: docker-compose.external-db.yml uses the `!override` YAML
   tag, which requires Docker Compose >= 2.24.0. Silently ignored on
   older Compose, causing the `db` dependency to survive the merge and
   startup to fail. Documented the minimum version in the override
   file's header AND in the main README prerequisites with a deep
   link to the External Postgres section.

terraform fmt + validate (module + examples/basic) both clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 09:48:04 -07:00

62 lines
2.9 KiB
YAML

# =============================================================================
# shared-memory — external Postgres override.
#
# Use this override when you want to point the app at a managed Postgres
# (AWS RDS, GCP Cloud SQL, Azure Database for PostgreSQL, your own VM, ...)
# instead of the bundled `db` container.
#
# Invocation (always together with the base file):
#
# docker compose -f docker-compose.yml -f docker-compose.external-db.yml up -d
#
# The caller MUST set `DATABASE_URL` explicitly in `.env` so that `migrator`
# and `app` know where to connect. The `POSTGRES_*` variables are not used
# in this mode (the bundled `db` service is disabled below). Example:
#
# DATABASE_URL=postgres://memory:STRONG_PASSWORD@your-rds.region.rds.amazonaws.com:5432/memory?sslmode=require
#
# The DB user needs privileges to `CREATE EXTENSION` for pgvector, pg_trgm,
# and pgcrypto on first run — on RDS that means the `rds_superuser` role, or
# pre-create the extensions yourself. See README "External Postgres".
#
# REQUIRES DOCKER COMPOSE >= 2.24.0 (Docker Desktop >= 4.25, or Compose plugin
# 2.24.0+). The `!override` YAML tag on the depends_on blocks below is what
# fully replaces — rather than merges — the base file's `depends_on: db`
# entries. On older Compose the tag is silently ignored, the `db` dependency
# survives the merge, and startup fails with "depends on undefined service
# db". Check with: docker compose version
# =============================================================================
services:
db:
# Park the bundled DB on a profile that nothing ever enables. Compose
# only starts services whose profile list is empty OR matches a
# `--profile` flag on the command line. "never" is not a magic name —
# it's just a label we promise not to pass, so the service stays down.
profiles: ["never"]
migrator:
# Docker compose merges `depends_on` by key — listing `embedder` here
# alone would keep the base file's `db` entry and break with
# "depends on undefined service db". The `!override` tag (compose 2.24+)
# replaces the whole block instead of merging.
depends_on: !override
embedder:
condition: service_healthy
environment:
# The base file hardcodes DATABASE_URL to point at the bundled `db`
# service. Override it to pass through whatever the operator set in
# `.env` (e.g. an RDS endpoint with sslmode=require).
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL not set in .env (required with external-db override)}
app:
# Same merge caveat as above — fully replace the block, keep embedder
# and migrator deps.
depends_on: !override
embedder:
condition: service_healthy
migrator:
condition: service_completed_successfully
environment:
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL not set in .env (required with external-db override)}