chore(types): enable warn_return_any and cast all no-any-return sites
Turn on mypy warn_return_any (pyproject) and resolve the 84 resulting [no-any-return] errors across 43 files with typing.cast() at the return sites — runtime no-ops that make the declared return type explicit where a dependency (SQLAlchemy scalar/first/one, httpx .json(), subprocess, docker SDK) hands back Any. No behavior change: no DTO/table field types altered, no validation/coercion calls added, every cast reflects the true runtime type. Locks in return-type strictness so the class of bug where a function silently widens to Any can't regress. mypy decnet/ clean; adversarially verified behavior-preserving (84 casts 1:1 with prior returns). Bump tornado 6.5.5 -> 6.5.7 (CVE-2026-49854, transitive via snakeviz).
This commit is contained in:
@@ -8,7 +8,7 @@ import os
|
||||
import traceback
|
||||
import uuid
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Any, AsyncGenerator, Optional
|
||||
from typing import Any, AsyncGenerator, Optional, cast
|
||||
|
||||
from fastapi import FastAPI, Request, status
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
@@ -306,7 +306,7 @@ class _ContentTypeMiddleware(BaseHTTPMiddleware):
|
||||
status_code=415,
|
||||
media_type="text/plain",
|
||||
)
|
||||
return await call_next(request)
|
||||
return cast(StarletteResponse, await call_next(request))
|
||||
|
||||
|
||||
app.add_middleware(_ContentTypeMiddleware)
|
||||
|
||||
@@ -6,7 +6,7 @@ Repository factory — selects a :class:`BaseRepository` implementation based on
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Any
|
||||
from typing import Any, cast
|
||||
|
||||
from decnet.web.db.repository import BaseRepository
|
||||
|
||||
@@ -32,4 +32,4 @@ def get_repository(**kwargs: Any) -> BaseRepository:
|
||||
raise ValueError(f"Unsupported database type: {db_type}")
|
||||
|
||||
from decnet.telemetry import wrap_repository
|
||||
return wrap_repository(repo)
|
||||
return cast(BaseRepository, wrap_repository(repo))
|
||||
|
||||
@@ -18,7 +18,7 @@ import os
|
||||
|
||||
import orjson
|
||||
import uuid
|
||||
from typing import Any, Optional, List
|
||||
from typing import Any, Optional, List, cast
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
||||
@@ -183,7 +183,7 @@ class SQLModelRepository(
|
||||
result = await session.execute(statement)
|
||||
state = result.scalar_one_or_none()
|
||||
if state:
|
||||
return json.loads(state.value)
|
||||
return cast(dict[str, Any], json.loads(state.value))
|
||||
return None
|
||||
|
||||
async def set_state(self, key: str, value: Any) -> None: # noqa: ANN401
|
||||
|
||||
@@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
|
||||
import uuid as _uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, or_, select
|
||||
from sqlmodel import col
|
||||
@@ -44,7 +44,7 @@ class AttackerIntelMixin(_MixinBase):
|
||||
row_uuid = _uuid.uuid4().hex
|
||||
session.add(AttackerIntel(uuid=row_uuid, **data))
|
||||
await session.commit()
|
||||
return row_uuid
|
||||
return cast(str, row_uuid)
|
||||
|
||||
async def get_attacker_intel_row_by_uuid(
|
||||
self,
|
||||
@@ -54,7 +54,7 @@ class AttackerIntelMixin(_MixinBase):
|
||||
result = await session.execute(
|
||||
select(AttackerIntel).where(AttackerIntel.attacker_uuid == uuid)
|
||||
)
|
||||
return result.scalar_one_or_none()
|
||||
return cast(Optional[AttackerIntel], result.scalar_one_or_none())
|
||||
|
||||
async def get_attacker_intel_by_uuid(
|
||||
self,
|
||||
@@ -67,7 +67,7 @@ class AttackerIntelMixin(_MixinBase):
|
||||
row = result.scalar_one_or_none()
|
||||
if not row:
|
||||
return None
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
|
||||
async def get_unenriched_attackers(
|
||||
self, limit: int = 100,
|
||||
|
||||
@@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import uuid as _uuid
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any, List, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, outerjoin, select
|
||||
from sqlmodel import col
|
||||
@@ -47,7 +47,7 @@ class AttackersCoreMixin(_MixinBase):
|
||||
data = {**data, "uuid": row_uuid}
|
||||
session.add(Attacker(**data))
|
||||
await session.commit()
|
||||
return row_uuid
|
||||
return cast(str, row_uuid)
|
||||
|
||||
async def get_attacker_uuid_by_ip(self, ip: str) -> Optional[str]:
|
||||
"""Return the :class:`Attacker` UUID for *ip*, or ``None``.
|
||||
@@ -61,7 +61,7 @@ class AttackersCoreMixin(_MixinBase):
|
||||
result = await session.execute(
|
||||
select(col(Attacker.uuid)).where(Attacker.ip == ip)
|
||||
)
|
||||
return result.scalar_one_or_none()
|
||||
return cast(Optional[str], result.scalar_one_or_none())
|
||||
|
||||
async def get_attacker_by_uuid(self, uuid: str) -> Optional[dict[str, Any]]:
|
||||
async with self._session() as session:
|
||||
|
||||
@@ -21,7 +21,7 @@ from __future__ import annotations
|
||||
|
||||
import uuid as _uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import func, select
|
||||
from sqlmodel import col
|
||||
@@ -66,7 +66,7 @@ class AttributionMixin(_MixinBase):
|
||||
if attacker_row is None:
|
||||
return None
|
||||
if attacker_row.identity_id:
|
||||
return attacker_row.identity_id
|
||||
return cast(str, attacker_row.identity_id)
|
||||
new_uuid = _uuid.uuid4().hex
|
||||
now = datetime.now(timezone.utc)
|
||||
session.add(
|
||||
|
||||
@@ -9,7 +9,7 @@ the reads.
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, select, update
|
||||
from sqlmodel import col
|
||||
@@ -36,9 +36,9 @@ class CampaignsMixin(_MixinBase):
|
||||
if campaign is None:
|
||||
return None
|
||||
if campaign.merged_into_uuid is None:
|
||||
return campaign.model_dump(mode="json")
|
||||
return cast(dict[str, Any], campaign.model_dump(mode="json"))
|
||||
current_uuid = campaign.merged_into_uuid
|
||||
return campaign.model_dump(mode="json")
|
||||
return cast(dict[str, Any], campaign.model_dump(mode="json"))
|
||||
|
||||
async def list_campaigns(
|
||||
self, limit: int = 50, offset: int = 0,
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, select, update
|
||||
|
||||
@@ -26,7 +26,7 @@ class CanaryMixin(_MixinBase):
|
||||
)
|
||||
row = existing.scalar_one_or_none()
|
||||
if row:
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
row = CanaryBlob(**data)
|
||||
session.add(row)
|
||||
await session.commit()
|
||||
@@ -155,7 +155,7 @@ class CanaryMixin(_MixinBase):
|
||||
.values(state=state, last_error=last_error)
|
||||
)
|
||||
await session.commit()
|
||||
return result.rowcount > 0
|
||||
return cast(bool, result.rowcount > 0)
|
||||
|
||||
async def record_canary_trigger(self, data: dict[str, Any]) -> str:
|
||||
# Persist the trigger row + bump the token's counters in the same
|
||||
@@ -204,4 +204,4 @@ class CanaryMixin(_MixinBase):
|
||||
.values(attacker_id=attacker_id)
|
||||
)
|
||||
await session.commit()
|
||||
return result.rowcount > 0
|
||||
return cast(bool, result.rowcount > 0)
|
||||
|
||||
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any, List, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, or_, select, update
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
@@ -67,7 +67,7 @@ class CredentialsCoreMixin(_MixinBase):
|
||||
existing.outcome = payload["outcome"]
|
||||
session.add(existing)
|
||||
await session.commit()
|
||||
return existing.id
|
||||
return cast(int, existing.id)
|
||||
row = Credential(
|
||||
attacker_ip=payload["attacker_ip"],
|
||||
decky_name=payload["decky_name"],
|
||||
@@ -103,7 +103,7 @@ class CredentialsCoreMixin(_MixinBase):
|
||||
existing2.outcome = payload["outcome"]
|
||||
session2.add(existing2)
|
||||
await session2.commit()
|
||||
return existing2.id
|
||||
return cast(int, existing2.id)
|
||||
await session.refresh(row)
|
||||
return row.id # type: ignore[return-value]
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import uuid as _uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, List, Optional
|
||||
from typing import Any, List, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, select
|
||||
from sqlmodel import col
|
||||
@@ -137,7 +137,7 @@ class CredentialReuseMixin(_MixinBase):
|
||||
d = existing.model_dump(mode="json")
|
||||
d["inserted"] = False
|
||||
d["changed"] = changed
|
||||
return d
|
||||
return cast(dict[str, Any], d)
|
||||
|
||||
async def find_credential_reuse_candidates(
|
||||
self, min_targets: int = 2
|
||||
@@ -236,7 +236,7 @@ class CredentialReuseMixin(_MixinBase):
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
d[key] = []
|
||||
await self._enrich_with_secret(session, [d])
|
||||
return d
|
||||
return cast(dict[str, Any], d)
|
||||
|
||||
@staticmethod
|
||||
async def _enrich_with_secret(
|
||||
|
||||
@@ -9,7 +9,7 @@ the reads.
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, select, update
|
||||
from sqlmodel import col
|
||||
@@ -42,10 +42,10 @@ class IdentitiesMixin(_MixinBase):
|
||||
if identity is None:
|
||||
return None
|
||||
if identity.merged_into_uuid is None:
|
||||
return identity.model_dump(mode="json")
|
||||
return cast(dict[str, Any], identity.model_dump(mode="json"))
|
||||
current_uuid = identity.merged_into_uuid
|
||||
# Hit the hop cap — surface what we have rather than recurse.
|
||||
return identity.model_dump(mode="json")
|
||||
return cast(dict[str, Any], identity.model_dump(mode="json"))
|
||||
|
||||
async def list_identities(
|
||||
self, limit: int = 50, offset: int = 0,
|
||||
|
||||
@@ -21,7 +21,7 @@ not validate values — that happens at construction time by the BEHAVE
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid as _uuid
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, select
|
||||
from sqlmodel import col
|
||||
@@ -85,7 +85,7 @@ class ObservationsMixin(_MixinBase):
|
||||
row_data = {**data, "id": row_id}
|
||||
session.add(ObservationRow(**row_data))
|
||||
await session.commit()
|
||||
return row_id
|
||||
return cast(str, row_id)
|
||||
|
||||
async def latest_observation_per_primitive(
|
||||
self, attacker_uuid: str,
|
||||
@@ -178,7 +178,7 @@ class ObservationsMixin(_MixinBase):
|
||||
row = (await session.execute(stmt)).scalar_one_or_none()
|
||||
if not row:
|
||||
return None
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
|
||||
async def observations_for_identity_primitive(
|
||||
self, identity_uuid: str, primitive: str,
|
||||
|
||||
@@ -13,7 +13,7 @@ caller is upgrading ``False/None`` to ``True``.
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Optional
|
||||
from typing import Optional, cast
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
@@ -106,4 +106,4 @@ class ObservedAttachmentsMixin(_MixinBase):
|
||||
row.mal_hash_match_at = now
|
||||
session.add(row)
|
||||
await session.commit()
|
||||
return row.uuid
|
||||
return cast(str, row.uuid)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import desc, func, select, update
|
||||
|
||||
@@ -92,7 +92,7 @@ class RealismMixin(_MixinBase):
|
||||
row = result.scalars().first()
|
||||
if row is None:
|
||||
return None
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
|
||||
async def get_realism_config(
|
||||
self, key: str,
|
||||
@@ -103,7 +103,7 @@ class RealismMixin(_MixinBase):
|
||||
row = result.scalars().first()
|
||||
if row is None:
|
||||
return None
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
|
||||
async def set_realism_config(
|
||||
self, key: str, value: str,
|
||||
@@ -157,4 +157,4 @@ class RealismMixin(_MixinBase):
|
||||
row = result.scalars().first()
|
||||
if row is None:
|
||||
return None
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
@@ -47,7 +47,7 @@ class TarpitMixin(_MixinBase):
|
||||
return None
|
||||
d = row.model_dump(mode="json")
|
||||
d["ports"] = json.loads(d["ports"])
|
||||
return d
|
||||
return cast(dict[str, Any], d)
|
||||
|
||||
async def delete_tarpit_rule(self, decky_name: str) -> bool:
|
||||
async with self._session() as session:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
import orjson
|
||||
from sqlalchemy import asc, desc, select, text
|
||||
@@ -102,7 +102,7 @@ class TopologyMutationsMixin(_MixinBase):
|
||||
_ = now
|
||||
if row is None:
|
||||
return None
|
||||
return row.model_dump(mode="json")
|
||||
return cast(dict[str, Any], row.model_dump(mode="json"))
|
||||
|
||||
async def mark_mutation_applied(self, mutation_id: str) -> None:
|
||||
async with self._session() as session:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
from sqlalchemy import select, update
|
||||
from sqlmodel import col
|
||||
@@ -65,7 +65,7 @@ class WebhooksMixin(_MixinBase):
|
||||
.values(**patch)
|
||||
)
|
||||
await session.commit()
|
||||
return result.rowcount > 0
|
||||
return cast(bool, result.rowcount > 0)
|
||||
|
||||
async def delete_webhook_subscription(self, uuid: str) -> bool:
|
||||
async with self._session() as session:
|
||||
|
||||
Reference in New Issue
Block a user