Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

277 lines
10 KiB
Python

"""
Tests for FAISS Index Verifier - File integrity verification for FAISS vector indexes.
Tests cover:
- File type detection (should_verify)
- FAISS-specific policy enforcement
- Checksum calculation
- Edge cases and error handling
"""
import hashlib
import tempfile
from pathlib import Path
import pytest
from local_deep_research.security.file_integrity.verifiers.faiss_verifier import (
FAISSIndexVerifier,
)
from local_deep_research.security.file_integrity.base_verifier import FileType
@pytest.fixture
def verifier():
"""Create a FAISS verifier instance."""
return FAISSIndexVerifier()
@pytest.fixture
def temp_faiss_file():
"""Create a temporary .faiss file."""
with tempfile.NamedTemporaryFile(suffix=".faiss", delete=False) as f:
f.write(b"fake faiss index content")
return Path(f.name)
@pytest.fixture
def temp_non_faiss_file():
"""Create a temporary non-.faiss file."""
with tempfile.NamedTemporaryFile(suffix=".txt", delete=False) as f:
f.write(b"text content")
return Path(f.name)
class TestFAISSVerifierInitialization:
"""Tests for FAISS verifier initialization."""
def test_verifier_creates_successfully(self):
"""Verifier can be instantiated."""
verifier = FAISSIndexVerifier()
assert verifier is not None
def test_verifier_inherits_base_verifier(self):
"""Verifier inherits from BaseFileVerifier."""
from local_deep_research.security.file_integrity.base_verifier import (
BaseFileVerifier,
)
verifier = FAISSIndexVerifier()
assert isinstance(verifier, BaseFileVerifier)
class TestShouldVerify:
"""Tests for should_verify method."""
def test_should_verify_faiss_extension(self, verifier):
"""Should return True for .faiss files."""
path = Path("/data/indexes/my_index.faiss")
assert verifier.should_verify(path) is True
def test_should_verify_faiss_uppercase_extension(self, verifier):
"""Should return True for .FAISS uppercase extension."""
path = Path("/data/indexes/my_index.FAISS")
assert verifier.should_verify(path) is True
def test_should_verify_faiss_mixed_case_extension(self, verifier):
"""Should return True for .Faiss mixed case extension."""
path = Path("/data/indexes/my_index.Faiss")
assert verifier.should_verify(path) is True
def test_should_not_verify_pdf_extension(self, verifier):
"""Should return False for .pdf files."""
path = Path("/data/docs/document.pdf")
assert verifier.should_verify(path) is False
def test_should_not_verify_txt_extension(self, verifier):
"""Should return False for .txt files."""
path = Path("/data/notes.txt")
assert verifier.should_verify(path) is False
def test_should_not_verify_no_extension(self, verifier):
"""Should return False for files without extension."""
path = Path("/data/file_without_extension")
assert verifier.should_verify(path) is False
def test_should_not_verify_faiss_in_name(self, verifier):
"""Should return False for files with 'faiss' in name but different extension."""
path = Path("/data/faiss_backup.json")
assert verifier.should_verify(path) is False
def test_should_verify_nested_directory_path(self, verifier):
"""Should return True for .faiss files in nested directories."""
path = Path("/data/embeddings/user123/collection_abc/index.faiss")
assert verifier.should_verify(path) is True
def test_should_verify_hidden_file(self, verifier):
"""Should return True for hidden .faiss files."""
path = Path("/data/.hidden_index.faiss")
assert verifier.should_verify(path) is True
def test_should_not_verify_empty_path(self, verifier):
"""Should handle empty file name gracefully."""
path = Path("")
# Empty path has no suffix
assert verifier.should_verify(path) is False
class TestGetFileType:
"""Tests for get_file_type method."""
def test_returns_faiss_index_type(self, verifier):
"""Should return FileType.FAISS_INDEX."""
assert verifier.get_file_type() == FileType.FAISS_INDEX
def test_file_type_is_enum_member(self, verifier):
"""File type should be a valid FileType enum member."""
file_type = verifier.get_file_type()
assert isinstance(file_type, FileType)
def test_file_type_value_is_string(self, verifier):
"""File type value should be a string."""
file_type = verifier.get_file_type()
assert file_type.value == "faiss_index"
class TestAllowsModifications:
"""Tests for allows_modifications method."""
def test_does_not_allow_modifications(self, verifier):
"""FAISS indexes should never allow modifications."""
assert verifier.allows_modifications() is False
def test_modification_policy_is_strict(self, verifier):
"""Modification policy should be consistently False."""
# Multiple calls should return same result
for _ in range(10):
assert verifier.allows_modifications() is False
class TestChecksumCalculation:
"""Tests for checksum calculation (inherited from BaseFileVerifier)."""
def test_calculate_checksum_returns_hex_string(
self, verifier, temp_faiss_file
):
"""Checksum should be a hex string."""
checksum = verifier.calculate_checksum(temp_faiss_file)
assert isinstance(checksum, str)
# SHA256 produces 64 hex characters
assert len(checksum) == 64
# All characters should be valid hex
assert all(c in "0123456789abcdef" for c in checksum)
def test_calculate_checksum_consistency(self, verifier, temp_faiss_file):
"""Same file should produce same checksum."""
checksum1 = verifier.calculate_checksum(temp_faiss_file)
checksum2 = verifier.calculate_checksum(temp_faiss_file)
assert checksum1 == checksum2
def test_calculate_checksum_different_files(self, verifier):
"""Different files should produce different checksums."""
with tempfile.NamedTemporaryFile(suffix=".faiss", delete=False) as f1:
f1.write(b"content A")
path1 = Path(f1.name)
with tempfile.NamedTemporaryFile(suffix=".faiss", delete=False) as f2:
f2.write(b"content B")
path2 = Path(f2.name)
checksum1 = verifier.calculate_checksum(path1)
checksum2 = verifier.calculate_checksum(path2)
assert checksum1 != checksum2
def test_calculate_checksum_file_not_found(self, verifier):
"""Should raise FileNotFoundError for non-existent file."""
path = Path("/nonexistent/path/index.faiss")
with pytest.raises(FileNotFoundError):
verifier.calculate_checksum(path)
def test_calculate_checksum_large_file(self, verifier):
"""Should handle large files (chunked reading)."""
with tempfile.NamedTemporaryFile(suffix=".faiss", delete=False) as f:
# Write 1MB of data
f.write(b"x" * (1024 * 1024))
path = Path(f.name)
checksum = verifier.calculate_checksum(path)
assert len(checksum) == 64
def test_calculate_checksum_empty_file(self, verifier):
"""Should handle empty files."""
with tempfile.NamedTemporaryFile(suffix=".faiss", delete=False) as f:
# Write nothing - empty file
path = Path(f.name)
checksum = verifier.calculate_checksum(path)
# SHA256 of empty string
expected = hashlib.sha256(b"").hexdigest()
assert checksum == expected
class TestGetAlgorithm:
"""Tests for get_algorithm method (inherited from BaseFileVerifier)."""
def test_get_algorithm_returns_sha256(self, verifier):
"""Should return sha256 as the algorithm."""
assert verifier.get_algorithm() == "sha256"
class TestEdgeCases:
"""Edge case tests for FAISS verifier."""
def test_path_with_special_characters(self, verifier):
"""Should handle paths with special characters."""
path = Path("/data/user's files/my (index) [v2].faiss")
assert verifier.should_verify(path) is True
def test_path_with_unicode_characters(self, verifier):
"""Should handle paths with unicode characters."""
path = Path("/données/索引/インデックス.faiss")
assert verifier.should_verify(path) is True
def test_path_with_spaces(self, verifier):
"""Should handle paths with spaces."""
path = Path("/my documents/vector indexes/main index.faiss")
assert verifier.should_verify(path) is True
def test_very_long_path(self, verifier):
"""Should handle very long paths."""
long_dir = "a" * 200
path = Path(f"/{long_dir}/index.faiss")
assert verifier.should_verify(path) is True
def test_relative_path(self, verifier):
"""Should handle relative paths."""
path = Path("./relative/path/index.faiss")
assert verifier.should_verify(path) is True
def test_multiple_extensions(self, verifier):
"""Should only check final extension."""
path = Path("/data/index.backup.faiss")
assert verifier.should_verify(path) is True
path_wrong = Path("/data/index.faiss.backup")
assert verifier.should_verify(path_wrong) is False
class TestIntegrationWithIntegrityManager:
"""Tests for integration with the integrity manager."""
def test_verifier_can_be_registered(self, verifier):
"""Verifier should have all methods required for registration."""
# Check all required methods exist
assert hasattr(verifier, "should_verify")
assert hasattr(verifier, "get_file_type")
assert hasattr(verifier, "allows_modifications")
assert hasattr(verifier, "calculate_checksum")
assert hasattr(verifier, "get_algorithm")
def test_verifier_methods_are_callable(self, verifier):
"""All verifier methods should be callable."""
assert callable(verifier.should_verify)
assert callable(verifier.get_file_type)
assert callable(verifier.allows_modifications)
assert callable(verifier.calculate_checksum)
assert callable(verifier.get_algorithm)