Files
wehub-resource-sync 7a0da7932b
Backwards Compatibility / Verify Encryption Constants (push) Waiting to run
Backwards Compatibility / PyPI Version Compatibility (push) Waiting to run
Backwards Compatibility / Database Migration Tests (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Blocked by required conditions
Docker Tests (Consolidated) / detect-changes (push) Waiting to run
Docker Tests (Consolidated) / Build Test Image (push) Waiting to run
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Blocked by required conditions
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Blocked by required conditions
Docker Tests (Consolidated) / Accessibility Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Unit Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / LLM Example Tests (push) Blocked by required conditions
Docker Tests (Consolidated) / Production Image Smoke Test (push) Blocked by required conditions
Docker Tests (Consolidated) / Infrastructure Tests (push) Blocked by required conditions
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Waiting to run
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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

184 lines
5.8 KiB
Python

"""
Tests for encryption key passing to background threads.
Verifies that research threads can access encrypted databases with the correct password.
"""
import threading
import pytest
from unittest.mock import patch
from tests.test_utils import add_src_to_path
add_src_to_path()
class TestThreadContextPasswordStorage:
"""Test that thread context correctly stores and retrieves passwords."""
def test_set_and_get_password_in_same_thread(self):
"""Password set via set_search_context should be retrievable."""
from local_deep_research.utilities.thread_context import (
set_search_context,
get_search_context,
)
set_search_context(
{
"username": "test_user",
"user_password": "secret123",
}
)
ctx = get_search_context()
assert ctx is not None
assert ctx.get("user_password") == "secret123"
def test_context_includes_all_fields(self):
"""All fields in context should be preserved."""
from local_deep_research.utilities.thread_context import (
set_search_context,
get_search_context,
)
context = {
"research_id": "res_123",
"username": "alice",
"user_password": "pass456",
"custom_field": "custom_value",
}
set_search_context(context)
retrieved = get_search_context()
assert retrieved["research_id"] == "res_123"
assert retrieved["username"] == "alice"
assert retrieved["user_password"] == "pass456"
assert retrieved["custom_field"] == "custom_value"
class TestThreadContextIsolation:
"""Test that thread context is properly isolated between threads."""
def test_child_thread_does_not_inherit_context(self):
"""A new thread should NOT see the parent thread's context."""
from local_deep_research.utilities.thread_context import (
set_search_context,
get_search_context,
)
child_result = []
def child_thread():
ctx = get_search_context()
child_result.append(ctx)
# Set context in main thread
set_search_context({"user_password": "main_thread_pass"})
# Child thread should not see it
thread = threading.Thread(target=child_thread)
thread.start()
thread.join(timeout=2)
assert child_result[0] is None, (
"Child thread should not inherit parent's context"
)
def test_child_thread_can_set_own_context(self):
"""A child thread can set and retrieve its own context."""
from local_deep_research.utilities.thread_context import (
set_search_context,
get_search_context,
)
child_result = []
def child_thread():
set_search_context({"user_password": "child_pass"})
ctx = get_search_context()
child_result.append(ctx)
thread = threading.Thread(target=child_thread)
thread.start()
thread.join(timeout=2)
assert child_result[0] is not None
assert child_result[0]["user_password"] == "child_pass"
class TestGetUserDbSessionPasswordRetrieval:
"""Test that get_user_db_session retrieves password from thread context."""
def test_password_retrieved_from_thread_context(self):
"""get_user_db_session should use password from thread context."""
from local_deep_research.utilities.thread_context import (
set_search_context,
)
from local_deep_research.database.session_context import (
get_user_db_session,
)
from local_deep_research.database.encrypted_db import db_manager
from local_deep_research.database import thread_local_session
set_search_context(
{
"username": "test_user",
"user_password": "thread_context_password",
}
)
captured_passwords = []
def capture(username, password):
captured_passwords.append(password)
raise Exception("Captured")
with patch(
"local_deep_research.database.session_context.has_app_context",
return_value=False,
):
with patch.object(db_manager, "has_encryption", True):
with patch.object(
thread_local_session,
"get_metrics_session",
side_effect=capture,
):
try:
with get_user_db_session("test_user"):
pass
except Exception:
pass
assert len(captured_passwords) == 1
assert captured_passwords[0] == "thread_context_password"
def test_none_password_causes_error_with_encryption(self):
"""If password is None and encryption is enabled, should raise error."""
from local_deep_research.utilities.thread_context import (
set_search_context,
)
from local_deep_research.database.session_context import (
get_user_db_session,
DatabaseSessionError,
)
from local_deep_research.database.encrypted_db import db_manager
# Set context with None password
set_search_context(
{
"username": "test_user",
"user_password": None,
}
)
with patch(
"local_deep_research.database.session_context.has_app_context",
return_value=False,
):
with patch.object(db_manager, "has_encryption", True):
with pytest.raises(DatabaseSessionError) as exc_info:
with get_user_db_session("test_user"):
pass
assert "requires password" in str(exc_info.value).lower()