fix(store): migration 012 — back-fill auto_summarize via RLS bypass
CI / Lint / Test / Vet (push) Successful in 12s
CI / Build & Import (push) Successful in 11s

Migration 011's UPDATE ran without tapir.current_user_id set, so FORCE RLS
blocked all rows and 0 users were updated (skipped_manual=607 in scheduler).
Migration 012 temporarily drops FORCE so the table owner can run the UPDATE,
then restores it.
This commit is contained in:
2026-06-06 10:01:13 +02:00
parent f35c2a85a5
commit 940f80899a
3 changed files with 27 additions and 4 deletions
+20 -4
View File
@@ -53,15 +53,16 @@ func TestMigration010LoginEventsUpDown(t *testing.T) {
require.True(t, loginEventsExists(t), "login_events must exist at latest migration") require.True(t, loginEventsExists(t), "login_events must exist at latest migration")
m := fileMigrator(t) m := fileMigrator(t)
// 011 (auto_summarize default) sits above 010; step it down first so the // 011 and 012 sit above 010; step them down first so 010 is exercised in isolation.
// 010 down/up is exercised in isolation. require.NoError(t, m.Steps(-1), "down 012 is a no-op, login_events intact")
require.True(t, loginEventsExists(t), "012 down leaves login_events intact")
require.NoError(t, m.Steps(-1), "down 011 must not touch login_events") require.NoError(t, m.Steps(-1), "down 011 must not touch login_events")
require.True(t, loginEventsExists(t), "011 down leaves login_events intact") require.True(t, loginEventsExists(t), "011 down leaves login_events intact")
require.NoError(t, m.Steps(-1), "down 010 must drop login_events") require.NoError(t, m.Steps(-1), "down 010 must drop login_events")
require.False(t, loginEventsExists(t), "login_events must be gone after the down migration") require.False(t, loginEventsExists(t), "login_events must be gone after the down migration")
require.NoError(t, m.Steps(2), "up must recreate 010 then re-apply 011") require.NoError(t, m.Steps(3), "up must recreate 010 then re-apply 011 and 012")
require.True(t, loginEventsExists(t), "login_events must be restored after the up migration") require.True(t, loginEventsExists(t), "login_events must be restored after the up migration")
} }
@@ -80,13 +81,28 @@ func autoSummarizeDefault(t *testing.T) string {
// up sets the auto_summarize column default to TRUE (ADR-018), down restores // up sets the auto_summarize column default to TRUE (ADR-018), down restores
// FALSE. The down intentionally does not revert existing rows — only the default. // FALSE. The down intentionally does not revert existing rows — only the default.
func TestMigration011AutoSummarizeDefaultUpDown(t *testing.T) { func TestMigration011AutoSummarizeDefaultUpDown(t *testing.T) {
newStore(t) // latest (011 applied) newStore(t) // latest (012 applied)
require.Equal(t, "true", autoSummarizeDefault(t), "011 sets the default to TRUE") require.Equal(t, "true", autoSummarizeDefault(t), "011 sets the default to TRUE")
m := fileMigrator(t) m := fileMigrator(t)
require.NoError(t, m.Steps(-1), "down 012 is a no-op")
require.NoError(t, m.Steps(-1), "down 011 reverts the column default") require.NoError(t, m.Steps(-1), "down 011 reverts the column default")
require.Equal(t, "false", autoSummarizeDefault(t), "default is FALSE after the down migration") require.Equal(t, "false", autoSummarizeDefault(t), "default is FALSE after the down migration")
require.NoError(t, m.Steps(1), "up 011 re-applies the TRUE default") require.NoError(t, m.Steps(1), "up 011 re-applies the TRUE default")
require.Equal(t, "true", autoSummarizeDefault(t)) require.Equal(t, "true", autoSummarizeDefault(t))
require.NoError(t, m.Steps(1), "up 012 runs clean (no FORCE RLS on fresh schema)")
}
// TestMigration012FixAutoSummarizeRLS proves 012 runs cleanly and flips any
// remaining auto_summarize=FALSE rows to TRUE (the back-fill blocked by RLS in 011).
func TestMigration012FixAutoSummarizeRLS(t *testing.T) {
newStore(t) // apply all migrations including 012
require.Equal(t, "true", autoSummarizeDefault(t), "column default is TRUE after 012")
// Round-trip: down 012, then up 012 — must be idempotent.
m := fileMigrator(t)
require.NoError(t, m.Steps(-1), "down 012 must not error")
require.NoError(t, m.Steps(1), "up 012 must re-apply cleanly")
require.Equal(t, "true", autoSummarizeDefault(t), "default still TRUE after 012 re-applied")
} }
@@ -0,0 +1 @@
-- No data revert: do not flip users back to manual on rollback.
@@ -0,0 +1,6 @@
-- Migration 011's UPDATE ran without tapir.current_user_id set, so FORCE RLS
-- blocked all rows and zero users were updated. Temporarily drop FORCE so the
-- table owner (tapir role) can bypass RLS for this back-fill, then restore it.
ALTER TABLE users NO FORCE ROW LEVEL SECURITY;
UPDATE users SET auto_summarize = TRUE WHERE auto_summarize = FALSE;
ALTER TABLE users FORCE ROW LEVEL SECURITY;