fix(static): nie fabrykuj hashy bez manifestu w TolerantManifestStaticFilesStorage#276
Merged
Conversation
…cFilesStorage Follow-up do #272/#269. Bez `staticfiles.json` (dev/testy bez collectstatic, albo stary `staticroot` sprzed Manifestu) vanilla `ManifestFilesMixin.stored_name` z `manifest_strict=False` liczył content-hash w locie dla pliku leżącego w STATIC_ROOT → zwracał `name.<hash>.ext`, czyli URL do pliku, którego fizycznej kopii nikt nie wygenerował. Efekt lokalnie (pod pytest `DEBUG=False`, więc short-circuit DEBUG w `.url()` nie ratuje): django-compressor rzucał `UncompressableFileError`, a bezpośredni GET (webtest) dostawał 404 — `test_admin_compression` i `import_list_if/test_views` padały. Na CII przechodziło, bo test-runner ma pusty STATIC_ROOT (`grunt build-non-interactive` pomija collectstatic) → `hashed_name` rzucał `ValueError` → łapane → nazwa nie-hashowana. Override `stored_name`: gdy `hashed_files` jest puste (brak manifestu) zwróć nazwę oryginalną zamiast martwego hasha. Gating na pusty manifest jest wąski — gdy collectstatic wygenerował manifest (produkcja, `.baked`), delegujemy do vanilla, więc cache-busting długiego ogona działa 1:1. Build-time `post_process` używa osobnej ścieżki (`_stored_name`), więc override go nie dotyka. Testy: regresja (plik w STATIC_ROOT + brak manifestu → nazwa oryginalna, kontrast z vanilla fabrykującym hash) + guard produkcyjny (manifest obecny → nadal hash). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Po zmergowaniu #272 testy
pbn_import/tests/test_admin_compression.py(2×) iimport_list_if/tests/test_views.py(2×) padały lokalnie, choć przechodziłyna CI:
Root cause
TolerantManifestStaticFilesStoragemamanifest_strict=False. Gdy nie mamanifestu (
staticfiles.json), vanillaManifestFilesMixin.stored_nameliczy content-hash w locie dla każdego pliku leżącego w
STATIC_ROOTizwraca
name.<hash>.ext— URL do pliku, którego fizycznej kopii nikt nigdy niewygenerował (stary collectstatic zrobił tylko nie-hashowaną kopię).
staticrootsprzed wprowadzeniaManifestu (same nie-hashowane pliki, bez
staticfiles.json) → martwe URL-e →compressor
UncompressableFileError, webtest 404 (request.user).STATIC_ROOT(grunt build-non-interactivepomija
shell:collectstatic) →hashed_namerzucaValueError→ łapane →nazwa nie-hashowana → przechodzi.
DEBUG=False, więc short-circuit DEBUG wHashedFilesMixin.url()(który w
runserverzwróciłby nazwę nie-hashowaną) nie ratuje.Czyli zachowanie testów zależało od przypadkowego stanu lokalnego
staticroot—nie-hermetyczne.
Fix
Override
stored_name: gdyhashed_filesjest puste (brak manifestu) zwróćnazwę oryginalną zamiast fabrykować martwy hash. Manifest jest jedynym
źródłem prawdy dla hashy; bez niego realny plik źródłowy zaserwuje
finder/runserver/whitenoise.
Gating na pusty manifest jest celowo wąski:
.bakedpo collectstatic) ma pełny manifest →hashed_filesniepuste → delegujemy do vanilla → cache-busting długiego ogona działa 1:1.
post_processużywa osobnej ścieżki (_stored_name,force=True),więc ten override jej nie dotyka.
collectstaticzostaje wyłącznie w build-time (nie dokładamy go do testów — CIcelowo go nie odpala, byłoby wolne i kruche).
Weryfikacja
test_existing_file_without_manifest_is_not_hashed_on_the_fly— przed fixem zwracał
foo.<hash>.css, po fixiefoo.css; kontrast z vanilladowodzi że to nasza subklasa daje wynik. Plus
test_present_manifest_still_hashes(guard produkcyjny).
7 passed.(collectstatic → usunięty manifest + 1640 hashowanych kopii, zostały same
nie-hashowane), 4 wcześniej padające testy →
4 passed.🤖 Generated with Claude Code