From ee1d54ac9003531b9ea69c54c18755fb308b7a8a Mon Sep 17 00:00:00 2001 From: Renn F Date: Sat, 13 Dec 2025 18:09:23 +0100 Subject: [PATCH] + Semgrep + Deptry --- pyproject.toml | 50 +++++++++++++++++++++++++++++++++++ roboco/api/routes/channels.py | 8 +++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 50bfddef..47ad7d21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -265,6 +265,56 @@ exclude = ["tests", ".venv", "vulture_whitelist.py", "alembic"] extend_exclude = ["conftest.py", "setup.py"] known_first_party = ["roboco"] +[tool.deptry.per_rule_ignores] +# DEP002: Dependencies not directly imported but used at runtime or via CLI +DEP002 = [ + # Runtime server/driver dependencies (used by frameworks, not imported) + "uvicorn", + "websockets", + "asyncpg", + "hiredis", + "python-multipart", + # Database migrations (CLI tool) + "alembic", + # Auth libraries (used via passlib[bcrypt], python-jose[cryptography]) + "python-jose", + "passlib", + # LLM utilities (embeddings/token counting) + "openai", + "tiktoken", + # Retry logic (used in production services) + "tenacity", + # Dev tools (CLI, not imported) + "pytest", + "pytest-asyncio", + "pytest-cov", + "pytest-xdist", + "factory-boy", + "faker", + "ruff", + "mypy", + "vulture", + "bandit", + "safety", + "pip-audit", + "radon", + "xenon", + "deptry", + "semgrep", + "ipython", + "rich", + # Type stubs (used by mypy) + "types-redis", + "types-passlib", + "types-python-jose", + # Documentation (CLI tools) + "mkdocs", + "mkdocs-material", + "mkdocstrings", +] +# DEP003: Starlette is a transitive dep of FastAPI, but BaseHTTPMiddleware is needed +DEP003 = ["starlette"] + [dependency-groups] dev = [ "types-aiofiles", diff --git a/roboco/api/routes/channels.py b/roboco/api/routes/channels.py index 86d7b6da..70a15360 100644 --- a/roboco/api/routes/channels.py +++ b/roboco/api/routes/channels.py @@ -9,7 +9,7 @@ from uuid import UUID from fastapi import APIRouter, HTTPException, Query, status from pydantic import BaseModel, Field -from sqlalchemy import select +from sqlalchemy import func, select from sqlalchemy.orm import selectinload from roboco.api.deps import CurrentAgentContext, DbSession, PermissionServiceDep @@ -109,11 +109,13 @@ async def list_channels( query = query.where(ChannelTable.is_archived.is_(False)) # Get total count - count_query = select(ChannelTable.id).where(ChannelTable.slug.in_(accessible_slugs)) + count_query = select(func.count(ChannelTable.id)).where( + ChannelTable.slug.in_(accessible_slugs) + ) if not params.include_archived: count_query = count_query.where(ChannelTable.is_archived.is_(False)) count_result = await db.execute(count_query) - total = len(count_result.all()) + total = count_result.scalar() or 0 # Apply pagination query = query.offset((params.page - 1) * params.page_size).limit(params.page_size)