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:
Indiana
2026-08-01 01:45:04 +00:00
parent a727858a62
commit 605f32f20e
5 changed files with 270 additions and 5 deletions

View File

@@ -28,7 +28,11 @@ type Hunter = {
}
type Conversation = {
hunter: Hunter
last_body: string
// GET /api/messages calls this `excerpt` (first 160 chars) with a
// `truncated` flag beside it. This type used to say `last_body`, which the
// API has never sent — every inbox preview rendered as an empty string.
excerpt: string
truncated: boolean
last_at: string
last_from_me: boolean
unread: number
@@ -132,7 +136,8 @@ function Inbox() {
</span>
<span className="msg-row-last dim">
{c.last_from_me ? t('messages.youPrefix') : ''}
{c.last_body}
{c.excerpt}
{c.truncated ? '…' : ''}
</span>
</span>
{c.unread > 0 && (