Skip to content

Commit b20904a

Browse files
committed
fix: gauntlet cycle 3 must-fixes for PR-5.1.5 (operator-runbook drift)
Cycle 3 surfaced operator-facing doc drift from this PR adding the requires-superuser marker to 006/007 (the same class as cycle 2's migrations/README.md fix, in the sibling infra runbooks): - benchmarks-website/infra/README.md bootstrap section no longer claims only 001/002/003 are master-applied with later additive migrations run as migrator; it now names the in-file marker as authoritative and points to migrations/README.md's bootstrap-ordering contract (002/004/005 + 006/007). - benchmarks-website/infra/provision.sh's operator handoff no longer lists only "002 + 004" as master-applied; it instructs applying every marked migration as master and references the migration docs so the list cannot drift again. Plus the cycle-3 should-fixes: - test_real_bootstrap_migrations_carry_superuser_marker now pins the marker on 006/007 too, so a future marker removal fails the suite. - migrations/README.md re-stamp note states the real privilege requirement (UPDATE on query_measurements AND SELECT on commits). - The commit_timestamp write-path test asserts over ALL rows (count of unstamped/drifted == 0) instead of an arbitrary fetchone row. - Aligned a misindented UNION arm in the filter-universe formats query. Deferred (nit): trimming the summary.ts skip-scan comment block (it documents load-bearing non-obvious planner behavior, not a hack). This is the final inner-loop cycle (project ~3-cycle cap); all cycle-3 findings are resolved. The fixes touch operator docs + tests only, no production logic. Signed-off-by: "Connor Tsui" <connor@spiraldb.com>
1 parent cbe2b97 commit b20904a

6 files changed

Lines changed: 50 additions & 28 deletions

File tree

benchmarks-website/infra/README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,26 @@ export PGSSLROOTCERT=/tmp/rds-global-bundle.pem
156156
uv run --no-project scripts/migrate-schema.py apply
157157
```
158158

159-
This applies `001` (schema), `002` (creates the `migrator` role + binds it to
160-
`rds_iam`), and `003` (grants `migrator` SELECT + INSERT on the
161-
`_applied_migrations` ledger). After the bootstrap, subsequent *additive*
159+
This applies `001` (schema) and every migration carrying the
160+
`-- migrate-schema: requires-superuser` marker — currently `002`/`004`/`005`
161+
(role creation + grants) and `006`/`007` (DDL on the master-owned
162+
`query_measurements` table). The marker in each file is authoritative; the
163+
runner refuses to apply a marked file under a non-master role. The single source
164+
of truth for the bootstrap-ordering contract is
165+
[`migrations/README.md`](../../migrations/README.md) § "Bootstrap ordering —
166+
`requires-superuser` migrations"; apply every marked migration as the master
167+
here. `003` (a ledger grant) carries no marker. After the bootstrap, *unmarked*
162168
migrations are applied by the `schema-deploy` workflow as `migrator` against the
163169
public instance endpoint (`RDS_BENCH_INSTANCE_ENDPOINT`) with direct IAM; the
164-
master password is not needed again.
170+
master password is not needed again for those.
165171

166172
Because the bootstrap runs as master, the schema objects and the ledger are
167173
master-owned; `003` grants `migrator` the ledger access it needs to record and
168174
read applied migrations. A migration that `ALTER`s or adds an index to an
169-
existing master-owned table (rather than only `CREATE`-ing new objects) needs
170-
the role-ownership model resolved first -- deferred to PR-2.1 alongside the
171-
ingest-role design (which also grants the six data tables' DML for the ingest
172-
write path). Phase-1 migrations are all additive (new objects), so `migrator`'s
173-
`CREATE` on the schema suffices today.
175+
existing master-owned table (rather than only `CREATE`-ing new objects) must
176+
itself carry the `requires-superuser` marker and be master-applied here — this
177+
is what `006`/`007` do (PR-5.1.5). `migrator`'s `CREATE` on the schema suffices
178+
only for new-object migrations.
174179

175180
The per-PR testcontainer migration test (`scripts/test_migrate_schema.py`)
176181
applies every migration as a single owning role, so it does NOT model the

benchmarks-website/infra/provision.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -611,9 +611,13 @@ NEXT STEPS:
611611
612612
4. Migrations create the Postgres '${PG_MIGRATOR_ROLE}' (002) and
613613
'${PG_INGEST_ROLE}' (004) users; both OIDC roles' permission policies are
614-
already scoped to those users. Apply 002 + 004 as the RDS master during the
615-
one-time bootstrap (they create roles and grant on master-owned tables), after
616-
which schema deploys run as '${PG_MIGRATOR_ROLE}'.
614+
already scoped to those users. During the one-time bootstrap, apply EVERY
615+
migration carrying the '-- migrate-schema: requires-superuser' marker as the
616+
RDS master (currently 002/004/005, which create roles + grants, and 006/007,
617+
which run DDL on the master-owned query_measurements table). The marker in
618+
each file is authoritative; see benchmarks-website/migrations/README.md
619+
'Bootstrap ordering' for the contract. After the bootstrap, unmarked schema
620+
deploys run as '${PG_MIGRATOR_ROLE}'.
617621
618622
=========================================================================
619623
EOF

benchmarks-website/web/lib/queries.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ export async function collectFilterUniverse(): Promise<FilterUniverse> {
12311231
LIMIT 1
12321232
) nxt
12331233
)
1234-
SELECT value FROM qm_formats
1234+
SELECT value FROM qm_formats
12351235
UNION SELECT format AS value FROM compression_times WHERE format IS NOT NULL
12361236
UNION SELECT format AS value FROM compression_sizes WHERE format IS NOT NULL
12371237
UNION SELECT format AS value FROM random_access_times WHERE format IS NOT NULL`,

migrations/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ read-service identity), and `006`/`007` in PR-5.1.5 (read-path perf).
7777
`commits.timestamp` (006). Writers stamp it at insert; 006 backfilled
7878
pre-existing rows. If rows are ever observed unstamped or drifted (a writer
7979
predating the stamp, or a commits re-ingest that changed a timestamp), the
80-
repair is the drift-tolerant form of the backfill, run as any role with UPDATE
81-
on the table:
80+
repair is the drift-tolerant form of the backfill. Run it as a role that holds
81+
`UPDATE` on `query_measurements` **and** `SELECT` on `commits` (the `FROM
82+
commits` clause reads `commits.timestamp`) — the RDS master, or any role granted
83+
both; the least-privilege `bench_read` role cannot run it:
8284

8385
```sql
8486
UPDATE query_measurements q

scripts/test_migrate_schema.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,15 +1712,22 @@ def test_migration_requires_superuser_false_without_exact_marker() -> None:
17121712

17131713

17141714
def test_real_bootstrap_migrations_carry_superuser_marker() -> None:
1715-
"""002 + 004 + 005 (role/grant bootstrap) are marked; 001 + 003 (additive / owned-grant) are not."""
1715+
"""002/004/005 (role/grant bootstrap) + 006/007 (master-owned-table DDL) are marked;
1716+
001 + 003 (additive / owned-grant) are not."""
17161717
by_name = {
17171718
p.name: p.read_text(encoding="utf-8") for p in runner.discover(REPO_MIGRATIONS_DIR)
17181719
}
1719-
for marked in ("002_iam_db_user.sql", "004_ingest_role.sql", "005_read_role.sql"):
1720+
for marked in (
1721+
"002_iam_db_user.sql",
1722+
"004_ingest_role.sql",
1723+
"005_read_role.sql",
1724+
"006_read_path_perf.sql",
1725+
"007_summary_covering_index.sql",
1726+
):
17201727
assert marked in by_name, f"expected {marked} in migrations/"
17211728
assert runner._migration_requires_superuser(by_name[marked]), (
1722-
f"{marked} creates roles / runs ALTER DEFAULT PRIVILEGES and must carry the "
1723-
"requires-superuser marker"
1729+
f"{marked} creates roles / runs ALTER DEFAULT PRIVILEGES / ALTERs a master-owned "
1730+
"table and must carry the requires-superuser marker"
17241731
)
17251732
for unmarked in ("001_initial_schema.sql", "003_migrator_ledger_grant.sql"):
17261733
assert unmarked in by_name, f"expected {unmarked} in migrations/"

scripts/test_post_ingest_postgres.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -309,21 +309,25 @@ def test_query_measurement_insert_populates_commit_timestamp(schema_conn: psycop
309309
writer never depend on the post-deploy re-backfill."""
310310
commit = _sample_commit()
311311
records = [r for r in _sample_records() if r["kind"] == "query_measurement"]
312+
assert records, "expected at least one query_measurement sample record"
313+
314+
def _unstamped_or_drifted() -> int:
315+
# Count rows that are NOT stamped to their commit's timestamp -- 0 means every
316+
# query_measurements row was correctly stamped (not just an arbitrary fetchone row).
317+
return schema_conn.execute(
318+
"SELECT count(*) FROM query_measurements q JOIN commits c USING (commit_sha)"
319+
" WHERE q.commit_timestamp IS NULL OR q.commit_timestamp <> c.timestamp"
320+
).fetchone()[0]
312321

313322
post_ingest.ingest_postgres(schema_conn, commit, records)
314-
row = schema_conn.execute(
315-
"SELECT q.commit_timestamp, c.timestamp FROM query_measurements q"
316-
" JOIN commits c USING (commit_sha)"
317-
).fetchone()
318-
assert row[0] is not None
319-
assert row[0] == row[1]
323+
assert _count(schema_conn, "query_measurements") == len(records)
324+
assert _unstamped_or_drifted() == 0
320325

321326
# The update path re-stamps as well: scrub the column, re-ingest the same envelope (an
322-
# ON CONFLICT DO UPDATE), and the timestamp must come back.
327+
# ON CONFLICT DO UPDATE), and every row's timestamp must come back.
323328
schema_conn.execute("UPDATE query_measurements SET commit_timestamp = NULL")
324329
post_ingest.ingest_postgres(schema_conn, commit, records)
325-
restamped = schema_conn.execute("SELECT commit_timestamp FROM query_measurements").fetchone()[0]
326-
assert restamped == row[1]
330+
assert _unstamped_or_drifted() == 0
327331

328332

329333
# Per-kind mutation of every value/side-counter/env column each table's ON

0 commit comments

Comments
 (0)