From e7607a0f3c5d3857ad11e7a5ec1ca794db949092 Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Mon, 27 Jul 2026 20:44:31 +0200 Subject: [PATCH] test(auth): define bootstrap and session expiry contracts --- tests/security/test_session_security.py | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/security/test_session_security.py diff --git a/tests/security/test_session_security.py b/tests/security/test_session_security.py new file mode 100644 index 0000000..e55df0f --- /dev/null +++ b/tests/security/test_session_security.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import importlib +from datetime import UTC, datetime, timedelta + +import pytest + +PASSWORD = "correct horse battery staple" + + +@pytest.mark.asyncio +async def test_remote_setup_requires_bootstrap_secret(tmp_path) -> None: + conftest = importlib.import_module("conftest") + app_module = importlib.import_module("backup_tool.api.app") + settings = conftest.make_settings(tmp_path).model_copy( + update={"public_base_url": "https://backup.example.test", "bootstrap_secret": "bootstrap"} + ) + cli = importlib.import_module("backup_tool.cli") + from alembic import command + from httpx import ASGITransport, AsyncClient + + command.upgrade(cli.build_alembic_config(settings), "head") + app = app_module.create_app(settings) + async with AsyncClient(transport=ASGITransport(app=app), base_url="https://backup.example.test") as client: + denied = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD}) + assert denied.status_code == 403 + accepted = await client.post("/api/v2/setup", json={"username": "admin", "password": PASSWORD, "bootstrap_secret": "bootstrap"}) + assert accepted.status_code == 201 + await app.state.engine.dispose() + + +def test_expired_session_is_rejected(tmp_path) -> None: + auth = importlib.import_module("backup_tool.security.auth") + key = tmp_path / "master.key" + key.write_bytes(b"x" * 32) + expired = auth.sign_session("user", "csrf", key, expires_at=datetime.now(UTC) - timedelta(seconds=1), session_id="session") + assert auth.verify_session(expired, key) is None