Skip to content
25 changes: 18 additions & 7 deletions docker/postgres-init/migrate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,26 @@ until pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d
sleep 1
done

# ponytail: gate at the existing 0012 boundary; replace with a migration ledger
# when a new non-idempotent migration family is introduced.
# ponytail: gate at the existing 0012 boundary; replace with a migration
# ledger when a new non-idempotent migration family is introduced.
#
# This used to be an explicit case-pattern whitelist of every file number
# from 0012 up. It silently fell behind as new migrations were added past
# the last-updated number (0103_tenant_settings.sql shipped with no entry
# here, so a fresh deployment never got it) -- a numeric boundary check
# can't go stale the same way. $((10#...)) forces base-10 arithmetic so a
# leading-zero number like "0103" isn't misread as octal.
for migration in /opt/lineageweave/migrations/*.sql; do
[ -f "$migration" ] || continue
migration_name=${migration##*/}
case "$migration_name" in
0012_*|0013_*|0014_*|0015_*|0016_*|0017_*|0018_*|0019_*|0020_*|0021_*|0022_*|0023_*|0024_*|0025_*|0026_*|0027_*|0028_*|0029_*|0030_*|0031_*|0032_*|0033_*|0034_*|0035_*|0036_*|0037_*|0038_*|0039_*|0040_*|0041_*|0042_*|0043_*|0044_*|0045_*|0046_*|0047_*|0048_*|0049_*|0050_*) ;;
0060_*|0100_*|0101_*|0102_*) ;;
*) continue ;;
esac
migration_number=$((10#${migration_name%%_*}))
Comment thread
seonghobae marked this conversation as resolved.
Outdated
# 0001-0011 are the non-idempotent baseline applied only by
# docker-entrypoint-initdb.d when the data directory is created.
# Later idempotent migrations may also be baked into a new image, but
# replay here is required for existing volumes.
if [ "$migration_number" -lt 12 ]; then
continue
fi
Comment thread
seonghobae marked this conversation as resolved.
Outdated
printf 'Applying %s\n' "$migration_name"
psql -X -v ON_ERROR_STOP=1 \
-h "$POSTGRES_HOST" -p "$POSTGRES_PORT" \
Expand Down
14 changes: 12 additions & 2 deletions tests/test_migration_replay.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ def test_migrate_sh_replays_leftover_pair_migration_on_existing_volumes() -> Non
The Dockerfile only bakes migrations into a brand-new Postgres data
directory via docker-entrypoint-initdb.d; any volume created before a
migration existed never gets it unless migrate.sh replays it on every
`docker compose up`. A window starting above 0012 silently leaves
`docker compose up`. A boundary above 12 silently leaves
report_leftover_pair missing on such volumes -- GET
/api/reports/{grouping}/{period} then 500s on undefined_table the
first time a period actually has leftover pairs.

migrate.sh replaced the old explicit `0012_*|0013_*|...` case-pattern
whitelist (which silently fell behind as new migration files were
added, per the ADR this test guards) with a numeric boundary check.
Assert on that mechanism instead of the retired literal token.
"""
script = (
Path(__file__).resolve().parents[1]
Expand All @@ -32,4 +37,9 @@ def test_migrate_sh_replays_leftover_pair_migration_on_existing_volumes() -> Non
/ "migrate.sh"
).read_text(encoding="utf-8")

assert "0012_*" in script
# 0001-0011 are the non-idempotent bootstrap; 0012 and up must replay.
assert '"$migration_number" -lt 12' in script
assert '[ -f "$migration" ] || continue' in script
# Base-10 forced so a leading-zero migration number (e.g. 0103) isn't
# misread as octal.
assert "10#${migration_name%%_*}" in script
4 changes: 3 additions & 1 deletion tests/test_post_content_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,4 +424,6 @@ def test_migration_contains_normalized_job_and_status_event_tables() -> None:

def test_migration_replay_window_includes_post_content_queue() -> None:
migrate = (_ROOT / "docker/postgres-init/migrate.sh").read_text()
assert "0050_*)" in migrate
# migrate.sh replays every migration numbered >= 12 via a numeric
# boundary check (not a per-file whitelist entry); 0050 clears it.
assert '"$migration_number" -lt 12' in migrate
Loading