1.0.5 — affichage des notices et progression
CI / Backend — lint, types, tests (push) Successful in 34s
CI / Interface — types et compilation (push) Successful in 16s
CI / Construction des images (sans publication) (push) Successful in 1m35s
Publication / Images vers Harbor (push) Successful in 2m34s

This commit is contained in:
hcornet committed 2026-09-12 19:44:36 +02:00
1 parent eb38aa9c11
commit 5bccd86edc
10 files changed
+111 -33

No files matched your search

+14
View File
@@ -2,6 +2,20 @@
Format inspiré de [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/).
## [1.0.5] — 2026-09-12
### Corrigé
- **Les messages internes de Maigret noyaient les résultats.** « Restarting
checks for 98 sites », « 0 extra requests performed » et consorts sont
destinés à sa sortie terminal ; affichés dans l'interface, ils repoussaient
les résultats hors de l'écran. Ils sont désormais filtrés.
- **Le bilan des blocages était répété par variante** — cinq avertissements
quasi identiques pour une même cause. Il est cumulé et émis une seule fois en
fin de recherche, avec le taux global et le renvoi vers la documentation.
- **La progression affichait « 945 / 833 ».** Maigret relance les sites en
échec, si bien que le nombre de vérifications dépasse le total estimé. La
valeur affichée est bornée.
## [1.0.4] — 2026-09-12
### Corrigé
+1 -1
View File
@@ -1 +1 @@
1.0.4
1.0.5
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "limier"
version = "1.0.4"
version = "1.0.5"
description = "Plateforme OSINT auto-hébergée : pseudonyme, nom, e-mail, domaine"
requires-python = ">=3.12,<3.14"
license = { text = "MIT" }
+1 -1
View File
@@ -1,3 +1,3 @@
"""Limier — plateforme OSINT auto-hébergée."""
__version__ = "1.0.4"
__version__ = "1.0.5"
+65 -18
View File
@@ -49,6 +49,24 @@ _logger_maigret.setLevel(logging.WARNING)
TAILLE_FILE = 2000
# Messages internes de Maigret sans valeur pour l'utilisateur : relances,
# compteurs de requêtes supplémentaires, bannières. Les laisser passer noie les
# résultats sous des dizaines de lignes, comme observé en conditions réelles.
BRUIT_MAIGRET = (
"restarting checks",
"extra requests performed",
"you can run search",
"starting a search",
"checking username",
"database",
"db auto-update",
"using sites database",
"support maigret",
"donate",
"detailed site check errors",
"extracted ids",
)
SEUIL_ALERTE_BLOCAGE = 0.15
"""Part de sites non vérifiables au-delà de laquelle on prévient l'utilisateur.
@@ -172,6 +190,28 @@ class MoteurPseudonyme(Engine):
):
yield evenement
async for evenement in self._bilan(compteur):
yield evenement
async def _bilan(self, compteur: dict[str, int]):
"""Avertissement unique de fin de recherche sur la couverture réelle."""
bloques = compteur.get("bloques", 0)
interroges = compteur.get("interroges", 0)
if not interroges:
return
taux = bloques / interroges
if taux > SEUIL_ALERTE_BLOCAGE:
yield NoticeEvent(
module=self.name,
level="warning",
message=(
f"{bloques} vérifications sur {interroges} ({taux:.0%}) ont échoué — "
"blocage anti-robot, captcha ou délai dépassé. Les résultats sont "
"partiels. Activer FlareSolverr ou un pool de proxies améliore "
"cette couverture (voir docs/06-exploitation.md)."
),
)
# -------------------------------------------------------------- interne
async def _chercher_un(
@@ -234,9 +274,12 @@ class MoteurPseudonyme(Engine):
if statut.startswith("Unknown"):
erreurs_reseau += 1
if compteur["faits"] % 10 == 0:
# Maigret relance les sites en échec : le nombre de
# vérifications dépasse alors le total estimé. On borne
# plutôt que d'afficher « 945 / 833 ».
yield ProgressEvent(
module=self.name,
done=compteur["faits"],
done=min(compteur["faits"], compteur["total"]),
total=compteur["total"],
label=label,
)
@@ -260,10 +303,13 @@ class MoteurPseudonyme(Engine):
yield evenement
elif genre == "notice":
message = charge.get("message", "")
if not _message_utile(message):
continue
yield NoticeEvent(
module=self.name,
level=charge.get("level", "info"),
message=charge.get("message", ""),
message=message,
)
try:
@@ -280,27 +326,20 @@ class MoteurPseudonyme(Engine):
)
return
if erreurs_reseau:
taux = erreurs_reseau / max(1, len(sites))
if taux > SEUIL_ALERTE_BLOCAGE:
await self.proxies.signaler_echec(proxy)
yield NoticeEvent(
module=self.name,
level="warning",
message=(
f"{erreurs_reseau} sites sur {len(sites)} n'ont pas pu être "
"vérifiés (blocage ou délai dépassé). Les résultats sont "
"partiels — voir la sortie réseau dans la documentation."
),
)
else:
await self.proxies.signaler_succes(proxy)
# Le bilan des blocages est cumulé puis émis une seule fois en fin de
# recherche : le répéter par variante produisait cinq avertissements
# quasi identiques pour une même cause.
compteur["bloques"] = compteur.get("bloques", 0) + erreurs_reseau
compteur["interroges"] = compteur.get("interroges", 0) + len(sites)
if erreurs_reseau / max(1, len(sites)) > SEUIL_ALERTE_BLOCAGE:
await self.proxies.signaler_echec(proxy)
else:
await self.proxies.signaler_succes(proxy)
yield ProgressEvent(
module=self.name,
done=compteur["faits"],
done=min(compteur["faits"], compteur["total"]),
total=compteur["total"],
label=label,
)
@@ -391,3 +430,11 @@ class MoteurPseudonyme(Engine):
if 2 < len(candidat) < 40 and " " not in candidat:
trouves[candidat] = site
return trouves
def _message_utile(message: str) -> bool:
"""Écarte le bavardage interne de Maigret destiné à sa sortie terminal."""
if not message or len(message) < 8:
return False
minuscule = message.lower()
return not any(bruit in minuscule for bruit in BRUIT_MAIGRET)
+1 -1
View File
@@ -7,7 +7,7 @@
# ---------------------------------------------------------------------------
REGISTRY=registry.tips-of-mine.com
TAG=1.0.4
TAG=1.0.5
LIMIER_HOST=limier.tips-of-mine.com
LIMIER_PUBLIC_URL=https://limier.tips-of-mine.com
LIMIER_ENVIRONMENT=prod
+4 -4
View File
@@ -56,7 +56,7 @@ x-limier-env: &limier-env
services:
limier-api:
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-backend:${TAG:-1.0.4}
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-backend:${TAG:-1.0.5}
container_name: limier-api
restart: unless-stopped
command: ["limier-api"]
@@ -99,7 +99,7 @@ services:
- "homepage.description=Plateforme OSINT"
limier-worker:
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-backend:${TAG:-1.0.4}
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-backend:${TAG:-1.0.5}
container_name: limier-worker
restart: unless-stopped
command: ["limier-worker"]
@@ -122,7 +122,7 @@ services:
- "com.centurylinklabs.watchtower.enable=true"
limier-web:
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-frontend:${TAG:-1.0.4}
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-frontend:${TAG:-1.0.5}
container_name: limier-web
restart: unless-stopped
volumes:
@@ -205,7 +205,7 @@ services:
# ``--profile``, pour que l'installation par défaut reste minimale.
limier-holehe:
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-holehe:${TAG:-1.0.4}
image: ${REGISTRY:-registry.tips-of-mine.com}/limier/limier-holehe:${TAG:-1.0.5}
container_name: limier-holehe
restart: unless-stopped
profiles: ["holehe"]
+3 -3
View File
@@ -12,7 +12,7 @@ Ni base de données, ni Redis, ni Authentik. On appelle le moteur directement.
cd /opt # ou n'importe où, il suffit d'avoir essai_moteur.py sous la main
docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \
registry.tips-of-mine.com/limier/limier-backend:1.0.4 \
registry.tips-of-mine.com/limier/limier-backend:1.0.5 \
python /tmp/essai.py domain tips-of-mine.com
```
@@ -24,7 +24,7 @@ Le moteur pseudonyme, en version courte :
```bash
docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \
-e LIMIER_USERNAME_TOP_SITES=80 \
registry.tips-of-mine.com/limier/limier-backend:1.0.4 \
registry.tips-of-mine.com/limier/limier-backend:1.0.5 \
python /tmp/essai.py username soxoj
```
@@ -33,7 +33,7 @@ Et la recherche par nom, qui montre les variantes déduites :
```bash
docker run --rm -v "$PWD/essai_moteur.py:/tmp/essai.py" \
-e LIMIER_USERNAME_TOP_SITES=60 \
registry.tips-of-mine.com/limier/limier-backend:1.0.4 \
registry.tips-of-mine.com/limier/limier-backend:1.0.5 \
python /tmp/essai.py name "Hubert Cornet"
```
+20 -3
View File
@@ -73,7 +73,24 @@ attachés à ton entryPoint `https` et s'appliquent automatiquement.
Les priorités de routeurs sont explicites : l'API à 60, l'interface à 50.
Sans cela, la règle `Host()` seule de `limier-web` capterait aussi `/api`.
## 4. Migrations puis démarrage
## 4. Droits du volume de la base de sites
Les conteneurs tournent en utilisateur non privilégié (UID 1000). Docker crée
les répertoires de montage en `root`, et ce montage masque les droits posés
dans l'image : le worker ne peut alors pas y écrire la base de sites mise à
jour, et reste sur les 3 302 sites livrés dans le paquet au lieu des 5 400+
disponibles en amont.
```bash
mkdir -p /opt/limier/data/sites
chown -R 1000:1000 /opt/limier/data/sites
```
Le symptôme, si on l'oublie : `copie_base_sites_impossible` avec
`Permission denied` dans le journal du worker, et `base_sites_prete` annonçant
3 302 sites au lieu de 5 442.
## 5. Migrations puis démarrage
```bash
docker compose run --rm limier-api alembic upgrade head
@@ -86,7 +103,7 @@ curl -s https://limier.tips-of-mine.com/api/pret | jq
complétude de la configuration. C'est la sonde à regarder quand « ça ne marche
pas ». `/api/sante` est la sonde du healthcheck Docker, volontairement triviale.
## 5. Modules optionnels
## 6. Modules optionnels
```bash
# holehe — lire services/holehe/app.py avant d'activer
@@ -101,7 +118,7 @@ docker compose --profile flaresolverr up -d
Sans `--profile`, ces services ne démarrent pas : l'installation par défaut
reste minimale.
## 6. Mise à jour
## 7. Mise à jour
```bash
cd /opt/limier
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "limier-frontend",
"version": "1.0.4",
"version": "1.0.5",
"private": true,
"type": "module",
"scripts": {