fix: blank inbox previews, two unauthenticated 500s, and the missing social tests
- Every conversation row in the inbox rendered an empty preview: the frontend read `last_body`, which the API has never sent. It sends `excerpt` plus `truncated`. - `GET /api/codex?limit=-1` passed a negative LIMIT to Postgres -> 500. Now bounded by Query(ge=1, le=200) -> 422. - Registering with a >255 char email hit the VARCHAR(255) column and surfaced as a 500. PATCH /api/profile already validated this; only /auth/register was open. The social layer had zero tests, despite routes/messages.py citing "tests/test_messages.py's cross-user leak tests" and routes/profile.py claiming "privacy rules that the tests pin". Neither file existed. Both now do: auth required on every route, email only on /api/profile/me, no id or password_hash on any public payload, third-party thread reads empty, payload-supplied sender inert, veiled profiles 404 and stay off the roster. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@ contacted, shared across all users (spec §4)."""
|
||||
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy import desc, func, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -126,7 +126,9 @@ def _entity_card(entity: Entity, discoverer: str | None) -> dict:
|
||||
async def list_codex(
|
||||
rarity: str | None = None,
|
||||
sort: str = "recent",
|
||||
limit: int = 60,
|
||||
# Bounded at the edge: an unvalidated `?limit=-1` reached Postgres as a
|
||||
# negative LIMIT and returned a 500 to an unauthenticated caller.
|
||||
limit: int = Query(default=60, ge=1, le=200),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
query = select(Entity)
|
||||
|
||||
@@ -7,7 +7,9 @@ from pydantic import BaseModel, ConfigDict, Field
|
||||
class RegisterRequest(BaseModel):
|
||||
username: str = Field(min_length=3, max_length=32)
|
||||
password: str = Field(min_length=8, max_length=128)
|
||||
email: str | None = None
|
||||
# users.email is VARCHAR(255): without a cap here an over-long address
|
||||
# reached Postgres and surfaced as a 500 instead of a validation error.
|
||||
email: str | None = Field(default=None, max_length=255)
|
||||
|
||||
|
||||
class UserOut(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user