chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
"""
|
||||
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()
|
||||
Reference in New Issue
Block a user