ci: guard migration immutability against sqlx checksum drift #498

Merged
nrupard merged 1 commit from feat/LC-515-migration-immutability-guard into main 2026-07-01 16:21:39 +02:00
Owner

lets-chat applies its SQLite migrations at runtime via sqlx::migrate!. sqlx checksums each migration on first apply and re-verifies on every start, so modifying, renaming, or deleting a migration already applied to a database makes it refuse to boot (migration N was previously applied but has been modified). LC-212 hit this on a one-line comment change, and the same class took down the mokosh-server v0.4.0 prod deploy on nc-01 (DEV-395). Nothing in CI caught the edit.

Adds ci-build/check-migration-immutability.nu (nushell, mirroring the ci-build/get-tags.nu convention): it diffs server/migrations against the merge-base with origin/main using --diff-filter=MRD and fails (exit 1, naming the offending files and telling the author to add a new migration) if any committed migration was modified, renamed, or deleted. Adding new migration files passes. It fails loud (exit 2) if the diff cannot run, so a shallow clone or missing base ref never silently reads as "nothing changed".

Wired into .forgejo/workflows/check.yml as a fail-fast step before the cargo work, with fetch-depth: 0 on the checkout so the merge-base is available. CLAUDE.md documents the enforcement.

Verified locally against throwaway commits (base origin/main): modify -> exit 1, rename -> exit 1, delete -> exit 1, add new migration -> exit 0, clean -> exit 0, bad/missing base ref -> exit 2. check.yml parses as valid YAML; the runner (RUNS_ON_OPENSUSE_BASE_LATEST) is the same nushell-capable image the sibling guards (menkent, rusty-links, mokosh-server DEV-395) run on.

CI-only change; no Rust touched. Depended on LC-520 (now merged) to green main first.

Fixes LC-515.

lets-chat applies its SQLite migrations at runtime via `sqlx::migrate!`. sqlx checksums each migration on first apply and re-verifies on every start, so modifying, renaming, or deleting a migration already applied to a database makes it refuse to boot (`migration N was previously applied but has been modified`). LC-212 hit this on a one-line comment change, and the same class took down the mokosh-server v0.4.0 prod deploy on nc-01 (DEV-395). Nothing in CI caught the edit. Adds `ci-build/check-migration-immutability.nu` (nushell, mirroring the `ci-build/get-tags.nu` convention): it diffs `server/migrations` against the merge-base with `origin/main` using `--diff-filter=MRD` and fails (exit 1, naming the offending files and telling the author to add a new migration) if any committed migration was modified, renamed, or deleted. Adding new migration files passes. It fails loud (exit 2) if the diff cannot run, so a shallow clone or missing base ref never silently reads as "nothing changed". Wired into `.forgejo/workflows/check.yml` as a fail-fast step before the cargo work, with `fetch-depth: 0` on the checkout so the merge-base is available. CLAUDE.md documents the enforcement. Verified locally against throwaway commits (base `origin/main`): modify -> exit 1, rename -> exit 1, delete -> exit 1, add new migration -> exit 0, clean -> exit 0, bad/missing base ref -> exit 2. `check.yml` parses as valid YAML; the runner (`RUNS_ON_OPENSUSE_BASE_LATEST`) is the same nushell-capable image the sibling guards (menkent, rusty-links, mokosh-server DEV-395) run on. CI-only change; no Rust touched. Depended on LC-520 (now merged) to green `main` first. Fixes LC-515.
ci: guard migration immutability against sqlx checksum drift
All checks were successful
check-secrets / TruffleHog (pull_request) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 6s
check-secrets / Kingfisher (pull_request) Successful in 7s
check-secrets / Nosey parker (push) Successful in 6s
check-secrets / Kingfisher (push) Successful in 8s
check-secrets / TruffleHog (push) Successful in 9s
Check / clippy + fmt + tests (pull_request) Successful in 3m1s
Create release / Create release from merged PR (pull_request) Has been skipped
d3705be85c
lets-chat applies its SQLite migrations at runtime via sqlx::migrate!; sqlx checksums each migration on first apply and re-verifies on every start, so modifying, renaming, or deleting a migration already applied to a database makes it refuse to boot ("migration N was previously applied but has been modified"). LC-212 hit this on a one-line comment change, and the same class took down the mokosh-server v0.4.0 prod deploy on nc-01 (DEV-395). Nothing in CI caught the edit.

Add ci-build/check-migration-immutability.nu (nushell, mirroring the ci-build/get-tags.nu convention): it diffs server/migrations against the merge-base with origin/main with --diff-filter=MRD and fails (exit 1, naming the offending files and telling the author to add a new migration) if any committed migration was modified, renamed, or deleted. Adding new migration files passes. It fails loud (exit 2) if the diff cannot run, so a shallow clone or missing base ref never silently reads as "nothing changed".

Wire it into .forgejo/workflows/check.yml as a fail-fast step before the cargo work, with fetch-depth: 0 on the checkout so the merge-base is available. Document the CI enforcement in CLAUDE.md.

#LC-515

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard scheduled this pull request to auto merge when all checks succeed 2026-07-01 16:20:47 +02:00
nrupard deleted branch feat/LC-515-migration-immutability-guard 2026-07-01 16:21:39 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!498
No description provided.