Ver Fonte

DISCORD_TOKEN="" : refusé comme une variable absente

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet há 9 horas atrás
pai
commit
bb1bd33572
3 ficheiros alterados com 15 adições e 9 exclusões
  1. 0 2
      CHANGELOG.md
  2. 7 7
      bot/config.py
  3. 8 0
      tests/test_config.py

+ 0 - 2
CHANGELOG.md

@@ -18,8 +18,6 @@ Les versions les plus récentes sont en haut. Chaque entrée commence par un ré
 
 ### Corrections
 
-- **`EFFORT` invalide avec la mémoire : un message clair.** Avec `MEMORY=on` et la réflexion active (`THINKING=on`, ou un modèle Opus), une valeur inconnue comme `EFFORT=ultra` faisait planter le démarrage avec une trace Python (`KeyError: 'ultra'`) au lieu du message « Erreur de configuration ». La valeur fausse n'est plus réutilisée dans la vérification de `MAX_TOKENS`.
-
 - **Erreurs de démarrage : toutes d'un coup, et dans `bot.log`.** Le bot s'arrêtait à la première variable fausse du `.env` : avec trois erreurs, il fallait trois redémarrages. Il les liste maintenant toutes. Le message n'était écrit que sur la console : il va aussi dans `bot.log` quand `LOG_FILE` est utilisable, pour qu'un redémarrage raté y laisse une trace. Enfin, un PC hors ligne ou une panne de Discord au démarrage donnaient une longue trace technique ; le bot dit maintenant « Impossible de joindre Discord : vérifie la connexion Internet » ou « Discord semble en panne ».
 
 - **Un `.env` entre guillemets marche aussi sous Docker.** `docker run --env-file` garde les guillemets que le bot retire en local : `DISCORD_TOKEN="abc"` donnait « Token Discord invalide » sous Docker. Le bot retire maintenant lui-même une paire de guillemets autour d'une valeur. Le README précise que `--env-file` ne retire pas les commentaires en fin de ligne, et que le `.env` est prioritaire sur une variable passée en ligne de commande.

+ 7 - 7
bot/config.py

@@ -41,16 +41,16 @@ class ConfigError(Exception):
 
 
 def _get_str(name: str, default: str | None = None, required: bool = False) -> str | None:
-    value = os.getenv(name)
-    if value is None or value.strip() == "":
-        if required:
-            raise ConfigError(f"La variable {name} est obligatoire mais absente du fichier .env.")
-        return default
-    value = value.strip()
+    value = (os.getenv(name) or "").strip()
     # docker run --env-file garde les guillemets que python-dotenv retire : DISCORD_TOKEN="abc".
     if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'":
         value = value[1:-1].strip()
-    return value or default
+    # Après les guillemets : DISCORD_TOKEN="" est vide, pas une valeur.
+    if not value:
+        if required:
+            raise ConfigError(f"La variable {name} est obligatoire mais absente ou vide dans le fichier .env.")
+        return default
+    return value
 
 
 def _get_int(name: str, default: int | None = None, required: bool = False, minimum: int | None = None,

+ 8 - 0
tests/test_config.py

@@ -102,6 +102,14 @@ class AllErrorsTest(unittest.TestCase):
                      "DISCORD_TOKEN est obligatoire"):
             self.assertIn(text, str(ctx.exception))
 
+    def test_empty_quotes_count_as_missing(self):
+        # docker run --env-file garde les guillemets : DISCORD_TOKEN="" ne doit pas passer pour une valeur.
+        for name in ("DISCORD_TOKEN", "ANTHROPIC_API_KEY", "CHANNEL_ID"):
+            for raw in ('""', "''", '" "'):
+                with self.subTest(name=name, raw=raw), self.assertRaises(ConfigError) as ctx:
+                    settings(**{name: raw})
+                self.assertIn(f"{name} est obligatoire", str(ctx.exception))
+
     def test_invalid_value_not_reused_in_other_checks(self):
         # MAX_TOKENS illisible : pas de second message sur la mémoire, ni pour THINKING invalide avec EFFORT=max.
         with self.assertRaises(ConfigError) as ctx: