Skip to content

Avatars, banners and chat images through the worker's quarantine (GRYT-1664) - #272

Merged
sivert-io merged 2 commits into
mainfrom
claude/GRYT-1664-server-quarantine
Oct 5, 2026
Merged

sivert-io merged 2 commits into
mainfrom
claude/GRYT-1664-server-quarantine

Conversation

@sivert-io

Copy link
Copy Markdown
Member

The server half of the upload plan in GRYT-1664. It goes with Gryt-chat/image-worker#40, and does nothing until that worker is deployed.

What it does

  • workerCapabilities.ts asks the image worker's /health every minute (IMAGE_WORKER_URL). Only when the answer lists quarantine-v1 does the server use quarantine. No worker, an old worker, an unreachable worker, or the desktop-embedded worker (which has no jail) all mean today's path, unchanged.
  • With it on, an avatar, banner or chat image is stored as sent under quarantine/avatars|banners|uploads/ with an image job, and the server doesn't decode it. Before, it ran sharp (avatars and banners) or validateImage (chat) on the stranger's file itself. The worker writes it out again in its jail and moves the row (image-worker#40).
  • GET /api/uploads/files/:id never serves a quarantine key. A read waits up to 15 seconds for the worker's copy, which normally takes a second or two, so clients need no change. If it never comes, the answer is 503 media_not_ready with no-store.
  • Unchanged for now: videos (they get the transcode in the next step), group and webhook pictures, and emoji.

Redoes the reverted 8d7f9bd (#268), gated on the worker this time, so a release can't leave uploads stranded.

What to look at

  • The read waits by polling the file row every 250ms for up to 15s. That holds a request open. Fine at Gryt's scale, but say if you'd rather have a client retry.
  • storeUploadedFile skips validateImage for a quarantined chat image. The worker refuses anything that doesn't decode, and the row has no width or height until it does.
  • No review-required path is touched (src/routes, src/services, src/index.ts).

Tests: 1965 pass, 3 of them new. They cover a banner landing in quarantine with its job, a read that waits for the worker's copy, a read that gives up with 503, and the old path with a worker that doesn't claim quarantine.

🤖 Generated with Claude Code

sivert-io and others added 2 commits October 5, 2026 10:49
… (GRYT-1664)

When the image worker reports quarantine-v1 on /health, an avatar, a
banner or a chat image is stored under quarantine/ as sent, with an
image job, and the server never decodes it: the worker writes it out
again inside its jail and moves the row. Any read of a file still in
quarantine waits up to 15 seconds for that, then answers 503
media_not_ready with no-store, so the bytes as sent are never served.

A worker that doesn't say quarantine-v1, including none at all and the
desktop-embedded one, keeps today's path. Videos, group and webhook
pictures and emoji are unchanged for now.

Redoes the reverted 8d7f9bd, gated on the worker.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@sivert-io
sivert-io merged commit b6dab87 into main Oct 5, 2026
4 checks passed
@sivert-io
sivert-io deleted the claude/GRYT-1664-server-quarantine branch October 5, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant