Skip to content

fix(favicon): favicon podąża za hostem w multi-tenant (3.7)#653

Open
mpasternak wants to merge 2 commits into
devfrom
fix/favicon-per-host
Open

fix(favicon): favicon podąża za hostem w multi-tenant (3.7)#653
mpasternak wants to merge 2 commits into
devfrom
fix/favicon-per-host

Conversation

@mpasternak

Copy link
Copy Markdown
Member

Problem

Favicon nie podążał za hostem w multi-tenant — django-favicon-plus-reloaded
używa CurrentSiteManager filtrującego po literalnym settings.SITE_ID,
którego SiteResolutionMiddleware nie podmienia. Wszystkie uczelnie dostawały
favicon site'u o SITE_ID (poz. 3.7 audytu).

Zmiana (ścieżka w repo, bez forka biblioteki)

  1. Odczyt per-host: nowy tag place_favicon pyta
    Favicon.objects.filter(site=request.site, isFavicon=True) zamiast globalnego
    managera.
  2. Fragment cache dostał vary_on: {% cache 3600 favicon request.get_host %},
    wpis zdjęty z allowlisty strażnika test_cache_fragmentow_vary_on.py (bo
    fragmenty {% cache %} nie mają hosta w kluczu — reguła Bump mixin-deep from 1.3.1 to 1.3.2 #4 audytu; bez tego
    cache podałby favicon jednej uczelni innej).
  3. Naprawa ścieżki ZAPISU (Critical z review): Favicon.save() biblioteki
    gasił isFavicon po on_site (SITE_ID) → zapis favicona dowolnego tenanta
    gasił favicon tenanta SITE_ID. Monkeypatch Favicon.save w BppConfig.ready()
    zawęża reset do filter(site=self.site). Idempotentny (guard
    _bpp_per_site_patched), obejmuje wszystkie ścieżki zapisu (w tym admin).

Weryfikacja

  • Różne hosty → różne favicony (multi-tenant) na realnym backendzie cache.
  • vary_on (request.get_host) spójny z wymiarem rozdzielczości (host) — brak
    „ten sam klucz, inny favicon"; strażnik zielony, regresja zapewniona z konstrukcji.
  • Test kontrolny clobberingu: bez monkeypatcha zapis tenanta B gasi favicon
    tenanta A (test pada), z patchem przeżywa. Fixture'y używają realnej ścieżki
    save() (nie obchodzą jej przez .update()).
  • Review + re-review: PASS + APPROVED (Critical domknięty, patch idempotentny,
    admin objęty, sygnatura zachowana). 7 passed.

Poz. 3.7 audytu.

🤖 Generated with Claude Code

https://claude.ai/code/session_019GmViAsaif9MXeuDMA5NHX

mpasternak and others added 2 commits July 20, 2026 21:52
`django-favicon-plus-reloaded` renderuje favicon przez `Favicon.on_site`
(CurrentSiteManager), który filtruje po literalnym `settings.SITE_ID`.
`SiteResolutionMiddleware` nie podmienia SITE_ID per request, więc dotąd
wszystkie uczelnie dostawały favicon site'u o SITE_ID zamiast własnego.

Fix bez patchowania biblioteki: nowy tag `bpp.templatetags.favicon_bpp.
place_favicon` pyta zwykły `Favicon.objects` po `request.site` (Host →
Site). Fragment `{% cache 3600 favicon request.get_host %}` w bare.html
dostaje vary_on na hoście, a wpis `favicon` znika z allowlisty strażnika
`test_cache_fragmentow_vary_on.py` — inaczej cache fragmentu podałby
favicon jednej uczelni pod domeną innej.

Testy (na realnym backendzie LocMem): różne hosty → różne favicony,
izolacja cache fragmentu per host, trafienie dla tego samego hosta.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019GmViAsaif9MXeuDMA5NHX
…tenantów

Krytyczny finding z code review: biblioteczny Favicon.save woła
Favicon.on_site.exclude(pk).update(isFavicon=False), a on_site to
CurrentSiteManager po literalnym settings.SITE_ID. Zapis favicona
DOWOLNEGO tenanta gasił więc isFavicon faviconom site'u o SITE_ID
(realnej uczelni) — utworzenie favicona tenanta B kasowało favicon
tenanta A spod SITE_ID.

Monkeypatch Favicon.save w BppConfig.ready() zawęża reset do self.site
(Favicon.objects.filter(site=self.site)) zamiast globalnego on_site.
Obejmuje wszystkie ścieżki zapisu (w tym admin biblioteki).

Test: dodano test clobberingu tworzący favicony NORMALNĄ ścieżką
create()/save() (jak admin) — pada na starej ścieżce bibliotecznej,
przechodzi po patchu. Fixture'y przestały wymuszać isFavicon przez
.update() omijające save() (maskowały buga) i używają teraz save().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019GmViAsaif9MXeuDMA5NHX
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