fix(backup): refuse another schema before reading the dump; tests read settings directly (#5815)
CI / lint (push) Successful in 3s
CI / integration (push) Successful in 1m25s
CI / unit (push) Successful in 1m39s
CI / publish (push) Successful in 1m11s

- restore_in_place checks the backup's migration heads before pg_restore
  writes anything, so a backup from another schema is refused at once.
- The integration tests read their own setting rows directly:
  get_all_settings knows only Steward's own keys.
- check.py: drop an import left unused by the move to pgdata.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 10:56:57 -04:00
co-authored by Claude Opus 5.5
parent aab8581f20
commit 9e5f6e183a
3 changed files with 24 additions and 11 deletions
@@ -47,6 +47,17 @@ async def _snapshot(app) -> bytes:
return script_from(blocks)
async def _setting(app, key):
"""A setting's stored value (get_all_settings knows only Steward's own keys)."""
import json
from sqlalchemy import select
from steward.models.settings import AppSetting
async with app.db_sessionmaker() as s:
raw = (await s.execute(select(AppSetting.value_json).where(AppSetting.key == key))).scalar_one()
return json.loads(raw)
async def _backup_file(app, tmp_path, heads=None):
from steward.backup import dump, job
(tmp_path / "steward.dump").write_bytes(b"PGDMP")
@@ -61,7 +72,7 @@ def test_a_backup_goes_back_in_place_and_history_stays(app, monkeypatch, tmp_pat
from sqlalchemy import func, select
from steward.backup import pgdata
from steward.backup.restore import restore_in_place
from steward.core.settings import get_all_settings, set_setting
from steward.core.settings import set_setting
from steward.models.alerts import AlertEvent, AlertOperator, AlertRule
from steward.models.audit import AuditEvent
from steward.models.hosts import Host
@@ -110,8 +121,8 @@ def test_a_backup_goes_back_in_place_and_history_stays(app, monkeypatch, tmp_pat
done = await restore_in_place(path, app.config["DATABASE_URL"])
settings = {k: await _setting(app, k) for k in (setting, "backup.last_attempt_at")}
async with app.db_sessionmaker() as s:
settings = await get_all_settings(s)
hosts = set((await s.execute(select(Host.id).where(
Host.id.in_([ids["kept_host"], ids["new_host"]])))).scalars())
events = dict((await s.execute(select(AlertEvent.rule_id, func.count()).where(
@@ -135,7 +146,7 @@ def test_a_restore_that_fails_part_way_changes_nothing(app, monkeypatch, tmp_pat
from steward.backup import pgdata
from steward.backup.dump import BackupError
from steward.backup.restore import restore_in_place
from steward.core.settings import get_all_settings, set_setting
from steward.core.settings import set_setting
tag = uuid.uuid4().hex[:8]
setting = f"test.undone_{tag}"
@@ -158,8 +169,7 @@ def test_a_restore_that_fails_part_way_changes_nothing(app, monkeypatch, tmp_pat
await set_setting(s, setting, "changed")
with pytest.raises(BackupError, match="undone, nothing changed"):
await restore_in_place(path, app.config["DATABASE_URL"])
async with app.db_sessionmaker() as s:
return (await get_all_settings(s))[setting]
return await _setting(app, setting)
assert asyncio.run(_go()) == "changed"