feat: Complete repository protocol coverage
- Add missing protocol methods to Fail2BanDbRepository: - get_ban_event_counts: Aggregate ban events per IP (used in ban_service) - Add missing protocol methods to GeoCacheRepository: - delete_stale_entries: Remove old geo cache entries (used in geo_cache_cleanup) - Add missing protocol methods to HistoryArchiveRepository: - purge_archived_history: Remove archived entries older than age threshold - Add comprehensive protocol compliance tests: - Created test_protocol_compliance.py with 8 test classes - Validates all 7 repository modules fully implement their protocols - Prevents silent protocol drift when methods change signatures - Tests verify no unexpected public methods in repository modules - Update documentation: - Add Repository Protocol Coverage Checklist to Backend-Development.md - Document procedure for adding new repositories with protocol definitions - List current protocol coverage (all 7 repositories, 40 total methods) - All repositories now have 100% protocol coverage: - SessionRepository: 4 methods - SettingsRepository: 4 methods - BlocklistRepository: 6 methods - ImportLogRepository: 4 methods - GeoCacheRepository: 13 methods - HistoryArchiveRepository: 5 methods - Fail2BanDbRepository: 8 methods This ensures: - Enhanced mockability for testing - Static contract verification - Prevention of protocol drift - Better IDE support and type checking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -13,7 +13,7 @@ import aiosqlite
|
||||
|
||||
from app.models.auth import Session
|
||||
from app.models.ban import BanOrigin
|
||||
from app.repositories.fail2ban_db_repo import BanRecord, HistoryRecord, JailBanCount
|
||||
from app.repositories.fail2ban_db_repo import BanIpCount, BanRecord, HistoryRecord, JailBanCount
|
||||
from app.repositories.geo_cache_repo import GeoCacheRow
|
||||
from app.repositories.import_log_repo import ImportLogRow
|
||||
|
||||
@@ -203,6 +203,9 @@ class GeoCacheRepository(Protocol):
|
||||
) -> tuple[int, int]:
|
||||
...
|
||||
|
||||
async def delete_stale_entries(self, db: aiosqlite.Connection, cutoff_iso: str) -> int:
|
||||
...
|
||||
|
||||
|
||||
class HistoryArchiveRepository(Protocol):
|
||||
"""Protocol for archived ban history persistence operations."""
|
||||
@@ -246,6 +249,9 @@ class HistoryArchiveRepository(Protocol):
|
||||
) -> list[dict[str, Any]]:
|
||||
...
|
||||
|
||||
async def purge_archived_history(self, db: aiosqlite.Connection, age_seconds: int) -> int:
|
||||
...
|
||||
|
||||
|
||||
class Fail2BanDbRepository(Protocol):
|
||||
async def check_db_nonempty(self, db_path: str) -> bool:
|
||||
@@ -273,6 +279,14 @@ class Fail2BanDbRepository(Protocol):
|
||||
) -> list[int]:
|
||||
...
|
||||
|
||||
async def get_ban_event_counts(
|
||||
self,
|
||||
db_path: str,
|
||||
since: int,
|
||||
origin: BanOrigin | None = None,
|
||||
) -> list[BanIpCount]:
|
||||
...
|
||||
|
||||
async def get_bans_by_jail(
|
||||
self,
|
||||
db_path: str,
|
||||
|
||||
Reference in New Issue
Block a user