Skip to content

Commit a18003d

Browse files
mpasternakclaude
andcommitted
fix: mapuj nazwę hosta zamiast podmieniać ją w URL-u
Wariant z podmianą hosta na host.docker.internal nie działał — sprawdzone na run-site z prawdziwą bazą. Padał z dwóch niezależnych powodów naraz: * connection refused, bo Daphne słucha na JEDNYM interfejsie (100.107.38.27:51656), nie na 0.0.0.0, więc brama Dockera trafiała w adres hosta, na którym nic nie nasłuchuje; * HTTP 400 DisallowedHost, bo podmiana hosta zmienia nagłówek Host na taki, którego Django nie zna. Ten błąd był maskowany przez pierwszy. Rozwiązanie odwraca problem: URL zostaje nietknięty, mapujemy nazwę przez --add-host=<host>:<IP>. TCP idzie na realny adres, Host zostaje ten, którego Django oczekuje. Porównanie nazw jest case-insensitive: hostname -s zwraca "Mac-mini", a banner run-site podaje "mac-mini". Bez tego gałąź się nie odpala, a objaw wygląda na problem sieciowy zamiast na literówkę. Osobno: oba tory uruchamiają walidator z katalogiem roboczym w cache'u. Walidator pisze do względnego data/, więc uruchomiony z korzenia repo zasypywał BPP setkami nieśledzonych plików (157 po jednym przebiegu). Zweryfikowane end-to-end przeciw endpointowi BPP z dumpu: oba tory dają OK (13 tests), repo zostaje czyste. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e8ae07c commit a18003d

2 files changed

Lines changed: 80 additions & 25 deletions

File tree

‎Makefile‎

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,13 @@ tests-with-microsoft-auth: enable-microsoft-auth tests-without-playwright-with-m
372372
#
373373
# Wymagania: JRE 17+ ALBO Docker. Mavena i JDK nie trzeba.
374374
#
375+
# Oba tory uruchamiają walidator z katalogiem roboczym ustawionym na cache,
376+
# NIE na korzeń repo: walidator zapisuje pobrane odpowiedzi OAI-PMH do
377+
# WZGLĘDNEGO katalogu data/ (CRISValidator:
378+
# `new FileLoggingConnectionStreamFactory("data")`), więc uruchomiony stąd
379+
# zasypałby repo setkami nieśledzonych plików. Tor javowy dostaje `cd`,
380+
# dockerowy — montowanie tej samej ścieżki na /work/data.
381+
#
375382
# Użycie: make cerif-validate URL=https://twoja-instancja/cerif-oai/
376383
CERIF_VALIDATOR_VERSION ?= v2.1.1-iplweb.1
377384
# Poza drzewem repo celowo: `make clean` robi `rm -rf .cache` (patrz
@@ -453,23 +460,45 @@ cerif-validate: ## Waliduj endpoint CERIF (URL=...) walidatorem euroCRIS
453460
fi; \
454461
if [ "$$java_ok" = 1 ]; then \
455462
$(MAKE) --no-print-directory "$(_cerif_jar)" && \
456-
java -jar "$(_cerif_jar)" "$(URL)"; \
463+
( cd "$(CERIF_VALIDATOR_CACHE)" && java -jar "$(_cerif_jar)" "$(URL)" ); \
457464
elif command -v docker >/dev/null 2>&1; then \
458465
echo "Używam obrazu $(CERIF_VALIDATOR_IMAGE):$(_cerif_image_tag)"; \
459-
url="$(URL)"; \
460-
host=$$(printf '%s' "$$url" | sed -E 's#^[a-zA-Z]+://([^/:]+).*#\1#'); \
461-
case "$$host" in \
462-
localhost|127.0.0.1|0.0.0.0|::1|"$$(hostname)"|"$$(hostname -s)") \
463-
url=$$(printf '%s' "$$url" | sed -e "s#//$$host#//host.docker.internal#"); \
464-
echo "UWAGA: kontener nie ma dostępu do '$$host' — podmieniam na $$url"; \
465-
echo " Django musi mieć host.docker.internal w ALLOWED_HOSTS,"; \
466-
echo " a na Linuksie serwer musi słuchać na 0.0.0.0, nie 127.0.0.1."; \
466+
host=$$(printf '%s' "$(URL)" | sed -E 's#^[a-zA-Z]+://([^/:]+).*#\1#'); \
467+
addhost=""; \
468+
lc() { printf '%s' "$$1" | tr 'A-Z' 'a-z'; }; \
469+
host_lc=$$(lc "$$host"); \
470+
self_lc=$$(lc "$$(hostname)"); \
471+
self_short_lc=$$(lc "$$(hostname -s)"); \
472+
case "$$host_lc" in \
473+
localhost|127.0.0.1|0.0.0.0|::1) \
474+
addhost="--add-host=$$host:host-gateway"; \
475+
echo "UWAGA: '$$host' w kontenerze wskazuje na sam kontener —"; \
476+
echo " mapuję na bramę hosta. Serwer MUSI słuchać na 0.0.0.0;"; \
477+
echo " przy bindzie tylko na 127.0.0.1 połączenie będzie odrzucone."; \
478+
;; \
479+
"$$self_lc"|"$$self_short_lc") \
480+
ip=$$(getent hosts "$$host" 2>/dev/null | awk '{print $$1; exit}'); \
481+
[ -n "$$ip" ] || ip=$$(dscacheutil -q host -a name "$$host" 2>/dev/null \
482+
| awk '/^ip_address:/{print $$2; exit}'); \
483+
[ -n "$$ip" ] || ip=$$(ping -c1 -t1 "$$host" 2>/dev/null \
484+
| sed -n '1s/.*(\([0-9.]*\)).*/\1/p'); \
485+
case "$$ip" in \
486+
""|127.*) \
487+
addhost="--add-host=$$host:host-gateway"; \
488+
echo "UWAGA: '$$host' nie rozwiązuje się na adres widoczny z kontenera"; \
489+
echo " — mapuję na bramę hosta."; \
490+
;; \
491+
*) \
492+
addhost="--add-host=$$host:$$ip"; \
493+
echo "Mapuję '$$host' -> $$ip w kontenerze."; \
494+
;; \
495+
esac; \
467496
;; \
468497
esac; \
469498
mkdir -p "$(CERIF_VALIDATOR_CACHE)/data"; \
470-
docker run --rm --add-host=host.docker.internal:host-gateway \
499+
docker run --rm $$addhost \
471500
-v "$(CERIF_VALIDATOR_CACHE)/data:/work/data" \
472-
"$(CERIF_VALIDATOR_IMAGE):$(_cerif_image_tag)" "$$url"; \
501+
"$(CERIF_VALIDATOR_IMAGE):$(_cerif_image_tag)" "$(URL)"; \
473502
else \
474503
echo "Potrzebny JRE 17+ albo Docker. Zainstaluj jedno z:"; \
475504
echo " brew install openjdk@17 # macOS"; \

‎docs/superpowers/specs/2026-08-05-cerif-validator-fork-design.md‎

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -328,20 +328,46 @@ przepływ nie zawiera wcale słowa „localhost" — dokładnie ten przypadek
328328
umknąłby heurystyce. Target wyciąga host z URL-a i porównuje z:
329329
`localhost`, `127.0.0.1`, `0.0.0.0`, `::1`, `$(hostname)`, `$(hostname -s)`.
330330

331-
Przy trafieniu: `--add-host=host.docker.internal:host-gateway` i podmiana
332-
hosta w URL-u, plus ostrzeżenie o dwóch warunkach, bez których i tak nie
333-
zadziała:
334-
335-
- **`ALLOWED_HOSTS`** — kontener wyśle `Host: host.docker.internal`, a Django
336-
odrzuci to `DisallowedHost` (HTTP 400). Walidator zobaczy 400 zamiast
337-
OAI-PMH i wypluje mylący błąd protokołu.
338-
- **bind na Linuksie** — `host-gateway` mapuje na IP bridge'a (`172.17.0.1`),
339-
więc serwer słuchający tylko na `127.0.0.1` odrzuci połączenie mimo
340-
poprawnego DNS-u. Na Docker Desktop (macOS) ruch idzie przez VM i działa
341-
niezależnie od bindu — stąd klasyczne „u mnie działa".
342-
343-
Katalog `data/` z kontenera montowany do cache'u, żeby ścieżka dockerowa
344-
zostawiała ten sam materiał diagnostyczny, co javowa (patrz §5.4).
331+
**Podmiana hosta w URL-u to złe rozwiązanie** — zweryfikowane empirycznie
332+
na `run-site` z prawdziwą bazą. Pierwotny wariant (przepisz host na
333+
`host.docker.internal`) padał z dwóch niezależnych powodów naraz:
334+
335+
1. **`connection refused`** — Daphne słucha na **jednym interfejsie**
336+
(`100.107.38.27:51656`), nie na `0.0.0.0`. Brama Dockera trafia w inny
337+
adres hosta, na którym nic nie nasłuchuje.
338+
2. **HTTP 400 `DisallowedHost`** — po podmianie kontener wysyła
339+
`Host: host.docker.internal`, którego Django nie zna. Walidator widzi 400
340+
zamiast OAI-PMH i zgłasza mylący błąd protokołu. Drugi błąd był maskowany
341+
przez pierwszy.
342+
343+
Rozwiązanie odwraca problem: **nie ruszamy URL-a, mapujemy nazwę.**
344+
`--add-host=<host>:<IP hosta>` sprawia, że TCP idzie na realny adres, a
345+
nagłówek `Host` zostaje ten, którego Django oczekuje. IP rozwiązujemy na
346+
hoście: `getent hosts`, `dscacheutil` (macOS), `ping` jako ostatnia deska.
347+
348+
⚠️ Porównanie nazw **musi być case-insensitive**: `hostname -s` zwraca
349+
`Mac-mini`, a banner `run-site` podaje `mac-mini`. Nazwy hostów są
350+
case-insensitive, więc naiwne `case` je rozjeżdża i gałąź w ogóle się nie
351+
odpala — objaw wygląda wtedy jak problem sieciowy, nie jak literówka.
352+
353+
Dla `localhost`/`127.0.0.1`/`::1`/`0.0.0.0` nie ma dobrego mapowania: zostaje
354+
`host-gateway` plus ostrzeżenie, że serwer musi słuchać na `0.0.0.0`. Tego
355+
ograniczenia nie da się obejść po stronie klienta.
356+
357+
#### Katalog roboczy: cache, nie repo
358+
359+
Walidator zapisuje pobrane odpowiedzi do **względnego** `data/`. Stary target
360+
uruchamiał `java` w katalogu klonu walidatora, więc śmieci lądowały tam.
361+
Naiwne przeniesienie na `java -jar <cache>/…` z korzenia repo zasypuje BPP
362+
setkami nieśledzonych plików (zmierzone: 157 po jednym przebiegu; `data/`
363+
nie jest w `.gitignore`). Oba tory dostają więc katalog roboczy w cache'u:
364+
javowy przez `cd`, dockerowy przez montowanie na `/work/data`.
365+
366+
Efekt uboczny, o którym warto wiedzieć: `data/` przeżywa między przebiegami,
367+
a walidator czyta stamtąd. Po serii nieudanych przebiegów potrafi to dać
368+
fałszywe błędy — jeden przebieg pokazał 2 błędy zaraz po serii zepsutych,
369+
a trzy kolejne czyste `OK (13 tests)`. Przy niewyjaśnionych błędach:
370+
wyczyścić `data/`.
345371

346372
#### Dokumentacja i newsfragment
347373

0 commit comments

Comments
 (0)