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

305 lines
11 KiB
Python

"""
Tests for SQLCipher settings and environment variable overrides.
These tests verify that default settings are correct and that
environment variables properly override them.
"""
import shutil
import tempfile
from pathlib import Path
import pytest
from src.local_deep_research.database.sqlcipher_utils import (
DEFAULT_KDF_ITERATIONS,
DEFAULT_PAGE_SIZE,
DEFAULT_HMAC_ALGORITHM,
DEFAULT_KDF_ALGORITHM,
get_sqlcipher_settings,
apply_cipher_defaults_before_key,
apply_performance_pragmas,
set_sqlcipher_key,
)
from src.local_deep_research.database.sqlcipher_compat import (
get_sqlcipher_module,
)
@pytest.fixture
def temp_db_path():
"""Create a temporary database path."""
temp_dir = tempfile.mkdtemp()
db_path = Path(temp_dir) / "test_settings.db"
yield db_path
shutil.rmtree(temp_dir)
@pytest.fixture
def sqlcipher_module():
"""Get the SQLCipher module."""
return get_sqlcipher_module()
@pytest.fixture
def clean_env(monkeypatch):
"""Remove all LDR_DB_* environment variables."""
env_vars = [
"LDR_DB_KDF_ITERATIONS",
"LDR_DB_PAGE_SIZE",
"LDR_DB_HMAC_ALGORITHM",
"LDR_DB_KDF_ALGORITHM",
"LDR_DB_CACHE_SIZE_MB",
"LDR_DB_JOURNAL_MODE",
"LDR_DB_SYNCHRONOUS",
]
for var in env_vars:
monkeypatch.delenv(var, raising=False)
return monkeypatch
class TestDefaultSettings:
"""Tests for default SQLCipher settings."""
def test_default_kdf_iterations(self, clean_env):
"""Verify default KDF iterations value."""
settings = get_sqlcipher_settings()
assert settings["kdf_iterations"] == DEFAULT_KDF_ITERATIONS
assert settings["kdf_iterations"] == 256000, "Default should be 256000"
def test_default_page_size(self, clean_env):
"""Verify default page size value."""
settings = get_sqlcipher_settings()
assert settings["page_size"] == DEFAULT_PAGE_SIZE
assert settings["page_size"] == 16384, "Default should be 16384 (16KB)"
def test_default_hmac_algorithm(self, clean_env):
"""Verify default HMAC algorithm value."""
settings = get_sqlcipher_settings()
assert settings["hmac_algorithm"] == DEFAULT_HMAC_ALGORITHM
assert settings["hmac_algorithm"] == "HMAC_SHA512"
def test_default_kdf_algorithm(self, clean_env):
"""Verify default KDF algorithm value."""
settings = get_sqlcipher_settings()
assert settings["kdf_algorithm"] == DEFAULT_KDF_ALGORITHM
assert settings["kdf_algorithm"] == "PBKDF2_HMAC_SHA512"
def test_settings_returns_all_required_keys(self, clean_env):
"""Verify settings dictionary has all required keys."""
settings = get_sqlcipher_settings()
required_keys = [
"kdf_iterations",
"page_size",
"hmac_algorithm",
"kdf_algorithm",
]
for key in required_keys:
assert key in settings, f"Missing key: {key}"
def test_settings_values_are_correct_types(self, clean_env):
"""Verify settings values have correct types."""
settings = get_sqlcipher_settings()
assert isinstance(settings["kdf_iterations"], int)
assert isinstance(settings["page_size"], int)
assert isinstance(settings["hmac_algorithm"], str)
assert isinstance(settings["kdf_algorithm"], str)
class TestEnvironmentOverrides:
"""Tests for environment variable overrides."""
def test_kdf_iterations_override(self, monkeypatch):
"""Verify LDR_DB_KDF_ITERATIONS environment variable works."""
monkeypatch.setenv("LDR_DB_KDF_ITERATIONS", "500000")
settings = get_sqlcipher_settings()
assert settings["kdf_iterations"] == 500000
def test_page_size_override(self, monkeypatch):
"""Verify LDR_DB_PAGE_SIZE environment variable works."""
monkeypatch.setenv("LDR_DB_PAGE_SIZE", "8192")
settings = get_sqlcipher_settings()
assert settings["page_size"] == 8192
def test_hmac_algorithm_override(self, monkeypatch):
"""Verify LDR_DB_HMAC_ALGORITHM environment variable works."""
monkeypatch.setenv("LDR_DB_HMAC_ALGORITHM", "HMAC_SHA256")
settings = get_sqlcipher_settings()
assert settings["hmac_algorithm"] == "HMAC_SHA256"
def test_kdf_algorithm_override(self, monkeypatch):
"""Verify LDR_DB_KDF_ALGORITHM environment variable works."""
monkeypatch.setenv("LDR_DB_KDF_ALGORITHM", "PBKDF2_HMAC_SHA256")
settings = get_sqlcipher_settings()
assert settings["kdf_algorithm"] == "PBKDF2_HMAC_SHA256"
class TestPerformancePragmaSettings:
"""Tests for performance pragma environment variable overrides."""
def test_cache_size_override(
self, sqlcipher_module, temp_db_path, monkeypatch
):
"""Verify LDR_DB_CACHE_SIZE_MB environment variable works."""
monkeypatch.setenv("LDR_DB_CACHE_SIZE_MB", "128")
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
# cache_size in KB (negative means KB)
# 128 MB = 131072 KB, stored as -131072
result = conn.execute("PRAGMA cache_size").fetchone()
assert result is not None
assert result[0] == -131072, (
f"Expected -131072 (-128*1024), got {result[0]}"
)
conn.close()
def test_journal_mode_override(
self, sqlcipher_module, temp_db_path, monkeypatch
):
"""Verify LDR_DB_JOURNAL_MODE environment variable works."""
monkeypatch.setenv("LDR_DB_JOURNAL_MODE", "DELETE")
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
result = conn.execute("PRAGMA journal_mode").fetchone()
assert result is not None
assert result[0].lower() == "delete"
conn.close()
def test_synchronous_override(
self, sqlcipher_module, temp_db_path, monkeypatch
):
"""Verify LDR_DB_SYNCHRONOUS environment variable works."""
monkeypatch.setenv("LDR_DB_SYNCHRONOUS", "FULL")
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
result = conn.execute("PRAGMA synchronous").fetchone()
assert result is not None
# SQLite returns synchronous as integer: 0=OFF, 1=NORMAL, 2=FULL, 3=EXTRA
assert result[0] == 2, f"Expected 2 (FULL), got {result[0]}"
conn.close()
def test_default_journal_mode_is_wal(
self, sqlcipher_module, temp_db_path, clean_env
):
"""Verify default journal mode is WAL."""
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
result = conn.execute("PRAGMA journal_mode").fetchone()
assert result is not None
assert result[0].lower() == "wal", f"Expected WAL, got {result[0]}"
conn.close()
def test_default_temp_store_is_memory(
self, sqlcipher_module, temp_db_path, clean_env
):
"""Verify temp_store is always set to MEMORY."""
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
result = conn.execute("PRAGMA temp_store").fetchone()
assert result is not None
# temp_store: 0=DEFAULT, 1=FILE, 2=MEMORY
assert result[0] == 2, f"Expected 2 (MEMORY), got {result[0]}"
conn.close()
def test_default_busy_timeout(
self, sqlcipher_module, temp_db_path, clean_env
):
"""Verify busy_timeout is set to 10000ms."""
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
result = conn.execute("PRAGMA busy_timeout").fetchone()
assert result is not None
assert result[0] == 10000, f"Expected 10000, got {result[0]}"
conn.close()
class TestSettingsAppliedToDatabase:
"""Tests verifying settings are actually applied to databases."""
def test_cipher_settings_applied_before_key(
self, sqlcipher_module, temp_db_path, clean_env
):
"""Verify cipher_default_* settings are applied before key."""
settings = get_sqlcipher_settings()
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
# Apply settings before key
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
cursor.close()
# Verify all cipher settings
page_size = conn.execute("PRAGMA cipher_page_size").fetchone()[0]
hmac_algo = conn.execute("PRAGMA cipher_hmac_algorithm").fetchone()[0]
kdf_algo = conn.execute("PRAGMA cipher_kdf_algorithm").fetchone()[0]
assert str(page_size) == str(settings["page_size"])
assert hmac_algo == settings["hmac_algorithm"]
assert kdf_algo == settings["kdf_algorithm"]
conn.close()
def test_multiple_env_overrides_work_together(
self, sqlcipher_module, temp_db_path, monkeypatch
):
"""Verify multiple environment variable overrides work together."""
monkeypatch.setenv("LDR_DB_PAGE_SIZE", "8192")
monkeypatch.setenv("LDR_DB_KDF_ITERATIONS", "100000")
monkeypatch.setenv("LDR_DB_CACHE_SIZE_MB", "32")
settings = get_sqlcipher_settings()
assert settings["page_size"] == 8192
assert settings["kdf_iterations"] == 100000
conn = sqlcipher_module.connect(str(temp_db_path))
cursor = conn.cursor()
apply_cipher_defaults_before_key(cursor)
set_sqlcipher_key(cursor, "testpassword")
apply_performance_pragmas(cursor)
cursor.close()
# Verify page size
page_size = conn.execute("PRAGMA cipher_page_size").fetchone()[0]
assert str(page_size) == "8192"
# Verify cache size (32MB = 32768KB = -32768)
cache_size = conn.execute("PRAGMA cache_size").fetchone()[0]
assert cache_size == -32768
conn.close()