Un APK sans cle API valide ne telecharge rien, et ne le dit pas

Le build de la journee est parti trois fois sans --dart-define=API_KEY, ou
avec une cle morte. L'app s'affiche normalement dans ce cas : seuls
instanceGetDetail et configuration/{id}/export repondent 401, et le
dialogue de telechargement annonce « verifiez votre connexion ». Le reseau
va tres bien, c'est l'authentification qui manque, et rien ne le dit.

tool/build_apk.sh <flavor> [--install] verifie la cle AVANT les dix minutes
de build (200 bonne cle, 403 cle d'une autre instance, 401 cle morte),
nettoie d'office, et refuse de rendre la main si le GIT_SHA demande n'est
pas dans libapp.so — un build incrementiel reutilise le kernel Dart en
cache et ignore un changement de --dart-define.

Les cles vivent dans tool/build_keys.env, ignore par git. Elles etaient
dans .vscode/launch.json, qui est suivi : celles qui y restent sont mortes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thomas Fransolet 2026-09-09 12:20:49 +02:00
parent d39949a6bd
commit e15f874d20
3 changed files with 114 additions and 0 deletions

3
.gitignore vendored
View File

@ -52,3 +52,6 @@ Thumbs.db
build
.flutter-plugins
.flutter-plugins-dependencies
# Cles API de build (dart-define) — jamais dans git.
tool/build_keys.env

83
tool/build_apk.sh Normal file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env bash
#
# Build d'un APK release avec les dart-define du flavor.
#
# tool/build_apk.sh dev [--install]
#
# Pourquoi ce script plutôt que la ligne de commande du README :
#
# 1. Un build sans --dart-define=API_KEY produit une app qui s'affiche mais ne
# télécharge rien : 401 sur l'instance comme sur l'export, et un message
# « vérifiez votre connexion » qui envoie chercher au mauvais endroit.
# 2. Les clés ne doivent plus vivre dans .vscode/launch.json — il est suivi par
# git, et les clés qui y étaient sont mortes (401) après rotation.
# 3. Un build incrémental réutilise le kernel Dart en cache et ignore un
# changement de --dart-define : d'où le `clean`, et la vérification finale
# que le GIT_SHA demandé est bien dans le binaire livré.
set -euo pipefail
flavor="${1:-}"
if [[ -z "$flavor" ]]; then
echo "usage: tool/build_apk.sh <dev|mdlf|fortsaintheribert> [--install]" >&2
exit 1
fi
cd "$(dirname "$0")/.."
if [[ ! -f tool/build_keys.env ]]; then
echo "tool/build_keys.env manquant — copier tool/build_keys.env.example et le remplir." >&2
exit 1
fi
# shellcheck disable=SC1091
source tool/build_keys.env
upper=$(echo "$flavor" | tr '[:lower:]' '[:upper:]')
instance_var="${upper}_INSTANCE_ID"
base_var="${upper}_API_BASE_URL"
key_var="${upper}_API_KEY"
instance="${!instance_var:-}"
base="${!base_var:-}"
key="${!key_var:-}"
if [[ -z "$instance" || -z "$base" || -z "$key" ]]; then
echo "flavor '$flavor' : ${instance_var}, ${base_var} ou ${key_var} vide dans tool/build_keys.env" >&2
exit 1
fi
# La clé est vérifiée AVANT les dix minutes de build : 200 = bonne instance,
# 403 = clé d'une autre instance, 401 = clé morte.
code=$(curl -s -o /dev/null -w "%{http_code}" -H "X-Api-Key: $key" "$base/api/instance/$instance" --max-time 25 || echo "000")
if [[ "$code" != "200" ]]; then
echo "clé $flavor refusée par $base (HTTP $code) — voir tool/build_keys.env.example" >&2
exit 1
fi
sha=$(git rev-parse --short HEAD)
echo "build $flavor · instance $instance · $base · sha $sha"
flutter clean >/dev/null
flutter pub get >/dev/null
flutter build apk --release --flavor "$flavor" -t lib/main.dart \
--dart-define=FLAVOR="$flavor" \
--dart-define=INSTANCE_ID="$instance" \
--dart-define=API_BASE_URL="$base" \
--dart-define=API_KEY="$key" \
--dart-define=GIT_SHA="$sha"
apk="build/app/outputs/flutter-apk/app-${flavor}-release.apk"
# « Built » ne prouve rien : c'est le binaire qu'on interroge.
tmp=$(mktemp)
unzip -p "$apk" lib/arm64-v8a/libapp.so > "$tmp"
if ! grep -q -a "$sha" "$tmp"; then
rm -f "$tmp"
echo "APK construit mais $sha absent de libapp.so — build périmé, relancer." >&2
exit 1
fi
rm -f "$tmp"
echo "OK · $apk · sha $sha vérifié dans le binaire"
if [[ "${2:-}" == "--install" ]]; then
adb install -r "$apk"
fi

View File

@ -0,0 +1,28 @@
# Modèle de tool/build_keys.env — copier, remplir, ne jamais committer le résultat.
#
# Les clés API sont embarquées dans le binaire au build (--dart-define=API_KEY).
# Sans clé valide, l'app ne peut ni lire l'instance ni télécharger une visite :
# `instanceGetDetail` et `configuration/{id}/export` répondent 401, et le
# dialogue de téléchargement affiche « vérifiez votre connexion » — un message
# trompeur qui a déjà coûté une demi-journée.
#
# Obtenir une clé pour une instance :
# curl "https://api.mymuseum.be/api/instance/app-key?pinCode=<PIN>&appType=Mobile"
# (route publique, le pinCode se lit dans le Manager). Ou Manager → clés API.
#
# Vérifier qu'une clé est bien vivante ET rattachée à la bonne instance :
# curl -o /dev/null -w "%{http_code}\n" -H "X-Api-Key: <CLE>" \
# https://api.mymuseum.be/api/instance/<INSTANCE_ID>
# 200 = bonne clé · 403 = clé d'une autre instance · 401 = clé morte
DEV_INSTANCE_ID=63514fd67ed8c735aaa4b8f2
DEV_API_BASE_URL=https://api.mymuseum.be
DEV_API_KEY=
MDLF_INSTANCE_ID=65ccc67265373befd15be511
MDLF_API_BASE_URL=https://api.mymuseum.be
MDLF_API_KEY=
FORTSAINTHERIBERT_INSTANCE_ID=633ee379d9405f32f166f047
FORTSAINTHERIBERT_API_BASE_URL=https://api.mymuseum.be
FORTSAINTHERIBERT_API_KEY=