Statut : canaux, publication et client de mise à jour dans le jeu. Décision de l'auteur (2026-10-10) : les zips sont envoyés à la
main sur le serveur du site (prism.am, prism-admin release add), qui publie une liste publique releases.json ; les joueurs
mettent à jour depuis le jeu, contre ce flux du site, jamais contre GitHub (le dépôt est privé : pas de jeton dans le client).
Le flux signé, Velopack, OVH et la signature des exécutables restent des phases ultérieures (docs/etude-mises-a-jour.md, branche
docs/autoupdate-study) ; ce qui suit décrit ce qui existe.
Deux canaux, deux installations
stable |
pbe |
|
|---|---|---|
Fichier channel (à côté de prism.exe) |
stable ou absent |
pbe |
| Dossier de données | %LOCALAPPDATA%\Prism\PrismNG\data (inchangé) |
%LOCALAPPDATA%\Prism\PrismNG-PBE\data |
| Base, replays, mods, skins, thèmes du joueur | ceux du dossier de données | ceux de son propre dossier |
Profil WebView2 (localStorage : réglages, skinConfig, brouillons de l'Atelier) |
<données>\webview2 |
<données>\webview2 (du canal PBE) |
| Titres de fenêtre | Prism, Prism — Auto… |
Prism PBE, Prism PBE — Auto… |
| Pastille | aucune | « PBE » dans l'en-tête du tiroir (Échap) |
| Instance unique (mutex Windows) | Local\PrismNG-stable |
Local\PrismNG-pbe |
Le fichier channel est lu une seule fois, au démarrage (apps/desktop/src/app/install.rs, appelé par startup.rs).
Il tient en un mot (stable ou pbe, casse et espaces ignorés). Absent : stable, sans message. Illisible, trop long ou mot
inconnu : stable et une ligne dans la console (PRISM: … is not usable). Le canal n'est jamais compilé : c'est ce qui
permet de promouvoir les mêmes octets d'exécutable de PBE vers stable.
Les deux canaux tournent côte à côte. Une seconde instance du même canal ne démarre pas : elle ramène la fenêtre de la
première au premier plan (recherche des fenêtres visibles dont le titre est celui du canal, dans un prism.exe), ou, si
aucune fenêtre n'existe encore, affiche « Prism est déjà lancé » puis quitte. --write-ts-packages, --check-library,
--bench-gameplay et les --smoke-* ne prennent jamais ce verrou.
Les variables PRISM_MODS_DIR et PRISM_SKINS_DIR fonctionnent comme avant. Réglages → À propos
affiche le canal et la version (Cargo.toml, la même pour les zips PBE et stable d'un même build).
Profil WebView2 hors du dossier de l'exécutable
Avant, WebView2 écrivait prism.exe.WebView2 à côté de l'exe : un outil qui remplace le dossier de l'exe aurait effacé
les réglages. Il est maintenant dans <données>\webview2 (app/profile.rs, WEBVIEW2_USER_DATA_FOLDER posé avant toute
WebView). Au premier lancement, un ancien prism.exe.WebView2 est copié (jamais déplacé) vers <données>\webview2 :
- seulement si la cible n'existe pas (une cible présente gagne toujours, même vide) ; idempotent ;
- copie dans
webview2.copyingpuis renommage : une copie interrompue ne laisse pas un faux profil ; - les fichiers verrou du navigateur (
lockfile,LOCK) sont ignorés, tout autre fichier illisible est journalisé (PRISM: profile file … not copied) et ignoré ; le reste est copié ; - une variable
WEBVIEW2_USER_DATA_FOLDERdéjà définie est respectée (rien n'est migré).
Conséquence : supprimer le dossier de données remet maintenant aussi les réglages à zéro (avant, ils survivaient). Les
diagnostics (--smoke-*, --bench-gameplay) gardent leur profil jetable dans le dossier temporaire.
Couper une release avec la CI GitHub (écartée pour l'instant)
Cette voie existe (.github/workflows/release.yml, jamais exécuté) mais n'est pas celle retenue : voir « Couper une release et la publier sur le site (sans CI : la voie retenue) ».
Tout passe par .github/workflows/release.yml (déclenché à la main : Actions → release → Run workflow, ou par un tag
v*). Le workflow ne se lance jamais seul sur un push.
- Changer la version du workspace (
Cargo.toml) si c'est une nouvelle version ; fusionner dans la branche à publier. - PBE : lancer le workflow avec
channel = pbe. Il construit, vérifie, empaquettePrism-<version>-pbe.<n>-windows-x64.zip(channel=pbe), et publie la releasev<version>-pbe.<n>en prerelease avecSHA256SUMS.txt(case « draft » pour la créer en brouillon). - Tester ce zip (décompresser, lancer
prism.exe, pastille PBE et dossierPrismNG-PBE). - Promouvoir sans recompiler (le chemin normal vers stable) :
gh release download v0.1.0-pbe.3 --pattern "Prism-*-pbe.3-windows-x64.zip" --dir dist
.\scripts\promote.ps1 -Zip dist\Prism-0.1.0-pbe.3-windows-x64.zip -OutDir dist\stable
gh release create v0.1.0 dist\stable\Prism-0.1.0-windows-x64.zip dist\stable\SHA256SUMS.txt --title "Prism v0.1.0" --notes-file dist\stable\NOTES.md
promote.ps1 refuse un zip qui n'est pas pbe, vérifie que prism.exe correspond au SHA-256 de RELEASE.txt, écrit
channel = stable, met RELEASE.txt à jour (promoted-from), reconstruit le zip Prism-<version>-windows-x64.zip,
contrôle que le SHA-256 de prism.exe est inchangé et écrit SHA256SUMS.txt. Écrire soi-même NOTES.md (ou utiliser
--generate-notes). Le workflow accepte aussi channel = stable (reconstruction complète), à réserver au tout premier
zip ou à un cas d'urgence.
Le zip contient : prism.exe, channel, RELEASE.txt (version, canal, commit, date, SHA-256 de l'exe), LISEZMOI.txt,
mods\, skins\, themes\. Un zip stable garde son nom historique ; un zip PBE porte -pbe.<n>. En local :
.\scripts\package.ps1 [-Channel pbe] [-Label pbe.3] [-SkipBuild].
Ce que le workflow vérifie (volontairement peu)
Compilation release verrouillée (--locked, runtime statique) puis : bun run check et les tests TypeScript purs
(src/lib, src/menu, src/theme : parité des langues, réglages, menus, thèmes) ; cargo test --release -p themes -p skin -p modding (le contenu livré : thèmes, skins, mods) ; les paquets TypeScript commités doivent être ceux qu'écrit l'exe
qu'on vient de construire. Les tests du crate desktop ne tournent pas là : ils recompileraient toute l'application en
profil de test, presque aussi long que la compilation. La suite complète et les smokes (GPU, WebView2) restent dans le
flux de l'intégrateur. Le workflow n'a encore jamais tourné : première exécution à surveiller.
Coût (estimation)
Dépôt privé, plan gratuit : 2 000 minutes par mois, les minutes Windows comptent double (facteur 2 du barème GitHub). Une
compilation à froid sur windows-latest : 25 à 40 min [estimation, non mesurée] ; avec le cache cargo : 8 à 15 min
[estimation]. Une release PBE coûterait donc de l'ordre de 20 à 80 minutes décomptées à froid, 16 à 30 avec cache : le plan
gratuit n'en offre qu'une trentaine par mois à froid. Raisons de ne pas lancer le workflow à chaque fusion.
Le client de mise à jour (Réglages → À propos → Mises à jour)
Tout est dans le crate crates/updater (aucune dépendance nouvelle : ureq, ring déjà dans l'arbre) ; l'hôte
(apps/desktop/src/app/updates.rs) route les commandes de la page et les états (updateState). Chaque étape tourne sur un fil à elle,
jamais sur le fil de la fenêtre, jamais pendant une partie, un aperçu ou un replay (un téléchargement en cours s'arrête quand une
partie démarre ; le fichier partiel est gardé et repris).
| Étape | Ce qui se passe |
|---|---|
| Vérifier | un seul GET de la liste (https://prism.am/releases.json par défaut), sans identifiant, sans version, sans cookie (agent Prism-updater). Automatique une fois par jour au plus (20 s après l'interface prête, puis relecture horaire de l'échéance ; une tentative compte, un site en panne n'est pas interrogé toutes les heures), bouton « Rechercher » à la demande |
| Télécharger | uniquement sur clic. Progression, reprise Range, taille et SHA-256 vérifiés contre la liste ; le fichier faux est supprimé |
| Installer | sur clic « Redémarrer pour mettre à jour » (ou au prochain lancement si le paquet est prêt) : déplacement des fichiers avec sauvegarde, redémarrage |
Réglages (visibles, Réglages → À propos) : updateCheck (activé par défaut : il ne fait que lire la liste), updateChannel
(vide = le canal de cette installation, stable ou pbe), updateFeedUrl (vide = le site ; PRISM_UPDATE_FEED l'emporte). Aucun
n'est exporté (.pvsettings.json). L'adresse du flux doit être en https (http seulement pour localhost/127.0.0.1), et
toute adresse suivie (paquet, redirection) doit avoir le même schéma, le même hôte et le même port que le flux ; 3 redirections au
plus, suivies par le client lui-même. Un site injoignable ou pas encore déployé donne seulement « Mises à jour indisponibles ».
Le flux releases.json (contrat du site)
Par version : channel, seq, build, publishedAt (ou date), url (relative au site ou absolue), sha256, size, notesMd
(ou notes), notesEnMd, commit, semver, builtFromBuild, withdrawn / status: "withdrawn", signature (facultatif, voir plus
bas). Les champs inconnus sont ignorés ; une entrée inutilisable est écartée seule. L'ordre d'un canal est seq, jamais build
(libellé libre, jamais analysé). Même seq que l'installé : rien à faire. Un « dernier » plus ancien que l'installé (retiré) : jamais de
rétrogradation. Un autre canal : sa dernière version est toujours proposée, avec l'avertissement que le dossier de données change
(PrismNG ↔ PrismNG-PBE : le channel du paquet déplace l'installation).
Quelle version est installée
Le seq est attribué par l'outil du site après la construction du zip : le zip ne peut pas toujours le porter. Le jeu le déduit, de
la source la plus sûre à la moins sûre :
- son propre enregistrement (
update-state.json, à côté de l'exe), écrit quand ce client a installé la version, avec le SHA-256 de l'exe installé : il ne compte que tant que l'exe en cours a ce hash (un zip décompressé à la main par-dessus l'invalide) ; seq:dansRELEASE.txtsi le paquetage l'a reçu (package.ps1 -Seq N) ; ignoré si la liste connaît ceseqavec un autrecommit;- le
commitdeRELEASE.txtcontre celui de la liste (préfixe, 7 à 40 hexadécimaux ; plusieurs correspondances : celle dont lebuildest l'étiquette du paquetage, sinon le plus petitseq) ; - l'étiquette (
label:=pbe.3) égale à unbuild.
Rien ne correspond : « Non reconnue ». La dernière version reste proposée, mais jamais installée sans clic. Pour que le jeu se
reconnaisse toujours, publier avec --commit (celui de RELEASE.txt) ou donner -Seq au paquetage (voir la procédure plus bas).
Signature Ed25519 (emplacement de clé vide pour l'instant)
La liste peut porter, par version, signature : 128 hexadécimaux, signature Ed25519 des octets
prism-update-v1\n<canal>\n<seq>\n<sha256 en minuscules>\n (le hash et non le fichier : vérifiable avant tout téléchargement, et le canal
et l'ordre sont liés au paquet). crates/updater/src/signature.rs::TRUSTED_KEYS est vide : rien n'est vérifié et l'interface écrit
« Non signée ». Dès qu'une clé publique (64 hexadécimaux) y est mise, une version sans signature ou à signature invalide est refusée
(la dernière n'est pas remplacée par une plus ancienne signée). Plusieurs clés sont admises (rotation : une version qui embarque la
suivante avant que l'ancienne parte). La clé privée n'est jamais dans ce dépôt.
Proposition pour l'outil d'administration du site (à implémenter par le worker du site ; rien n'a été modifié dans son dépôt) :
prism-admin keys generate --out <fichier> (Ed25519, clé privée PKCS#8 hors dépôt et hors base, droits 0600, sauvegarde hors ligne ;
affiche la clé publique en hexadécimal à coller dans TRUSTED_KEYS) ; prism-admin release add … --sign-key <fichier> calcule la
signature du message ci-dessus et la range dans releases.json (champ signature) ; verify la revérifie ; regenerate la conserve
(jamais re-signée pour un autre seq) ; release next-seq --channel pbe affiche le prochain seq pour package.ps1 -Seq. Vecteur de
test (Ed25519 étant déterministe) : graine [7; 32], clé publique ea4a6c63e29c520abef5507b132ec5f9954776aebebe7b92421eea691446d22c,
message (canal pbe, seq 7, hash ab×32) prism-update-v1\npbe\n7\nabababababababababababababababababababababababababababababababab\n, signature
281558931de70d1d028affffbe5b7941fcd0cb1150a5d9376e3102ce6c2322f6b743cd20ba601d65ab3370a3b2c08e45a2abe61ce800c88178b3e45525bbc000
(test the_signing_vector_published_for_the_site_verifies).
Installation, sauvegarde, retour arrière
Un prism.exe en cours se renomme sous Windows (il ne s'écrase ni ne se supprime ; prouvé par un test avec une copie d'un programme
système en cours d'exécution). Tout reste à côté de l'exe, jamais dans le dossier de données (sauf update-check.json, l'heure de
la dernière vérification) :
update-staging/download/…zip.partial le zip pendant le téléchargement (repris)
update-staging/files/… le paquet décompressé (règles d'archive du téléchargeur : ni `..`, ni chemin absolu, ni lien) et contrôlé
update-staging/ready.json écrit en dernier : le paquet est complet
update-backup/<seq>/files/… chaque fichier remplacé, tel qu'il était (les deux dernières sauvegardes sont gardées)
update-backup/<seq>/manifest.json remplacés / ajoutés
update-state.json version installée, compteur de lancements, dernier retour arrière
Le paquet doit contenir prism.exe (en-tête MZ) et un fichier channel égal au canal annoncé ; les noms update-* sont réservés. Politique
des dossiers livrés (mods\, skins\, themes\) : un fichier du paquet remplace le même chemin (le contenu livré suit le jeu) et
l'ancien est gardé dans update-backup/<seq>/ s'il diffère ; tout ce que le paquet ne contient pas n'est jamais touché ni supprimé
(dossiers et fichiers ajoutés par le joueur) ; un fichier livré qu'une version supprime reste (le retirer demande le manifeste de hachage
de la phase suivante). Les modifications sur place d'un fichier livré sont donc écrasées mais sauvegardées.
Au lancement, avant la fenêtre : le compteur de lancements d'une version fraîchement installée augmente ; l'interface prête (ready) le
remet à zéro. Deux lancements de suite sans atteindre l'interface : au troisième, les fichiers sont remis (les fichiers fautifs vont dans
update-backup/<seq>/failed/), l'ancienne version redémarre et Réglages → À propos le dit. Une installation interrompue (coupure,
processus tué) est annulée au lancement suivant (le manifeste est écrit avant le premier déplacement). Le nouveau processus attend la
fin de l'ancien (--after-update <pid>) avant de prendre le verrou d'instance et le profil WebView2. Limite : le garde-fou tourne dans le
nouvel exe ; un exe qui ne se charge même pas ne peut pas se remettre lui-même (restaurer update-backup/<seq>/files/prism.exe).
Le programme suppose que l'exe s'appelle prism.exe et que son dossier est inscriptible (pas dans Program Files : sinon
« dossier non inscriptible »).
Couper une release et la publier sur le site (sans CI : la voie retenue)
.\scripts\package.ps1 -Channel pbe -Label pbe.4 [-Seq N](leseqne sert qu'à la reconnaissance :release next-seqdu site, si l'outil l'offre).RELEASE.txtporte la version, le canal, l'étiquette, leseqs'il est donné, le commit, la date et le SHA-256 de l'exe.- Envoyer le zip sur le serveur ;
prism-admin release add --channel pbe --build "PBE 0004" --zip … --commit <commit de RELEASE.txt> --notes …. Le jeu des joueurs voit la version au prochain contrôle (une fois par jour, ou « Rechercher »). - Promouvoir sans recompiler :
.\scripts\promote.ps1 -Zip <zip pbe>produit le zip stable (leseq:du PBE y est retiré : le site attribue celui de stable), puis le publier de la même façon avec--channel stable. Retirer une version :prism-admin release withdraw(elle disparaît de la liste ; un client qui l'avait vue ne la télécharge plus).
.github/workflows/release.yml reste dans le dépôt mais la décision de l'auteur est de ne pas utiliser la CI GitHub pour l'instant.
Ce qui n'est pas prouvé
Testé : tout le crate contre un vrai serveur HTTP local (flux, zip, hash faux, signature fausse ou absente, version retirée, téléchargement
coupé puis repris, zip-slip, même seq, changement de canal, redirections vers un autre hôte), l'installation, le retour arrière, et le renommage d'un
exécutable en cours. Non prouvé, seul un vrai passage sur le site le montre : le TLS et les en-têtes réels du site (Range,
Content-Range, redirections de Caddy), la reconnaissance d'une version publiée avec les vrais champs, le redémarrage réel (nouveau processus,
mutex, WebView2) et l'application au lancement. Aucun prism.exe n'a été lancé pour ce travail.
Suite
- Générer la clé de signature et la mettre dans
TRUSTED_KEYS(décision de l'auteur : où vit la clé privée, sa sauvegarde, la rotation). - Manifeste de hachage des dossiers livrés, « Dupliquer pour personnaliser », pierres tombales (retirer un fichier livré).
- Installeur (amorce WebView2), signature des exécutables, deltas, déploiement progressif.