From 175a550c7be5c2c7aa2adadedcc88bb374c750bb Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Mon, 27 Jul 2026 21:01:04 +0200 Subject: [PATCH] fix(auth): persist sessions and lock remote setup --- backend/alembic/versions/0002_sessions.py | 1 - tests/conftest.py | 4 ++-- tests/integration/test_migrations.py | 1 + tests/security/test_session_security.py | 21 ++++++++++++++++----- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/backend/alembic/versions/0002_sessions.py b/backend/alembic/versions/0002_sessions.py index c165514..4450cca 100644 --- a/backend/alembic/versions/0002_sessions.py +++ b/backend/alembic/versions/0002_sessions.py @@ -7,7 +7,6 @@ Revises: 0001_v2_baseline from collections.abc import Sequence import sqlalchemy as sa - from alembic import op revision: str = "0002_sessions" diff --git a/tests/conftest.py b/tests/conftest.py index 0222057..b57bbdf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,7 +31,7 @@ def make_settings(tmp_path: Path) -> Any: local_source_roots=(sources,), restore_roots=(restores,), master_key_file=key, - public_base_url="https://testserver", + public_base_url="https://127.0.0.1:8000", ) @@ -42,7 +42,7 @@ async def app_client(tmp_path: Path) -> AsyncIterator[tuple[AsyncClient, Any]]: app_module = importlib.import_module("backup_tool.api.app") app = app_module.create_app(settings) async with AsyncClient( - transport=ASGITransport(app=app), base_url="https://testserver" + transport=ASGITransport(app=app), base_url="https://127.0.0.1:8000" ) as client: yield client, settings await app.state.engine.dispose() diff --git a/tests/integration/test_migrations.py b/tests/integration/test_migrations.py index ad55fc2..1d2142d 100644 --- a/tests/integration/test_migrations.py +++ b/tests/integration/test_migrations.py @@ -28,6 +28,7 @@ EXPECTED_TABLES = { "restores", "schedules", "secrets", + "sessions", "sources", "users", } diff --git a/tests/security/test_session_security.py b/tests/security/test_session_security.py index b17790e..7574657 100644 --- a/tests/security/test_session_security.py +++ b/tests/security/test_session_security.py @@ -80,8 +80,12 @@ async def test_remote_setup_without_configured_bootstrap_fails_closed(tmp_path) ) command.upgrade(cli.build_alembic_config(settings), "head") app = app_module.create_app(settings) - async with AsyncClient(transport=ASGITransport(app=app), base_url=settings.public_base_url) as client: - response = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD}) + async with AsyncClient( + transport=ASGITransport(app=app), base_url=settings.public_base_url + ) as client: + response = await client.post( + "/api/v2/setup", json={"username": "admin", "password": PASSWORD} + ) assert response.status_code == 403 assert response.json()["code"] == "bootstrap_required" await app.state.engine.dispose() @@ -122,10 +126,13 @@ async def test_logout_revocation_survives_app_restart(tmp_path) -> None: local_source_roots=(roots[2],), restore_roots=(roots[3],), master_key_file=key, + public_base_url="https://127.0.0.1:8000", ) command.upgrade(cli.build_alembic_config(settings), "head") app = app_module.create_app(settings) - async with AsyncClient(transport=ASGITransport(app=app), base_url=settings.public_base_url) as client: + async with AsyncClient( + transport=ASGITransport(app=app), base_url=settings.public_base_url + ) as client: setup = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD}) assert setup.status_code == 201 copied_cookie = client.cookies.get("backup_tool_session") @@ -137,7 +144,11 @@ async def test_logout_revocation_survives_app_restart(tmp_path) -> None: await app.state.engine.dispose() restarted = app_module.create_app(settings) - async with AsyncClient(transport=ASGITransport(restarted), base_url=settings.public_base_url) as client: - rejected = await client.get("/api/v2/auth/session", headers={"Cookie": f"backup_tool_session={copied_cookie}"}) + async with AsyncClient( + transport=ASGITransport(restarted), base_url=settings.public_base_url + ) as client: + rejected = await client.get( + "/api/v2/auth/session", headers={"Cookie": f"backup_tool_session={copied_cookie}"} + ) assert rejected.status_code == 401 await restarted.state.engine.dispose()