Variables d'environnement¶
Référence des variables déclarées dans .env à la racine du dépôt. .env ne contient que des valeurs par défaut non secrètes et est versionné.
Gestion des secrets
- Les credentials réels (mots de passe, clés API, tokens, DSN avec mot de passe) vivent dans
.env.local, non versionné (présent dans.gitignore). - En production, les secrets sont injectés via les variables d'environnement du
docker-compose.prod.ymlou un gestionnaire externe. Ils ne transitent jamais par Git. - En cas de fuite : changer immédiatement la valeur dans tous les environnements avant de chercher la cause.
Symfony charge les variables dans l'ordre suivant : .env → .env.local → variables d'environnement du process. La dernière valeur lue gagne.
À surcharger obligatoirement en production¶
Les valeurs présentes dans .env sont des valeurs factices destinées au seul environnement de développement local. Elles ne doivent jamais être utilisées en production. Avant tout déploiement, vérifier que chacune des variables ci-dessous est définie via compose.prod.yaml ou un gestionnaire de secrets externe :
| Variable | Risque si non surchargée |
|---|---|
APP_SECRET |
Signature CSRF et cookies prévisibles → forge de session possible. |
POSTGRES_PASSWORD |
Mot de passe !ChangeMe! connu publiquement (versionné) → accès BDD trivial. |
DATABASE_URL |
Contient POSTGRES_PASSWORD — recomposer ou réutiliser le DSN avec le nouveau mot de passe. |
RABBITMQ_USER / RABBITMQ_PASSWORD |
Couple guest/guest par défaut → prise de contrôle du bus de messages. |
MESSENGER_TRANSPORT_DSN |
Contient les credentials RabbitMQ — à recomposer en cohérence. |
CADDY_MERCURE_JWT_SECRET |
Secret connu → forge de JWT Mercure (publication arbitraire d'événements SSE). |
TYPESENSE_API_KEY |
Clé xyz-dev-key connue → lecture/écriture arbitraire dans l'index de recherche. |
TRUSTED_HOSTS |
Regex permissive (localhost, 127.0.0.1…) → Host: spoofing possible. À restreindre au domaine cible. |
SERVER_NAME |
localhost par défaut → certificats Caddy invalides en prod. À fixer au domaine réel. |
SENTRY_DSN |
Vide → aucune télémétrie d'erreurs en prod. À renseigner. |
GRAYLOG_HOST |
Vide → aucun log centralisé en prod. À renseigner. |
Règle absolue
Aucune valeur secrète ne transite par Git. Si l'une des valeurs ci-dessus est jamais commitée par erreur (même brièvement), la considérer comme compromise et la régénérer dans tous les environnements avant de chercher la cause de la fuite.
Framework Symfony¶
| Variable | Défaut | Rôle |
|---|---|---|
APP_ENV |
dev |
Environnement applicatif (dev, test, prod). |
APP_SECRET |
!ChangeMe! |
Secret utilisé pour la signature CSRF, les cookies, etc. À surcharger en prod. |
TRUSTED_PROXIES |
127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 |
Liste CIDR des proxies de confiance. Définie inline dans compose.yaml pour Docker networking — ne pas redéfinir sauf en prod derrière un proxy personnalisé. |
TRUSTED_HOSTS |
^(kirexo\.com\|kirexo\.co\|kirexo\.app\|localhost\|127\.0\.0\.1)$ |
Expression régulière des Host autorisés. Définie inline dans compose.yaml. À surcharger en prod pour n'autoriser que votre domaine. |
DEFAULT_URI |
https://localhost |
URI de base pour la génération d'URL dans les contextes non-HTTP (commandes Symfony Console, Messenger workers). |
FrankenPHP / Caddy¶
| Variable | Défaut | Rôle |
|---|---|---|
SERVER_NAME |
localhost |
Nom de domaine(s) sur lequel Caddy écoute. FrankenPHP le lit au démarrage du conteneur. En prod, définir la valeur exacte du domaine (ex. www.kirexo.fr). Utilisé aussi comme label Traefik dans compose.prod.yaml. |
CADDY_MERCURE_JWT_SECRET |
!ChangeThisMercureHubJWTSecretKey! |
Secret utilisé pour signer et vérifier les JWT Mercure (SSE). En dev, la valeur par défaut est suffisante — À surcharger en prod par une valeur aléatoire forte. Dérive les variables MERCURE_PUBLISHER_JWT_KEY et MERCURE_SUBSCRIBER_JWT_KEY exposées au conteneur. |
Doctrine / PostgreSQL¶
| Variable | Défaut | Rôle |
|---|---|---|
POSTGRES_DB |
app |
Nom de la base. |
POSTGRES_USER |
app |
Utilisateur PostgreSQL. |
POSTGRES_PASSWORD |
!ChangeMe! |
Mot de passe PostgreSQL. À surcharger en prod. |
POSTGRES_VERSION |
16 |
Version de Postgres (utilisée par Doctrine et l'image du conteneur). |
DATABASE_URL |
postgresql://app:!ChangeMe!@database:5432/app?serverVersion=16&charset=utf8 |
DSN Doctrine complet. Recomposé à partir des variables ci-dessus. |
Messenger / RabbitMQ¶
| Variable | Défaut | Rôle |
|---|---|---|
RABBITMQ_USER |
guest |
Utilisateur RabbitMQ. |
RABBITMQ_PASSWORD |
guest |
Mot de passe RabbitMQ. À surcharger en prod. |
MESSENGER_TRANSPORT_DSN |
amqp://guest:guest@rabbitmq:5672/%2f/messages |
DSN du transport Messenger principal (bus de commandes async). |
Redis¶
| Variable | Défaut | Rôle |
|---|---|---|
REDIS_URL |
redis://redis:6379 |
URL de connexion Redis. Utilisée par : le pool de cache applicatif (config/packages/cache.yaml), le handler de session HTTP (config/packages/framework.yaml) et — par défaut en dev — le store de verrouillage Symfony Lock (cf. LOCK_DSN). |
Typesense¶
| Variable | Défaut | Rôle |
|---|---|---|
TYPESENSE_HOST |
typesense |
Hôte du moteur de recherche Typesense. |
TYPESENSE_PORT |
8108 |
Port Typesense. |
TYPESENSE_API_KEY |
xyz-dev-key |
Clé API Typesense. À surcharger en prod. |
Gotenberg¶
| Variable | Défaut | Rôle |
|---|---|---|
GOTENBERG_URL |
http://gotenberg:3000 |
URL du service Gotenberg (génération PDF). |
Mailer¶
| Variable | Défaut | Rôle |
|---|---|---|
MAILER_DSN |
smtp://mailer:1025 |
DSN du mailer Symfony. En dev, pointe sur Mailpit (aucun mail ne sort de la machine). |
Symfony Lock¶
| Variable | Défaut | Rôle |
|---|---|---|
LOCK_DSN |
redis://redis:6379 |
DSN du store de verrouillage distribué. Redis est utilisé par défaut pour que les verrous soient partagés entre le serveur web FrankenPHP et les workers Messenger — flock (lock fichier système) ne fonctionnerait qu'au sein d'un seul processus / filesystem. En prod multi-instance, le même DSN convient ; pour une dépendance moindre on peut basculer sur postgresql+advisory://…. |
Observabilité¶
| Variable | Défaut | Rôle |
|---|---|---|
SENTRY_DSN |
(vide) | DSN Sentry. Vide en dev, injecté en prod. |
GRAYLOG_HOST |
(vide) | Hôte Graylog pour les logs GELF/UDP. Vide en dev — aucun service Graylog local n'est démarré. En prod, pointer vers votre instance Graylog. |
GRAYLOG_PORT |
12201 |
Port Graylog (GELF UDP). |
Graylog — prod uniquement
Le handler Monolog gelf n'est activé que sous when@prod (voir config/packages/monolog.yaml). En dev, les logs partent uniquement dans les fichiers Monolog / la console Symfony. Si GRAYLOG_HOST est vide en prod, le handler UDP échoue silencieusement — Monolog capture l'erreur de transport sans interrompre l'application.
Le handler requiert le package PHP graylog2/gelf-php :
Image de production et préfixe de registry¶
Ces deux variables pilotent quelle image Docker la production tire du registry. Elles ne vivent pas dans .env : en production, on les exporte dans le shell (ou un gestionnaire de secrets/config) avant docker compose pull && up.
Depuis l'étape 4, le service php de compose.prod.yaml ne build plus l'image sur le serveur : il PULL une image immuable poussée par la CI (job docker:build-prod, cf. Pipeline GitLab CI). La référence d'image est :
| Variable | Défaut dans compose.yaml |
Défaut dans compose.prod.yaml |
Rôle |
|---|---|---|---|
IMAGES_PREFIX |
(vide) | registry.gitlab.com/shaurifr/kirexo/ |
Préfixe du nom de l'image Docker. En dev (compose.yaml), il préfixe kirexo-app (vide par défaut → image locale non poussée). En prod (compose.prod.yaml), il pointe le registry du projet devant kirexo-prod. |
KIREXO_VERSION |
— | latest |
Tag de l'image kirexo-prod à déployer. Épingle une release précise (le tag Git YYYYMMDDHHMM que la CI pousse aussi comme tag d'image). |
IMAGES_PREFIX doit finir par / si vous le définissez manuellement
Le préfixe est concaténé directement au nom de l'image (${IMAGES_PREFIX}kirexo-prod). S'il ne se termine pas par une barre oblique, le préfixe se colle au nom : registry.gitlab.com/shaurifr/kirexokirexo-prod. Le défaut prod (registry.gitlab.com/shaurifr/kirexo/) inclut déjà le / final — ne le redéfinissez que si vous poussez vers un autre registry, en conservant le / terminal.
Toujours exporter KIREXO_VERSION en production
Le défaut latest est un tag mutable : il est réécrit à chaque release. Si le serveur de prod ne définit pas KIREXO_VERSION, un docker compose pull ramène la dernière image publiée — vous perdez la possibilité de rejouer une version précise ou de revenir en arrière de façon déterministe.
Le déploiement DOIT donc exporter KIREXO_VERSION=<tag> (un tag Git YYYYMMDDHHMM) avant docker compose pull && up, pour épingler exactement l'image testée par la CI et garder un rollback propre. La procédure complète est décrite dans Déployer Kirexo en production.
Variables Docker Compose (dev uniquement)¶
Le fichier compose.override.yaml expose également des variables pour surcharger les ports locaux quand ils entrent en conflit avec d'autres services. Elles ne vivent pas dans .env : définissez-les dans votre shell ou dans un .env.local si vous en avez besoin.
Modèle .env.local.dist
Un modèle versionné .env.local.dist à la racine du dépôt regroupe les variables surchargeables (ports Compose, USER_ID/GROUP_ID du build, Xdebug, observabilité, devcontainer). Pour démarrer : cp .env.local.dist .env.local puis décommentez uniquement les lignes que vous voulez surcharger. La liste exhaustive et le rôle de chaque variable restent documentés ci-dessous.
| Variable | Défaut | Rôle |
|---|---|---|
HTTP_PORT |
80 |
Port HTTP de FrankenPHP côté hôte. |
HTTPS_PORT |
443 |
Port HTTPS (TCP) de FrankenPHP côté hôte. |
HTTP3_PORT |
443 |
Port HTTP/3 (UDP) de FrankenPHP côté hôte. |
POSTGRES_PORT |
5432 |
Port PostgreSQL côté hôte. Permet de connecter un client BDD (DBeaver, DataGrip…) depuis l'hôte sans passer par docker compose port. |
RABBITMQ_PORT |
5672 |
Port AMQP de RabbitMQ côté hôte. |
RABBITMQ_MANAGEMENT_PORT |
15672 |
Port de l'UI RabbitMQ côté hôte. |
TYPESENSE_PORT |
8108 |
Port Typesense côté hôte. |
GOTENBERG_PORT |
3000 |
Port Gotenberg côté hôte. |
MKDOCS_PORT |
8000 |
Port du service docs (mkdocs-material) côté hôte. |
MAILPIT_SMTP_PORT |
1025 |
Port SMTP Mailpit côté hôte. |
MAILPIT_UI_PORT |
8025 |
Port de l'UI Mailpit côté hôte. |
IMAGES_PREFIX n'est plus dev-only
IMAGES_PREFIX est lue par compose.yaml et par compose.prod.yaml. Comme son rôle et son défaut diffèrent entre les deux, elle est documentée dans sa propre section : Image de production et préfixe de registry.
Mode Xdebug
Xdebug est désactivé par défaut en dev via xdebug.mode = off dans frankenphp/conf.d/20-app.dev.ini — pas via une variable d'environnement. Pour activer ponctuellement la couverture, castor test:coverage injecte XDEBUG_MODE=coverage le temps du run (cf. castor.php). Les outils tiers comme PHPStorm peuvent forcer un mode différent à la volée via le flag CLI -dxdebug.mode=..., qui surcharge la directive INI le temps du processus.
Fuseau horaire du conteneur¶
| Variable | Défaut | Rôle |
|---|---|---|
TZ |
Europe/Paris en dev, (non définie) en prod |
Fuseau horaire du shell du conteneur php. Définie dans compose.override.yaml (chargé automatiquement en dev) sous la forme TZ: ${TZ:-Europe/Paris} — surchargeable via une variable d'environnement de l'hôte avant docker compose up. compose.prod.yaml ne la définit pas : la prod reste donc volontairement en UTC. |
Portée limitée au shell — PHP reste figé sur UTC
TZ n'affecte que le shell et les outils non-PHP du conteneur (statusline Claude Code, commande date, logs Docker, scripts Bash). PHP ignore cette variable car date.timezone = UTC est figé dans frankenphp/conf.d/10-app.ini et a priorité.
Conséquence pratique : dans une même session, date côté shell renvoie Europe/Paris (ex. 20:22 CEST) tandis que php -r 'echo date("H:i e");' renvoie 18:22 UTC. C'est attendu, pas un bug. Le décalage de 2 h ci-dessus est l'heure d'été ; en hiver ce sera 1 h.
Côté Doctrine, la discipline qui en découle est classique en Symfony : stocker les DateTimeImmutable en UTC, convertir vers le fuseau de l'utilisateur au moment du rendu uniquement (filtres Twig, formatters). Ne jamais laisser une comparaison de dates s'appuyer sur le fuseau du shell.
Surcharger ponctuellement
Pour exécuter la stack dans un autre fuseau (ex. test d'un bug lié au passage à l'heure d'hiver côté UI) :
Ou pour rendre la surcharge persistante côté hôte, déclarer TZ dans .env.local (lu par Docker Compose au démarrage).
Variables de build Docker (dev uniquement)¶
Ces variables sont lues par compose.override.yaml comme build.args du build du service php (image kirexo-dev). Elles réalignent l'utilisateur app du conteneur sur l'UID/GID de l'hôte pour que les fichiers créés dans le bind-mount /app (vendor/, var/, composer.lock…) appartiennent au développeur et non à root.
| Variable | Défaut | Rôle |
|---|---|---|
USER_ID |
1000 (dans .env) |
UID de l'utilisateur hôte passé au build. |
GROUP_ID |
1000 (dans .env) |
GID correspondant, même raison. |
Docker Compose ne lit que .env, jamais .env.local
Contrairement à Symfony (qui applique la cascade .env → .env.local → environnement du process), Docker Compose ne lit qu'un seul fichier dotenv : .env. La cascade .env.local est une mécanique propre à Symfony. Définir USER_ID/GROUP_ID dans .env.local n'a donc aucun effet sur le build du devcontainer — utilisez .env (défaut versionné) ou une vraie variable d'environnement (surcharge ponctuelle).
C'est pourquoi .env (versionné) porte des défauts USER_ID=1000 / GROUP_ID=1000 dans sa section ###> build Docker (dev uniquement) ### : ils garantissent que tout lanceur trouve toujours les variables, quel que soit le point d'entrée (Castor, IDE JetBrains/Gateway, devcontainer CLI). Sans ce défaut, un lanceur hors Castor interpolait ${USER_ID}/${GROUP_ID} à vide et le build plantait sur groupmod: invalid group ID ''.
Précédence des valeurs UID/GID¶
Pour le user app du conteneur — et donc la propriété des fichiers du bind-mount /app — l'UID/GID résulte, par ordre de précédence décroissante :
- Variable d'environnement réelle présente au moment du
docker compose(la plus prioritaire) :- Castor l'injecte automatiquement via
posix_getuid()/posix_getgid()(fonctionhost_user_env()decastor.php) →castor up --builddonne toujours vos vraies valeurs, sans rien configurer. - IDE JetBrains / Gateway (qui lance
docker composedirectement, hors Castor) : la variable doit être exportée dans l'environnement de la session qui démarre l'IDE — voir Ouvrir Kirexo dans un Dev Container PHPStorm.
- Castor l'injecte automatiquement via
- Défaut
1000:1000versionné dans.env(lu par Docker Compose). - Repli
:-1000du blocargs:decompose.override.yaml(filet si.envétait absent).
En complément, dans le dockerfile_inline de compose.override.yaml, les références sont écrites $${USER_ID} / $${GROUP_ID} : le $$ échappe l'interpolation Compose pour que ce soit le moteur de build (via les ARG, repli :-1000) qui les résolve. C'est un filet anti-crash supplémentaire si l'environnement du process est vide.
Cas concret : GID hôte ≠ 1000
La plupart des utilisateurs Linux ont UID et GID à 1000 — le défaut suffit, rien à faire. Mais un dev dont le groupe primaire n'est pas standard (ex. GID hôte 1001) doit surcharger via l'environnement, sinon il hérite du défaut 1000 et les fichiers du bind-mount finissent possédés par le mauvais groupe. Vérifiez votre identité avec id :
Avec Castor, c'est automatique. Avec un IDE JetBrains/Gateway, exportez USER_ID/GROUP_ID — procédure dans le tutoriel PHPStorm.
Variables internes au Dev Container¶
Ces variables sont lues à l'intérieur du Dev Container par les scripts shell de .devcontainer/*.sh. Elles ne sont pas définies dans .env — leur défaut est codé dans init-firewall.lib.sh (sourcée par tous les scripts qui en dépendent).
| Variable | Défaut | Rôle |
|---|---|---|
KIREXO_WORKSPACE |
/app |
Racine du projet montée dans le devcontainer. Lue par init-firewall.sh, post-start.sh, frankenphp-supervisor.sh et php-healthcheck.sh pour construire les chemins absolus (${KIREXO_WORKSPACE}/.devcontainer/..., ${KIREXO_WORKSPACE}/var/log/devcontainer/frankenphp.log). Permet de tester les scripts depuis l'hôte sans monter le projet en /app, ou de rebrancher la cible vers un autre chemin sans toucher chaque script. Le sudoers (/etc/sudoers.d/init-firewall) fige malgré tout /app/.devcontainer/... en absolu — un changement de KIREXO_WORKSPACE impose un rebuild de l'image pour aligner le sudoers. |
Variables CI/CD GitLab¶
Ces variables sont définies dans Settings → CI/CD → Variables du projet GitLab et lues par les pipelines décrites dans la Référence Pipeline GitLab CI. Elles ne vivent jamais dans .env ni dans .env.local.
| Variable | Source | Rôle |
|---|---|---|
GITLAB_TOKEN |
À créer manuellement — Personal Access Token (PAT) | Token unique du projet, consommé par cinq usages qui ont tous besoin soit de pousser une branche/un tag, soit d'appeler une route de l'API REST que CI_JOB_TOKEN ne couvre pas sur GitLab Free : (1) tag:create (cf. .gitlab/ci/tag.yml) pour appeler POST /projects/:id/repository/tags ; (2) security:composer-audit (cf. .gitlab/ci/security.yml) pour pousser une branche security/composer-* et ouvrir la MR de patch (ou ouvrir une issue de fallback via castor ci:open-issue) ; (3) tools:version-check (cf. .gitlab/ci/dependencies.yml) pour ouvrir une issue via castor ci:open-issue quand un outil épinglé dans le Dockerfile est en retard ; (4) dependencies:renovate (cf. .gitlab/ci/dependencies.yml), où Renovate le lit via le mapping RENOVATE_TOKEN: $GITLAB_TOKEN pour créer branches et merge requests de montée de version ; (5) security:container-issue et security:container-issue:builders (cf. .gitlab/ci/security.yml) pour appeler POST /projects/:id/issues quand au moins une CVE Critical/High est remontée — CI_JOB_TOKEN n'est pas supporté pour cette route sur GitLab Free (la whitelist du job token couvre Registry/Packages/Releases mais pas l'API issues : retour HTTP 401 testé empiriquement, et le réglage « Allow projects to access this project via CI/CD job tokens » n'y change rien — il n'étend que l'accès inter-projets, pas la whitelist des endpoints). Scopes nécessaires : api (création d'issue/MR par les jobs 2, 3, 4 et 5 via le PAT) + write_repository (création de tag par le job 1 et de branches par les jobs 2 et 4). À configurer en masked uniquement (non protected) dans Settings → CI/CD → Variables — la variable doit être disponible aussi sur les feature branches et les MRs, pas seulement sur les refs protégées (les jobs security:container-issue (+ :builders) tournent sur la pipeline de MR / branche courante pour pouvoir ouvrir l'issue d'alerte CVE, et Protect variable la masquerait à ce moment-là). Non utilisé par release:create ni par les jobs Docker — ceux-ci passent par CI_JOB_TOKEN / CI_REGISTRY_PASSWORD (cf. ci-dessous). |
CI_REGISTRY_USER |
Injecté par GitLab | Identifiant d'authentification au registry du projet. Utilisé par les jobs docker:build-* pour docker login. |
CI_REGISTRY_PASSWORD |
Injecté par GitLab | Mot de passe d'authentification au registry du projet, valide le temps du job. |
CI_REGISTRY_IMAGE |
Injecté par GitLab | Préfixe complet du registry du projet (ex. registry.gitlab.com/shaurifr/kirexo). Sert à construire les noms d'images kirexo-base, kirexo-dev, kirexo-prod. |
CI_JOB_TOKEN |
Injecté par GitLab | Token automatique du job courant, scopé sur le job (révoqué à sa fin). Utilisé par release:create pour authentifier release-cli. Pas utilisé par security:container-issue (+ :builders) : la whitelist de CI_JOB_TOKEN sur GitLab Free ne couvre pas POST /projects/:id/issues (testé HTTP 401 empiriquement), ces deux jobs passent par GITLAB_TOKEN (cf. ligne au-dessus). |
CREATE_TAG |
Variable de déclenchement (à passer au lancement de pipeline) | true pour lancer la pipeline isolée de création de tag (job tag:create, cf. .gitlab/ci/tag.yml). Absente ou différente de true : la pipeline standard quality + test tourne. Voir Créer un tag de release. |
FORCE_TAG |
Variable de déclenchement optionnelle (à passer au lancement de pipeline) | true pour outrepasser le garde-fou de tag:create, qui refuse normalement de créer le tag si aucune pipeline success n'existe pour le dernier commit de main. À passer en plus de CREATE_TAG=true. Sans effet hors de la pipeline CREATE_TAG=true. Réservée aux cas exceptionnels. Voir Créer un tag de release. |
Pourquoi un PAT et pas un project access token
Kirexo est hébergé sur GitLab.com en tier gratuit, où les project access tokens (et les group access tokens) ne sont disponibles qu'à partir des offres Premium/Ultimate. En gratuit, le seul type de token utilisable en variable CI/CD est un Personal Access Token (PAT) rattaché à un compte. GITLAB_TOKEN est donc un PAT du mainteneur, avec les scopes api + write_repository. Il sert aussi à Renovate, qui le lit via le mapping RENOVATE_TOKEN: $GITLAB_TOKEN défini dans le job dependencies:renovate — aucune variable RENOVATE_TOKEN distincte n'est déclarée côté GitLab.
GITLAB_TOKEN : masqué, non protégé
Cocher Mask variable au moment de la création, sans cocher Protect variable. Mask empêche le token d'apparaître en clair si un job l'echoait par mégarde. Protect, en revanche, doit rester décoché : security:container-issue (+ :builders) tourne sur la pipeline de la MR / feature branch courante pour ouvrir l'issue d'alerte CVE, et Protect variable rendrait la variable indisponible sur ces refs non protégées — l'appel POST /projects/:id/issues partirait alors sans PRIVATE-TOKEN et retomberait en HTTP 401. Le PAT doit appartenir à un compte ayant comme rôle minimum Maintainer sur le projet, pour pouvoir créer un tag (l'API repository/tags refuse les rôles inférieurs) ainsi que les branches et MRs de Renovate.
Variables lues côté hôte (avant création du devcontainer)¶
Certaines variables ne sont pas lues par compose.override.yaml ni par .env.local — elles doivent être exportées dans le shell qui lance l'IDE, avant que PHPStorm/VS Code ne crée le Dev Container. La définition exhaustive vit dans la Référence du Dev Container. Les déclarer dans .env.local n'a pas d'effet (le fichier est lu trop tard, après postCreateCommand) — le modèle .env.local.dist le documente explicitement dans la section dédiée.
| Variable | Voir |
|---|---|
KIREXO_CLAUDE_BYPASS |
Référence du Dev Container — Variables lues côté hôte |