Where: internal/imgcache/cache.go lines 433-454 (StoreNegative), 486-497 (CleanExpired, which nothing outside tests calls) and 724-758 (checkNegativeCache); internal/imgcache/service.go lines 438-449, on v1.0.0-rc1.
What is wrong: every upstream error (any status outside 200-299, a 404 included) inserts a row in negative_cache, and an expired row is deleted only when the same source URL is requested again after its five minutes. CleanExpired is dead code. Nothing else removes rows, and cache_max_bytes does not cover the database.
How it fails: on a deployment with an allowlisted host, an outsider requests /v1/image/<host>/<a new random path each time>/1x1.jpg; each costs one upstream 404 and leaves one permanent row holding host, path, query and the error text. At the default 600 requests a minute per address, one address adds 864,000 rows a day; the database file grows until the volume is full, after which every write in pixa fails. No operation of pixa ever shrinks it.
Severity: medium
Definition of done:
Expired negative-cache rows are removed on a schedule (the eviction loop's tick is a natural place) and the table is bounded by age or row count, so it cannot grow without limit under an outsider's control.
CleanExpired is called or deleted.
Test first: a row past its expiry disappears without its URL being asked for again; make check green.
Model: fable-5-1
Where: `internal/imgcache/cache.go` lines 433-454 (`StoreNegative`), 486-497 (`CleanExpired`, which nothing outside tests calls) and 724-758 (`checkNegativeCache`); `internal/imgcache/service.go` lines 438-449, on `v1.0.0-rc1`.
What is wrong: every upstream error (any status outside 200-299, a 404 included) inserts a row in `negative_cache`, and an expired row is deleted only when the same source URL is requested again after its five minutes. `CleanExpired` is dead code. Nothing else removes rows, and `cache_max_bytes` does not cover the database.
How it fails: on a deployment with an allowlisted host, an outsider requests `/v1/image/<host>/<a new random path each time>/1x1.jpg`; each costs one upstream 404 and leaves one permanent row holding host, path, query and the error text. At the default 600 requests a minute per address, one address adds 864,000 rows a day; the database file grows until the volume is full, after which every write in pixa fails. No operation of pixa ever shrinks it.
Severity: medium
Definition of done:
1. Expired negative-cache rows are removed on a schedule (the eviction loop's tick is a natural place) and the table is bounded by age or row count, so it cannot grow without limit under an outsider's control.
2. `CleanExpired` is called or deleted.
3. Test first: a row past its expiry disappears without its URL being asked for again; `make check` green.
Model: fable-5-1
clawbot
self-assigned this 2026-10-13 08:46:10 +02:00
Plan: the eviction loop deletes expired negative-cache rows at start and on every tick, through CleanExpired (kept, now called), so rows last at most their five minutes plus one interval. Nothing else changes in how rows are written or read.
Package: internal/imgcache. Test first: a row past its expiry is gone after the loop runs, without its URL being requested again.
#250 changes the same loop and is started after this lands.
Model: opus-5-5
Plan: the eviction loop deletes expired negative-cache rows at start and on every tick, through `CleanExpired` (kept, now called), so rows last at most their five minutes plus one interval. Nothing else changes in how rows are written or read.
Package: `internal/imgcache`. Test first: a row past its expiry is gone after the loop runs, without its URL being requested again.
https://git.eeqj.de/sneak/pixa/issues/250 changes the same loop and is started after this lands.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Where:
internal/imgcache/cache.golines 433-454 (StoreNegative), 486-497 (CleanExpired, which nothing outside tests calls) and 724-758 (checkNegativeCache);internal/imgcache/service.golines 438-449, onv1.0.0-rc1.What is wrong: every upstream error (any status outside 200-299, a 404 included) inserts a row in
negative_cache, and an expired row is deleted only when the same source URL is requested again after its five minutes.CleanExpiredis dead code. Nothing else removes rows, andcache_max_bytesdoes not cover the database.How it fails: on a deployment with an allowlisted host, an outsider requests
/v1/image/<host>/<a new random path each time>/1x1.jpg; each costs one upstream 404 and leaves one permanent row holding host, path, query and the error text. At the default 600 requests a minute per address, one address adds 864,000 rows a day; the database file grows until the volume is full, after which every write in pixa fails. No operation of pixa ever shrinks it.Severity: medium
Definition of done:
CleanExpiredis called or deleted.make checkgreen.Model: fable-5-1
Plan: the eviction loop deletes expired negative-cache rows at start and on every tick, through
CleanExpired(kept, now called), so rows last at most their five minutes plus one interval. Nothing else changes in how rows are written or read.Package:
internal/imgcache. Test first: a row past its expiry is gone after the loop runs, without its URL being requested again.#250 changes the same loop and is started after this lands.
Model: opus-5-5