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

113 lines
3.5 KiB
Python

"""Regression guard for the encrypted-DB CreateIndex defect.
Until v1.6.x, ``encrypted_db.create_user_database()`` only emitted
``CreateTable`` statements and never ``CreateIndex``. As a result every
model-declared index (``index=True``, ``unique=True``, explicit
``Index(...)`` in ``__table_args__``) was missing in user databases.
This test asserts that for every table in ``Base.metadata``, every named
index declared by the model is present in a freshly created encrypted
database — both column-level and table-level.
"""
from __future__ import annotations
import sys
import tempfile
from pathlib import Path
import pytest
from sqlalchemy import inspect
pytest.importorskip(
"sqlcipher3",
reason="SQLCipher is required to test the encrypted-DB schema path.",
)
sys.path.insert(
0,
str(Path(__file__).parent.parent.parent.resolve()),
)
from local_deep_research.database.encrypted_db import DatabaseManager
from local_deep_research.database.models import Base
@pytest.fixture
def temp_data_dir(monkeypatch):
with tempfile.TemporaryDirectory() as tmpdir:
path = Path(tmpdir)
monkeypatch.setattr(
"local_deep_research.database.encrypted_db.get_data_directory",
lambda: path,
)
yield path
@pytest.fixture
def db_manager(temp_data_dir):
m = DatabaseManager()
yield m
for username in list(m.connections.keys()):
m.close_user_database(username)
def test_every_model_declared_index_exists_in_fresh_db(db_manager):
"""Iterate Base.metadata; assert every named index is present."""
assert db_manager.has_encryption, (
"sqlcipher3 imports but DatabaseManager reported has_encryption=False"
)
username = "indexcheck"
password = "StrongPassword1!"
db_manager.create_user_database(username, password)
engine = db_manager.connections[username]
inspector = inspect(engine)
missing: list[tuple[str, str]] = []
for table in Base.metadata.sorted_tables:
if table.name == "users":
continue
if not inspector.has_table(table.name):
continue
existing = {idx["name"] for idx in inspector.get_indexes(table.name)}
for index in table.indexes:
if not index.name:
continue
if index.name not in existing:
missing.append((table.name, index.name))
assert not missing, (
f"Missing model-declared indexes in fresh user DB: {missing}. "
f"This usually means encrypted_db.create_user_database() is not "
f"emitting CreateIndex for declared indexes."
)
def test_download_tracker_url_hash_has_unique_backing(db_manager):
"""The exact regression that caused #3697 — url_hash must be UNIQUE.
Without UNIQUE backing on the FK target, SQLCipher raises
"foreign key mismatch — download_attempts referencing download_tracker"
on cascade delete.
"""
assert db_manager.has_encryption
username = "trackercheck"
password = "StrongPassword1!"
db_manager.create_user_database(username, password)
engine = db_manager.connections[username]
inspector = inspect(engine)
indexes = inspector.get_indexes("download_tracker")
unique_on_url_hash = [
idx
for idx in indexes
if idx.get("unique") and idx.get("column_names") == ["url_hash"]
]
assert unique_on_url_hash, (
"download_tracker.url_hash must have a UNIQUE backing index for "
"FK references from download_attempts/download_duplicates to "
f"resolve. Indexes present: {indexes}"
)