Delete the kagane-specific cover path (#63)

The web proxy for kagane covers is dead: since #62 every Site's cover
bytes land in the content-addressed store at creation or on the poll,
and the one public route serves them all. Remove the second way to
reach a Cover:

- Bookmark.CoverURL() and the templates' use of it: templates render
  the wire value (.Cover) and nothing else.
- GET /img/kagane/{id}, web.CoverFetcher, coverIDRe: the route and its
  identifier validation are gone, and with them web/cover.go.
- store.KaganeImageID, GetKaganeCover, PutKaganeCover,
  kaganeCoverSourceURL: the proxy's persistence.
- Bookmark.CoverSource: dead once CoverURL is gone.

Acquisition keeps the browser where kagane genuinely needs it, but the
Site name leaves the routing: kaganeImageURLRe lives in browser.go with
the rest of the per-Site knowledge, browserCoverURL claims the URLs the
sidecar alone can fetch, and fetchCoverBytes routes by URL shape with
no Site argument. No plain-TLS fallback for a claimed URL — that would
only retrieve a challenge page.

Cover tests: kagane route tests removed, the general-route guarantees
they pinned kept and re-pinned — unstored and traversal-shaped
addresses serve nothing (TestPublicCoverRejectsUnknownAddress), non-image
content types are never echoed back (TestPublicCoverNeverEchoesNonImage
+ TestCoverStoreAcceptsAnySourceURL). Store content-addressing and
reopen-persistence tests rewritten against PutCover/GetCover.

No Site name remains in a cover code path outside the acquisition
module; go test ./... green.
This commit is contained in:
2026-08-10 11:24:42 +07:00
parent 78234f3c19
commit cce3d61799
16 changed files with 127 additions and 480 deletions
+12 -10
View File
@@ -10,9 +10,10 @@ import (
"bookmarkmanager/backend/internal/store"
)
// TestSmokeKaganeImage is the live proof that the cover proxy's fetch actually
// clears Cloudflare and returns image bytes. It needs the real browser unit
// with outbound network, so it runs only when SMOKE_BROWSER_WS_URL is set:
// TestSmokeKaganeImage is the live proof that the acquisition path's browser
// fetch actually clears Cloudflare and returns image bytes. It needs the real
// browser unit with outbound network, so it runs only when SMOKE_BROWSER_WS_URL
// is set:
//
// cd chrome && BROWSER_BIND_ADDR=127.0.0.1 docker compose up -d --build
// SMOKE_BROWSER_WS_URL=ws://127.0.0.1:9222 go test -run TestSmokeKaganeImage ./internal/latest
@@ -24,12 +25,11 @@ func TestSmokeKaganeImage(t *testing.T) {
if ws == "" {
t.Skip("SMOKE_BROWSER_WS_URL unset")
}
const imageID = "019fe11a-84c3-7fc3-a84b-88787374b617" // SP Baby's cover
const imageURL = "https://kagane.to/api/v2/image/019fe11a-84c3-7fc3-a84b-88787374b617/compressed" // SP Baby's cover
// The same URL through a plain client is what the web UI's <img> gets.
// The same URL through a plain client is what any other fetcher would get.
// Asserting on it keeps the test honest about why the browser is needed.
req, err := http.NewRequest(http.MethodGet,
"https://kagane.to/api/v2/image/"+imageID+"/compressed", nil)
req, err := http.NewRequest(http.MethodGet, imageURL, nil)
if err != nil {
t.Fatal(err)
}
@@ -48,7 +48,7 @@ func TestSmokeKaganeImage(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
body, contentType, err := f.Image(ctx, imageID)
body, contentType, err := f.Image(ctx, imageURL)
if err != nil {
t.Fatalf("Image: %v", err)
}
@@ -64,8 +64,10 @@ func TestSmokeKaganeImage(t *testing.T) {
}
t.Logf("fetched %d bytes of %s", len(body), contentType)
if _, _, err := f.Image(ctx, "not-a-uuid"); err == nil {
t.Fatal("Image accepted a non-uuid id")
// The browser module claims only the cover URL shape it can clear a
// challenge for; anything else must be refused before any navigation.
if _, _, err := f.Image(ctx, "https://cdn.example/cover.jpg"); err == nil {
t.Fatal("Image accepted a cover URL the browser module does not claim")
}
}