Audit — variables d'environnement a fallback vide
15 aout 2026. Declenche par le defaut ContextIQ (#429) : un badge qui proposait d'installer une extension deja installee, parce que la variable qui commandait la detection n'etait definie nulle part.
15 aout 2026. Declenche par le defaut ContextIQ (#429) : un badge qui proposait d'installer une extension deja installee, parce que la variable qui commandait la detection n'etait definie nulle part.
Le constat en un paragraphe
Le probleme n'est pas le fallback "". Il est legitime : il permet
au produit de demarrer sans que chaque integration optionnelle soit
configuree. Le probleme est qu'une variable absente peut couper une
fonctionnalite sans que personne, ni operateur ni developpeur, ne
puisse l'apprendre. Le repo possede pourtant deja l'outil pour le dire,
/admin/operations/env-audit, mais il ne voit qu'un tiers du parc.
Chiffres
| Mesure | Valeur |
|---|---|
Variables declarees dans serverEnv | 175 |
Dont fallback ?? "" | 158 |
Enregistrees dans le manifeste env-audit.ts | 56 |
| Invisibles au dashboard operateur | 119 |
| Invisibles + gatees sans aucun log ni throw | 74 |
| Invisibles + gatees + sans intention ecrite | 38 |
Declarees sans aucun consommateur dans src/ | 9 |
La distinction qui compte
Un fallback vide n'est dangereux que lorsque rien n'enonce ce qui se passe sans la variable. Deux contre-exemples sains, trouves pendant l'audit :
NEXT_PUBLIC_WHATSAPP_NUMBER—whatsapp-qr-block.tsxecrit noir sur blanc : « Falls back to a "coming soon" toast when [...] is not set, the QR still renders so the layout holds ». Comportement voulu, connu.NEXT_PUBLIC_SUPPORT_CHAT_PROVIDER— « Default off: explicit opt-in via env so dev/preview don't ping the provider ». Idem.
Ces deux-la ont un fallback vide et ne sont pas des bugs. La signature du defaut ContextIQ etait autre : aucun commentaire, aucun log, aucune entree de manifeste. Le code sortait simplement de la fonction.
Les 38 a la signature ContextIQ
Invisibles au dashboard, gatees sans log, et sans intention ecrite au point de consommation. Ce n'est pas une liste de bugs confirmes : c'est la liste de celles ou, comme pour ContextIQ, rien ne permet de savoir si l'etat eteint est voulu. Chacune demande une lecture de son consommateur pour trancher.
Les plus exposees, parce qu'elles commandent une surface visible :
| Variable | Ce qu'elle commande |
|---|---|
NEXT_PUBLIC_HUME_CONFIG_ID | session vocale @Atlas (bouton d'appel du composer) |
NEXT_PUBLIC_HEYO_PROJECT_ID | widget de support Heyo |
NEXT_PUBLIC_BASE_URL | URLs absolues cote client |
INVITATION_CODE | acces par code d'invitation |
LAUNCH_PHASE | phase de lancement affichee |
MAX_CONVERSATION_USD | garde-fou de cout par conversation |
TRACKING_SYSTEM_PASSWORD | acces au systeme de tracking |
UPSTASH_REDIS_REST_URL / _TOKEN | cache Redis (double des cles KV_REST_API_*) |
Le reste — cles fournisseurs (AHREFS, SEMRUSH, DATOS,
DATAFORSEO...), reglages d'intelligence, verifications de moteurs de
recherche, drapeaux de fonctionnalite : est vraisemblablement optionnel
par nature, mais aucun ne le dit.
Variables mortes
Declarees dans serverEnv, lues nulle part dans src/ :
AI_MODEL_WEBSEARCH · BOOSTECOM_CORS_ORIGINS ·
DATABASE_POSTGRES_PASSWORD · DATABASE_POSTGRES_USER ·
KV_REST_API_READ_ONLY_TOKEN · PORT · SHOPIFY_PARTNERS_API_TOKEN ·
SHOPIFY_PARTNERS_ORG_ID · SHOPIFY_REDIRECT_URI
Certaines sont injectees par une integration Vercel et legitimement
inutilisees cote code (DATABASE_POSTGRES_*, KV_REST_API_READ_ONLY_TOKEN).
Les autres meritent un coup d'oeil : SHOPIFY_PARTNERS_* et
SHOPIFY_REDIRECT_URI ressemblent a du cablage inacheve.
Ce qui a ete fait
src/test/env-audit-coverage.test.ts — un cliquet, pas un grand
nettoyage. Trois invariants :
- toute variable de
serverEnva une entree de manifeste, sauf les 119 explicitement derogees ; - la liste de derogation reste honnete (pas d'entree deja enregistree ou plus declaree) ;
- le manifeste ne nomme pas une variable que
serverEnvne lit pas, elle serait affichee MISSING a jamais.
La dette est donc gelee : elle peut diminuer, plus grandir. Une nouvelle variable non enregistree fait echouer la suite en nommant la coupable. Verifie empiriquement : sortir une cle de la derogation fait bien tomber le test.
Ce qui reste a faire
- Reduire la derogation. 119 entrees a documenter dans
env-audit.ts(nom, categorie, severite, description, casse). C'est mecanique mais demande la connaissance metier de chaque variable — par lots, par pilier. - Trancher les 38. Pour chacune : soit ecrire l'intention au point de consommation, soit l'enregistrer au manifeste, soit la supprimer.
- Les 9 mortes. Confirmer l'injection Vercel pour les unes, supprimer ou cabler les autres.
- La lecon de forme. ContextIQ gatait sur une config ce qui etait
une donnee publique : l'ID est dans l'URL du store et dans la
barre d'adresse de tout utilisateur. Une valeur non secrete n'a pas a
vivre uniquement dans l'environnement : lui donner une constante de
repli (ce que fait deja
APP_URLdansconfig/platform.ts) supprime la panne silencieuse a la racine.