7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
253 lines
9.0 KiB
Python
253 lines
9.0 KiB
Python
"""
|
|
Tests for web/auth/session_cleanup.py
|
|
|
|
Tests cover:
|
|
- cleanup_stale_sessions() function
|
|
- Skip conditions (should_skip, no username, user connected, temp_auth_token, no encryption)
|
|
- Session clearing behavior (no session_id, session_id with no password, session_id with password)
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from flask import Flask, session
|
|
|
|
|
|
def _make_app():
|
|
"""Create a minimal Flask test app with a secret key."""
|
|
app = Flask(__name__)
|
|
app.secret_key = "test-secret-key"
|
|
return app
|
|
|
|
|
|
class TestCleanupStaleSessions:
|
|
"""Tests for cleanup_stale_sessions function."""
|
|
|
|
def test_skips_when_should_skip_returns_true(self):
|
|
"""Should return immediately when should_skip_session_cleanup() is True."""
|
|
app = _make_app()
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=True,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
):
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
cleanup_stale_sessions()
|
|
# db_manager should never be consulted
|
|
mock_db.is_user_connected.assert_not_called()
|
|
# Session should remain intact
|
|
assert session.get("username") == "testuser"
|
|
|
|
def test_does_nothing_when_no_username_in_session(self):
|
|
"""Should do nothing when session has no username."""
|
|
app = _make_app()
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
):
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
# No username set in session
|
|
cleanup_stale_sessions()
|
|
mock_db.is_user_connected.assert_not_called()
|
|
|
|
def test_does_nothing_when_user_is_connected(self):
|
|
"""Should do nothing when db_manager.is_user_connected returns True."""
|
|
app = _make_app()
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
):
|
|
mock_db.is_user_connected.return_value = True
|
|
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
cleanup_stale_sessions()
|
|
# Session should remain intact
|
|
assert session.get("username") == "testuser"
|
|
|
|
def test_does_nothing_when_temp_auth_token_exists(self):
|
|
"""Should not clear session when temp_auth_token is present (recovery possible)."""
|
|
app = _make_app()
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
):
|
|
mock_db.is_user_connected.return_value = False
|
|
mock_db.has_encryption = True
|
|
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
session["temp_auth_token"] = "some-recovery-token"
|
|
cleanup_stale_sessions()
|
|
# Session should remain intact
|
|
assert session.get("username") == "testuser"
|
|
|
|
def test_does_nothing_when_db_has_no_encryption(self):
|
|
"""Should not clear session when db_manager.has_encryption is False."""
|
|
app = _make_app()
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
):
|
|
mock_db.is_user_connected.return_value = False
|
|
mock_db.has_encryption = False
|
|
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
cleanup_stale_sessions()
|
|
# Session should remain intact because encryption is off
|
|
assert session.get("username") == "testuser"
|
|
|
|
def test_clears_session_when_no_session_id_and_no_recovery(self):
|
|
"""Should clear session when there is no session_id (no way to recover)."""
|
|
app = _make_app()
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
):
|
|
mock_db.is_user_connected.return_value = False
|
|
mock_db.has_encryption = True
|
|
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
# No session_id, no temp_auth_token
|
|
cleanup_stale_sessions()
|
|
# Session should be cleared
|
|
assert session.get("username") is None
|
|
|
|
def test_clears_session_when_session_id_but_no_password_in_store(self):
|
|
"""Should clear session when session_id exists but password store has no password."""
|
|
app = _make_app()
|
|
|
|
mock_password_store = MagicMock()
|
|
mock_password_store.get_session_password.return_value = None
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
patch(
|
|
"local_deep_research.database.session_passwords.session_password_store",
|
|
mock_password_store,
|
|
),
|
|
):
|
|
mock_db.is_user_connected.return_value = False
|
|
mock_db.has_encryption = True
|
|
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
session["session_id"] = "sess-abc-123"
|
|
cleanup_stale_sessions()
|
|
# Session should be cleared
|
|
assert session.get("username") is None
|
|
mock_password_store.get_session_password.assert_called_once_with(
|
|
"testuser", "sess-abc-123"
|
|
)
|
|
|
|
def test_does_not_clear_session_when_password_found_in_store(self):
|
|
"""Should NOT clear session when password IS found in the session password store."""
|
|
app = _make_app()
|
|
|
|
mock_password_store = MagicMock()
|
|
mock_password_store.get_session_password.return_value = (
|
|
"stored-password"
|
|
)
|
|
|
|
with (
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup",
|
|
return_value=False,
|
|
),
|
|
patch(
|
|
"local_deep_research.web.auth.session_cleanup.db_manager"
|
|
) as mock_db,
|
|
patch(
|
|
"local_deep_research.database.session_passwords.session_password_store",
|
|
mock_password_store,
|
|
),
|
|
):
|
|
mock_db.is_user_connected.return_value = False
|
|
mock_db.has_encryption = True
|
|
|
|
from local_deep_research.web.auth.session_cleanup import (
|
|
cleanup_stale_sessions,
|
|
)
|
|
|
|
with app.test_request_context("/"):
|
|
session["username"] = "testuser"
|
|
session["session_id"] = "sess-abc-123"
|
|
cleanup_stale_sessions()
|
|
# Session should remain intact
|
|
assert session.get("username") == "testuser"
|
|
assert session.get("session_id") == "sess-abc-123"
|
|
mock_password_store.get_session_password.assert_called_once_with(
|
|
"testuser", "sess-abc-123"
|
|
)
|