Aller au contenu principal

Canaux (Tracks) et Promotion Zéro-Recompilation

La page /apps/[appId]/tracks (src/app/apps/[appId]/tracks/page.tsx) permet d'isoler le cycle de validation des patchs OTA par environnement (Track / Channel) et de promouvoir un binaire certifié d'un canal à un autre sans jamais recompiler le code source Dart.


1. Les canaux standards et personnalisés​

Par défaut, chaque application dispose de trois pistes standards auxquelles l'opérateur peut ajouter des pistes personnalisées :

CanalUsage recommandéComportement typique
devDéveloppement interne et tests unitaires d'intégrationAuto-approbation rapide en mode non-4-Yeux, tests sur émulateurs ou téléphones développeurs
stagingRecette QA, pré-production et validation métier (UAT)Protégé par la Liste Blanche QA (allowedClientIds) pour empêcher toute fuite hors de l'équipe de test
stableFlotte de production finale (clients finaux)Soumis au bouclier IN_STORE_REVIEW, au contrôle à 4-Yeux (APPROVED_AND_SIGNED) et au Canary Rollout progressif
Canaux personnalisésPistes dédiées (ex. beta-vip, pilote-agences, canary-interne)Créés depuis le bouton Nouveau Canal sur /apps/[appId]/tracks et persistés dans localStorage sous tks_custom_channels_<appId> (fusionnés automatiquement avec tout canal retourné par le backend)

2. Pourquoi la promotion Zéro-Recompilation est essentielle​

Dans un pipeline mobile classique, recompiler l'application entre l'environnement staging et l'environnement stable présente deux risques majeurs :

  1. Dérive non déterministe du binaire : Horodatages de compilation, versions mineures de dépendances ou variables d'environnement modifiées entre le build de recette et le build de production.
  2. Invalidation de la recette QA : Le binaire livré aux clients finaux sur stable n'est plus mathématiquement identique au binaire validé par l'équipe QA sur staging.

Avec la Promotion 1-Clic de TkushPatch (Serveur TkushPatch), le serveur réutilise exactement le même artefact physique .vmcode (diffArtifactPath), le même targetSha256Hash et le même fichier de symboles .symbols.

Workflow de promotion entre environnements
  1. Recette initiale sur dev ou staging : Le patch est testé par les équipes de validation sur une flotte restreinte d'appareils autorisés.
  2. Décision de promotion : Dès validation complète de la recette, le responsable clique sur Promouvoir vers Stable.
  3. Scellement de production : Le correctif reçoit la signature de production et le déploiement public commence.

3. Fonctionnement technique de la promotion (POST /api/admin/v1/patches/{id}/promote)​

Lorsque l'opérateur (ROLE_ADMIN ou ROLE_SECURITY_OFFICER, permission PROMOTE_PATCH) clique sur Promouvoir depuis /apps/[appId]/tracks, /releases ou /rollout :

  1. Requête HTTP :
    POST /api/admin/v1/patches/{patchId}/promote
    Content-Type: application/json

    {
    "target_channel": "stable",
    "promoted_by": "rssi@entreprise.com",
    "tenant_id": "sara-money"
    }
  2. Contrôles de sécurité côté serveur (Serveur TkushPatch) :
    • Vérifie l'isolation multi-tenant (assertReleaseBelongsToTenant).
    • Contrôle d'état strict : Seul un patch dans l'état APPROVED_AND_SIGNED peut être promu (sourcePatch.status() == PatchStatus.APPROVED_AND_SIGNED). Un patch STAGED ou ROLLED_BACK est formellement rejeté.
    • Contrôle de canal : Interdit de promouvoir un patch vers son propre canal source (cleanTargetChannel.equalsIgnoreCase(sourcePatch.channel())).
  3. Numérotation séquentielle par canal :
    • Le serveur calcule le prochain numéro de patch disponible sur le canal cible pour cette release : nextPatchNumber = patchRepository.findMaxPatchNumberForReleaseAndChannel(releaseId, cleanTargetChannel) + 1.
  4. Re-signature cryptographique par environnement (si l'isolation des clés est active) :
    • Si ota.crypto.per-environment-keys-enabled=true, cryptoSigner.signPatchHash(tenantId, appId, cleanTargetChannel, targetSha256Hash) signe le hash SHA-256 avec la clé RSA isolée du canal cible (prod vs nonprod). Sinon, la signature certifiée est conservée.
  5. Traçabilité et éviction du cache :
    • Le nouveau patch est enregistré avec approvedBy = "PROMOTED_FROM_<SOURCE_CHANNEL>:<promotedBy>", le cache L1/L2 de la release est immédiatement invalidé et un événement d'audit PATCH_PROMOTED est inscrit avec sourcePatchId, sourceChannel, targetChannel et patchNumber.