11#! /usr/bin/env bash
2- # Script interactif pour compléter les variables d'environnement
2+ # Script pour compléter les variables d'environnement
33# Appelé par `make install`
44#
55# Deux modes :
6- # 1. Vaultwarden : importe les secrets depuis deux secure notes Bitwarden/Vaultwarden
7- # 2. Interactif : demande chaque variable à compléter une par une
8- #
9- # Organisation Vaultwarden attendue :
10- # - Deux secure notes contenant uniquement les variables secrètes (KEY=VALUE)
11- # - Le script demande l'URL du serveur, la clé API, et les liens des deux notes
12- # - Les .env sont d'abord créés depuis .env.example, puis les secrets remplacent les placeholders.
6+ # 1. Coller le contenu d'un fichier .env pour compléter les valeurs manquantes
7+ # 2. Passer et compléter les fichiers .env manuellement
138
149set -euo pipefail
1510
1611PLACEHOLDERS=" PICK_A_PASSWORD|ASK_A_MAINTAINER|YOUR_EMAIL|YOUR_MATTERMOST_USERNAME|CREATE_A_SECRET_KEY"
17- ENV_DOC=" ENV.md"
1812
1913# Couleurs
2014CYAN=' \033[36m'
2115YELLOW=' \033[33m'
2216GREEN=' \033[32m'
23- RED=' \033[31m'
2417DIM=' \033[2m'
2518RESET=' \033[0m'
2619
2720# ──────────────────────────────────────────────
28- # Vaultwarden
21+ # Coller un fichier .env
2922# ──────────────────────────────────────────────
3023
31- ensure_bw_cli () {
32- if command -v bw & > /dev/null; then
33- return 0
34- fi
35-
36- echo -e " ${DIM} Bitwarden CLI (bw) non trouvé — installation...${RESET} "
37- local os
38- os=$( uname -s)
39-
40- case " $os " in
41- Darwin)
42- if command -v brew & > /dev/null; then
43- brew install bitwarden-cli
44- else
45- echo -e " ${RED} Homebrew requis pour installer bw sur macOS.${RESET} "
46- return 1
47- fi
48- ;;
49- Linux)
50- if command -v snap & > /dev/null; then
51- sudo snap install bw
52- elif command -v npm & > /dev/null; then
53- npm install -g @bitwarden/cli
54- else
55- echo -e " ${RED} snap ou npm requis pour installer bw sur Linux.${RESET} "
56- return 1
57- fi
58- ;;
59- MINGW* |MSYS* |CYGWIN* )
60- if command -v winget & > /dev/null; then
61- winget install -e --id Bitwarden.CLI
62- elif command -v npm & > /dev/null; then
63- npm install -g @bitwarden/cli
64- else
65- echo -e " ${RED} winget ou npm requis pour installer bw sur Windows.${RESET} "
66- return 1
67- fi
68- ;;
69- * )
70- echo -e " ${RED} OS non reconnu. Installez bw manuellement : https://bitwarden.com/help/cli/${RESET} "
71- return 1
72- ;;
73- esac
74-
75- if ! command -v bw & > /dev/null; then
76- echo -e " ${RED} Installation échouée. Installez bw manuellement : https://bitwarden.com/help/cli/${RESET} "
77- return 1
78- fi
79-
80- echo -e " ${GREEN} bw installé.${RESET} "
81- }
82-
83- # Extrait l'itemId d'un lien Vaultwarden ou retourne la valeur telle quelle si c'est déjà un ID
84- extract_item_id () {
85- local input=" $1 "
86- # Si c'est une URL contenant itemId=...
87- if echo " $input " | grep -q ' itemId=' ; then
88- echo " $input " | sed ' s/.*itemId=\([^&]*\).*/\1/'
89- else
90- # Sinon c'est déjà un ID
91- echo " $input "
92- fi
93- }
94-
95- bw_login () {
96- local server_url=" $1 "
97-
98- # Déconnecter la session précédente pour repartir proprement
99- bw logout 2> /dev/null || true
100-
101- # Configurer le serveur
102- echo -e " ${DIM} Serveur : ${server_url}${RESET} "
103- bw config server " $server_url " 2> /dev/null
104-
105- # Connexion avec email + mot de passe
106- # Note : les clés API d'organisation ne sont pas supportées par le CLI Bitwarden,
107- # seules les clés API personnelles fonctionnent. On utilise donc email + mot de passe
108- # pour pouvoir accéder aux items des coffres d'organisation.
109- echo -e " ${DIM} Connexion (les clés API ne sont pas supportées pour les coffres d'organisation)${RESET} "
110- BW_SESSION=$( bw login --raw < /dev/tty)
111- if [ -z " $BW_SESSION " ]; then
112- echo -e " ${RED} Échec de la connexion.${RESET} "
113- return 1
114- fi
115-
116- export BW_SESSION
117- }
118-
119- # Récupère le contenu d'une secure note par son ID
120- bw_get_note () {
121- local item_id=" $1 "
122- local item_json
123- # bw get item fonctionne pour les items personnels et organisationnels
124- item_json=$( bw get item " $item_id " --session " $BW_SESSION " 2>&1 ) || {
125- echo -e " ${DIM} Erreur bw : ${item_json}${RESET} " >&2
126- return 1
127- }
128- # Extraire les notes du JSON
129- echo " $item_json " | python3 -c " import sys,json; n=json.load(sys.stdin).get('notes',''); print(n if n else '')" 2> /dev/null
130- }
131-
132- # Applique les secrets d'une note Vaultwarden sur un fichier .env existant
133- # La note contient des lignes KEY=VALUE (uniquement les secrets)
24+ # Applique des lignes KEY=VALUE sur un fichier .env existant
13425apply_secrets_to_env () {
13526 local env_file=" $1 "
136- local note_content =" $2 "
27+ local content =" $2 "
13728 local count=0
13829
13930 while IFS= read -r line; do
@@ -150,166 +41,58 @@ apply_secrets_to_env() {
15041 rm -f " ${env_file} .bak"
15142 count=$(( count + 1 ))
15243 fi
153- done <<< " $note_content "
44+ done <<< " $content "
15445
15546 echo " $count "
15647}
15748
158- fetch_from_vaultwarden () {
159- echo " "
160- echo -e " ${YELLOW} Import des secrets depuis Vaultwarden${RESET} "
161- echo " "
162-
163- ensure_bw_cli || return 1
49+ paste_env_content () {
50+ local env_file=" $1 "
51+ local label=" $2 "
16452
165- # Demander l'URL du serveur
166- printf " URL du serveur Vaultwarden (ex: https://vault.example.com) : "
167- read -r server_url < /dev/tty
168- if [ -z " $server_url " ]; then
169- echo -e " ${RED} URL requise.${RESET} "
170- return 1
53+ if [ ! -f " $env_file " ]; then
54+ return 0
17155 fi
17256
173- bw_login " $server_url " || return 1
174-
175- bw sync --session " $BW_SESSION " > /dev/null 2>&1
57+ # Vérifier s'il y a des placeholders dans ce fichier
58+ if ! grep -qE " $PLACEHOLDERS " " $env_file " 2> /dev/null; then
59+ echo -e " ${label} : ${DIM} aucune variable à compléter${RESET} "
60+ return 0
61+ fi
17662
177- # Demander les liens des notes
17863 echo " "
179- echo -e " ${DIM} Pour chaque note, collez l'URL ou l'ID de l'élément Vaultwarden. ${RESET} "
180- echo -e " ${DIM} URL : https://vault.example.com/#/vault?itemId=xxxx-xxxx ${RESET} "
181- echo -e " ${DIM} ID : xxxx-xxxx-xxxx-xxxx ${RESET} "
182- echo -e " ${DIM} Appuyez sur Entrée pour passer.${RESET} "
64+ echo -e " ${CYAN} ── ${label} ── ${RESET} "
65+ echo -e " ${DIM} Collez le contenu du fichier .env (lignes KEY=VALUE), ${RESET} "
66+ echo -e " ${DIM} puis appuyez sur Entrée et tapez ${CYAN} EOF ${DIM} pour terminer. ${RESET} "
67+ echo -e " ${DIM} Appuyez directement sur Entrée puis ${CYAN} EOF ${DIM} pour passer.${RESET} "
18368 echo " "
18469
185- local success=0
70+ local pasted_content=" "
71+ while IFS= read -r line < /dev/tty; do
72+ [ " $line " = " EOF" ] && break
73+ pasted_content+=" ${line} " $' \n '
74+ done
18675
187- # .env
188- printf " Note des secrets ${CYAN} .env${RESET} (URL ou ID) : "
189- read -r env_link < /dev/tty
190- if [ -n " $env_link " ]; then
191- local env_id
192- env_id=$( extract_item_id " $env_link " )
193- local env_content
194- if env_content=$( bw_get_note " $env_id " ) ; then
195- if [ -n " $env_content " ]; then
196- local count
197- count=$( apply_secrets_to_env " .env" " $env_content " )
198- echo -e " ${GREEN}${count} variables importées dans .env${RESET} "
199- success=1
200- else
201- echo -e " ${RED} Note trouvée mais vide${RESET} "
202- fi
203- else
204- echo -e " ${RED} Note introuvable (ID: ${env_id} )${RESET} "
205- fi
206- fi
207-
208- # airflow/.env
209- printf " Note des secrets ${CYAN} airflow/.env${RESET} (URL ou ID) : "
210- read -r airflow_link < /dev/tty
211- if [ -n " $airflow_link " ]; then
212- local airflow_id
213- airflow_id=$( extract_item_id " $airflow_link " )
214- local airflow_content
215- if airflow_content=$( bw_get_note " $airflow_id " ) ; then
216- if [ -n " $airflow_content " ]; then
217- local count
218- count=$( apply_secrets_to_env " airflow/.env" " $airflow_content " )
219- echo -e " ${GREEN}${count} variables importées dans airflow/.env${RESET} "
220- success=1
221- else
222- echo -e " ${RED} Note trouvée mais vide${RESET} "
223- fi
224- else
225- echo -e " ${RED} Note introuvable (ID: ${airflow_id} )${RESET} "
226- fi
227- fi
76+ # Supprimer le dernier saut de ligne
77+ pasted_content=" ${pasted_content% $' \n ' } "
22878
229- if [ $success -eq 0 ]; then
230- echo " "
231- echo -e " ${RED} Aucun secret importé. Basculement vers la saisie interactive...${RESET} "
232- return 1
233- fi
234-
235- return 0
236- }
237-
238- # ──────────────────────────────────────────────
239- # Interactif
240- # ──────────────────────────────────────────────
241-
242- # Cherche la description d'une variable dans ENV.md
243- get_description () {
244- local var_name=" $1 "
245- if [ -f " $ENV_DOC " ]; then
246- grep -m1 " | \` ${var_name} \` " " $ENV_DOC " 2> /dev/null | sed ' s/.*| `[^`]*` | \([^|]*\) |.*/\1/' | sed ' s/^ *//;s/ *$//' || true
79+ if [ -z " $pasted_content " ]; then
80+ echo -e " ${DIM} Aucun contenu collé, fichier non modifié.${RESET} "
81+ return 0
24782 fi
248- }
249-
250- # Traite un fichier .env interactivement
251- process_env_file () {
252- local env_file=" $1 "
253- local label=" $2 "
254- local found=0
255-
256- # Lire le fichier via fd 3 pour laisser stdin (/dev/tty) libre pour l'utilisateur
257- while IFS= read -r line < & 3; do
258- # Ignorer les commentaires et lignes vides
259- [[ " $line " =~ ^[[:space:]]* # ]] && continue
260- [[ -z " $line " ]] && continue
261-
262- # Extraire nom=valeur
263- local var_name= " ${line%% =* } "
264- local var_value= " ${line#* =} "
265-
266- # Vérifier si la valeur contient un placeholder
267- if echo " $var_value " | grep -qE " $PLACEHOLDERS " ; then
268- if [ $found -eq 0 ]; then
269- echo " "
270- echo -e " ${CYAN} ── ${label} ──${RESET} "
271- found=1
272- fi
273-
274- local description
275- description=$( get_description " $var_name " )
276-
277- echo " "
278- echo -e " ${CYAN}${var_name}${RESET} "
279- if [ -n " $description " ]; then
280- echo -e " ${DIM}${description}${RESET} "
281- fi
282- echo -e " ${DIM} Actuel : ${var_value}${RESET} "
283-
284- printf " Valeur : "
285- read -r new_value < /dev/tty
286-
287- if [ -n " $new_value " ]; then
288- sed -i.bak " s|^${var_name} =.*|${var_name} =${new_value} |" " $env_file "
289- fi
290- fi
291- done 3< " $env_file "
292-
293- # Nettoyer les fichiers de backup
294- rm -f " ${env_file} .bak"
29583
296- if [ $found -eq 0 ] ; then
297- echo -e " ${label} : ${DIM} aucune variable à compléter ${RESET} "
298- fi
84+ local count
85+ count= $( apply_secrets_to_env " $env_file " " $pasted_content " )
86+ echo -e " ${GREEN}${count} variables importées dans ${label}${RESET} "
29987}
30088
301- interactive_setup () {
89+ import_from_paste () {
30290 echo " "
303- echo -e " ${DIM} Appuyez sur Entrée sans rien saisir pour garder la valeur actuelle. ${RESET} "
304- echo -e " ${DIM} Les valeurs ASK_A_MAINTAINER sont à demander à un mainteneur du projet.${RESET} "
91+ echo -e " ${YELLOW} Import par collage de fichier .env ${RESET} "
92+ echo -e " ${DIM} Demandez le fichier .env à un mainteneur du projet, puis collez son contenu ci-dessous .${RESET} "
30593
306- if [ -f " .env" ]; then
307- process_env_file " .env" " .env — Application"
308- fi
309-
310- if [ -f " airflow/.env" ]; then
311- process_env_file " airflow/.env" " airflow/.env — Airflow"
312- fi
94+ paste_env_content " .env" " .env"
95+ paste_env_content " airflow/.env" " airflow/.env"
31396}
31497
31598# ──────────────────────────────────────────────
338121echo " "
339122echo " Comment configurer les variables ?"
340123echo " "
341- echo -e " ${CYAN} 1${RESET} ) Saisie interactive"
342- echo -e " ${CYAN} 2${RESET} ) Importer depuis Vaultwarden"
343- echo -e " ${CYAN} 3${RESET} ) Passer (compléter les fichiers .env manuellement)"
124+ echo -e " ${CYAN} 1${RESET} ) Coller le contenu d'un fichier .env"
125+ echo -e " ${CYAN} 2${RESET} ) Passer (compléter les fichiers .env manuellement)"
344126echo " "
345- printf " Choix [1/2/3 ] : "
127+ printf " Choix [1/2] : "
346128read -r choice < /dev/tty
347129
348130case " $choice " in
349- 2)
350- if ! fetch_from_vaultwarden; then
351- interactive_setup
352- fi
131+ 1)
132+ import_from_paste
353133 ;;
354- 3 )
134+ * )
355135 echo " "
356136 echo -e " ${DIM} Pensez à compléter .env et airflow/.env avant de lancer l'application.${RESET} "
357137 echo -e " ${DIM} Voir ENV.md pour la documentation.${RESET} "
358138 ;;
359- * )
360- interactive_setup
361- ;;
362139esac
363140
364141echo " "
0 commit comments