feat(deploy): install silencieuse (dashboard) + MAJ GPO clients Léa + procédure Julien — 2026-07-06
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m58s
tests / Tests unitaires (sans GPU) (push) Failing after 2m8s
tests / Tests sécurité (critique) (push) Has been skipped

Deux canaux de déploiement des clients Léa, en s'appuyant sur l'installeur EXE
v1.0.2 existant (per-user, upgrade-safe, mode /VERYSILENT /CONFIG=).

- Route dashboard `GET /api/fleet/installer` (web_dashboard/app.py, insertion pure,
  125 lignes, 0 suppression) : sert un ZIP {EXE + install_silencieux.bat + enroll.txt
  (SERVER_URL/token injectés via _resolve_public_server_url) + LISEZMOI} pour un poste
  NEUF. L'EXE génère lui-même le machine_id → pas de pré-enregistrement (distinct de
  la voie ZIP download_agent_package). Tri EXE en semver (1.0.10 > 1.0.2). Testée e2e.
- deploy/installer/silent/ : lanceur d'install silencieuse + gabarit enroll + notice.
- deploy/gpo/Deploy-LeaUpdate.ps1 : MAJ upgrade-safe via GPO **logon script user-context**
  (install per-user invisible au contexte SYSTEM). Détection version = **DisplayVersion
  du registre HKCU** (primaire pour install EXE ; le config.txt EXE ne porte PAS la
  version — vérifié sur poste réel), fallback RPA_AGENT_VERSION (installs ZIP).
  Comparaison semver, idempotent, journalisation best-effort silencieuse, non bloquant
  à l'ouverture de session. Options -DryRun / -TargetVersionOverride / -LogShareOverride.
  **Validé sur poste réel .11 (Windows PowerShell 5.1)** : branche « déjà à jour » et
  branche « MAJ requise » (DryRun, 0 install), détection = 1.0.2.
- docs/PROCEDURE_DEPLOIEMENT_LEA_JULIEN.md : procédure (poste neuf / MAJ manuelle / GPO / rollback).
- EXE binaire jamais versionné (deploy/installer/releases/.gitignore).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-07-06 10:22:34 +02:00
parent f4bef1de37
commit 48b1fc2800
8 changed files with 547 additions and 0 deletions

View File

@@ -0,0 +1,181 @@
<#
.SYNOPSIS
Met a jour l'agent Lea (installe per-user) via un script d'OUVERTURE DE SESSION GPO.
.DESCRIPTION
============================================================================
A DEPLOYER EN : User Configuration > Policies > Windows Settings >
Scripts (Logon/Logoff) > Logon.
ET PAS EN "Computer > Startup".
============================================================================
RAISON (non negociable) : l'installeur Lea est PER-USER
(%LOCALAPPDATA%\Programs\Lea, cle de desinstallation sous HKCU). Un script de
DEMARRAGE MACHINE tourne en contexte SYSTEM : il ne verrait NI l'installation
NI HKCU du collaborateur -> il ne mettrait jamais rien a jour. Le contexte
UTILISATEUR est donc obligatoire.
Le script, a chaque ouverture de session :
1. Detecte la version installee (DisplayVersion de la cle de desinstallation
Inno dans HKCU — primaire pour un install EXE ; fallback RPA_AGENT_VERSION
du config.txt, present uniquement sur les installs via ZIP).
2. La compare a la version cible (comparaison semver correcte :
1.0.2 < 1.0.10, contrairement a une comparaison de chaines).
3. Si plus ancienne : lance l'installeur en mode SILENCIEUX + UPGRADE-SAFE
(SANS /CONFIG -> machine_id, serveur et token du poste PRESERVES).
4. Journalise le resultat. IDEMPOTENT : ne refait rien si deja a jour.
Ne leve JAMAIS d'exception bloquant l'ouverture de session (tout en try/catch,
sortie 0 sur erreur non geree).
.NOTES
Execution : configurer la GPO pour lancer
powershell.exe -NoProfile -ExecutionPolicy Bypass -File Deploy-LeaUpdate.ps1
Test sur un poste (lecture seule, ne telecharge/installe RIEN) :
powershell.exe -NoProfile -ExecutionPolicy Bypass -File Deploy-LeaUpdate.ps1 -DryRun
#>
param(
# -DryRun : teste la DECISION (version installee vs cible) et journalise ce
# qui SERAIT fait, sans rien telecharger ni installer. Pour valider un poste.
[switch]$DryRun,
# Overrides optionnels (sinon = valeurs du bloc PARAMETRES ci-dessous).
# Utiles pour tester un poste (cible bumpee, journal local) sans editer le script.
[string]$TargetVersionOverride,
[string]$LogShareOverride
)
# ============================================================================
# PARAMETRES A ADAPTER PAR LE DSI / Julien (les 3 seules lignes a toucher)
# ============================================================================
# Source de l'installeur : chemin UNC du domaine (recommande) OU URL http(s).
# UNC : \\SRV-FICHIERS\Deploiement$\Lea\Lea-Setup-v1.0.2.exe
# HTTPS : https://lea.labs.laurinebazin.design/api/fleet/installer/exe
$ExeSource = '\\SRV-FICHIERS\Deploiement$\Lea\Lea-Setup-v1.0.2.exe'
# Version cible : DOIT correspondre a l'EXE ci-dessus.
$TargetVersion = '1.0.2'
# Dossier de journalisation partage (audit Julien). Vide => journal local %TEMP%.
$LogShare = '\\SRV-FICHIERS\Deploiement$\Lea\logs'
# ============================================================================
# Ne rien modifier en dessous de cette ligne.
# ============================================================================
# Overrides de ligne de commande (prioritaires sur le bloc PARAMETRES).
if ($TargetVersionOverride) { $TargetVersion = $TargetVersionOverride }
if ($PSBoundParameters.ContainsKey('LogShareOverride')) { $LogShare = $LogShareOverride }
$InstallDir = Join-Path $env:LOCALAPPDATA 'Programs\Lea'
$ConfigTxt = Join-Path $InstallDir 'config.txt'
$AppUninst = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\{B3F9A1E2-5C4D-4E7F-9A1B-2C3D4E5F6789}_is1'
function Write-Log([string]$msg) {
$line = '{0} {1}\{2} {3}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $env:COMPUTERNAME, $env:USERNAME, $msg
Write-Output $line
# Journalisation best-effort : ne DOIT jamais perturber l'ouverture de session.
# -ErrorAction SilentlyContinue car un partage injoignable produit une erreur
# NON-terminante (non capturee par try/catch) — verifie sur poste reel .11.
try {
$dir = if ($LogShare) { $LogShare } else { Join-Path $env:TEMP 'Lea-update-logs' }
if (-not (Test-Path $dir -ErrorAction SilentlyContinue)) {
New-Item -ItemType Directory -Path $dir -Force -ErrorAction SilentlyContinue | Out-Null
}
$file = Join-Path $dir ('{0}_{1}.log' -f $env:COMPUTERNAME, $env:USERNAME)
Add-Content -Path $file -Value $line -Encoding UTF8 -ErrorAction SilentlyContinue
} catch { }
}
function Get-InstalledVersion {
# 1. Source de verite pour un install EXE (Inno) : DisplayVersion dans HKCU
# (install per-user). Toujours ecrite par l'installeur -> methode primaire.
# Verifie sur poste reel .11 : le config.txt genere par l'EXE ne contient
# PAS de ligne de version, seul le registre fait foi.
if (Test-Path $AppUninst) {
$dv = (Get-ItemProperty -Path $AppUninst -Name DisplayVersion -ErrorAction SilentlyContinue).DisplayVersion
if ($dv) { return $dv }
}
# 2. Fallback : RPA_AGENT_VERSION dans config.txt (present sur les installs
# via ZIP/Python ; absent des installs via EXE).
if (Test-Path $ConfigTxt) {
$m = Select-String -Path $ConfigTxt -Pattern '^\s*RPA_AGENT_VERSION\s*=\s*(.+?)\s*$' -ErrorAction SilentlyContinue
if ($m) { return $m.Matches[0].Groups[1].Value.Trim() }
}
return $null
}
function ConvertTo-VersionParts([string]$v) {
$clean = ($v -replace '^[vV]', '').Trim()
$parts = New-Object System.Collections.Generic.List[int]
foreach ($p in ($clean -split '\.')) {
$n = 0
if ([int]::TryParse($p, [ref]$n)) { $parts.Add($n) } else { $parts.Add(0) }
}
while ($parts.Count -lt 3) { $parts.Add(0) }
return $parts
}
function Compare-Semver([string]$a, [string]$b) {
# -1 si a<b, 0 si egal, 1 si a>b. Tolerant (piege 1.0.2 < 1.0.10).
$pa = ConvertTo-VersionParts $a
$pb = ConvertTo-VersionParts $b
$max = [Math]::Max($pa.Count, $pb.Count)
for ($i = 0; $i -lt $max; $i++) {
$va = if ($i -lt $pa.Count) { $pa[$i] } else { 0 }
$vb = if ($i -lt $pb.Count) { $pb[$i] } else { 0 }
if ($va -lt $vb) { return -1 }
if ($va -gt $vb) { return 1 }
}
return 0
}
try {
$installed = Get-InstalledVersion
if (-not $installed) {
Write-Log 'Lea non installe sur ce profil -> ignore (les nouveaux postes passent par le dashboard).'
exit 0
}
if ((Compare-Semver $installed $TargetVersion) -ge 0) {
Write-Log ('Deja a jour (installe={0}, cible={1}) -> rien a faire.' -f $installed, $TargetVersion)
exit 0
}
if ($DryRun) {
Write-Log ('[DryRun] MAJ qui SERAIT appliquee : {0} -> {1}. Aucune action (ni telechargement ni installation).' -f $installed, $TargetVersion)
exit 0
}
Write-Log ('MAJ requise : installe={0} < cible={1}. Recuperation de l''installeur...' -f $installed, $TargetVersion)
# Recuperer l'EXE (UNC ou URL) vers un fichier temporaire local.
$localExe = Join-Path $env:TEMP ('Lea-Setup-{0}.exe' -f $TargetVersion)
if ($ExeSource -match '^(?i)https?://') {
Invoke-WebRequest -Uri $ExeSource -OutFile $localExe -UseBasicParsing
} else {
Copy-Item -Path $ExeSource -Destination $localExe -Force
}
if (-not (Test-Path $localExe)) {
Write-Log ('ECHEC : installeur introuvable apres recuperation ({0}).' -f $ExeSource)
exit 1
}
# Installation SILENCIEUSE + UPGRADE-SAFE (sans /CONFIG : identite du poste preservee).
# L'installeur arrete Lea (via lock), sauvegarde <app>_backup, puis met a jour.
$logInstall = Join-Path $env:TEMP ('Lea-upgrade-{0}.log' -f (Get-Date -Format 'yyyyMMdd_HHmmss'))
$installArgs = @('/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', ('/LOG={0}' -f $logInstall))
$proc = Start-Process -FilePath $localExe -ArgumentList $installArgs -Wait -PassThru
$rc = $proc.ExitCode
if ($rc -eq 0) {
$now = Get-InstalledVersion
Write-Log ('MAJ OK : {0} -> {1} (code 0).' -f $installed, $now)
} else {
Write-Log ('ECHEC MAJ : code {0}. Journal installeur : {1}.' -f $rc, $logInstall)
}
exit $rc
} catch {
Write-Log ('ERREUR non geree : ' + $_.Exception.Message)
exit 0 # ne JAMAIS bloquer l'ouverture de session
}

5
deploy/installer/releases/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
# L'installeur EXE (~33 Mo binaire) est déposé ici mais JAMAIS versionné.
# On garde le dossier + son LISEZMOI, on ignore tout le reste.
*
!.gitignore
!LISEZMOI.txt

View File

@@ -0,0 +1,17 @@
============================================================
deploy/installer/releases/ — Depot des installeurs EXE
============================================================
DEPOSER ICI l'installeur "Lea-Setup-vX.Y.Z.exe" (buildé sur .11).
Le dashboard sert le plus RECENT via la route :
GET /api/fleet/installer
-> paquet ZIP "Lea-Install-Silencieux-vX.Y.Z.zip"
(EXE + install_silencieux.bat + enroll.txt pré-rempli + LISEZMOI)
L'EXE (~33 Mo binaire) n'est VOLONTAIREMENT pas versionné dans git.
Pour pointer ailleurs : variable d'environnement RPA_LEA_RELEASES_DIR.
Ce fichier LISEZMOI.txt sert uniquement à garder le dossier présent
dans le dépôt (l'EXE, lui, est déposé à la main / par script de release).
============================================================

View File

@@ -0,0 +1,40 @@
============================================================
Lea - Installation silencieuse (nouveau poste)
============================================================
CE DOSSIER CONTIENT :
- Lea-Setup-vX.Y.Z.exe : l'installeur Lea
- install_silencieux.bat : le lanceur d'installation
- enroll.txt : les parametres d'enrolement a remplir
- LISEZMOI_SILENCIEUX.txt : ce fichier
------------------------------------------------------------
QUAND UTILISER CETTE VOIE ?
------------------------------------------------------------
Pour installer Lea sur un poste qui NE l'a PAS encore.
(Pour METTRE A JOUR un poste deja installe : voir la voie GPO,
ou relancer simplement l'installeur qui detecte l'existant.)
------------------------------------------------------------
PROCEDURE (3 etapes, ~2 min, sans droits administrateur)
------------------------------------------------------------
1. Ouvrir "enroll.txt" avec le Bloc-notes.
Renseigner : USER_NAME, USER_EMAIL, SERVER_URL, API_TOKEN.
(Remplacer les valeurs "CONFIGURE_ME".) Enregistrer.
2. Double-cliquer sur "install_silencieux.bat".
L'installation se deroule sans fenetre d'installation.
Ne pas fermer la fenetre noire avant le message "OK".
3. Verifier que Lea demarre (icone dans la barre des taches,
pres de l'horloge). C'est termine.
------------------------------------------------------------
EN CAS DE PROBLEME
------------------------------------------------------------
- Message "valeurs CONFIGURE_ME" : enroll.txt n'est pas rempli.
- Message "aucun Lea-Setup trouve" : l'EXE n'est pas dans ce dossier.
- Autre erreur : le journal detaille est indique a l'ecran
(dossier %TEMP%, fichier Lea-install-silencieux.log).
Le transmettre a l'administrateur AIVANOV.
============================================================

View File

@@ -0,0 +1,31 @@
# ============================================================
# enroll.txt — Enrolement pour installation SILENCIEUSE
# ------------------------------------------------------------
# Utilise par install_silencieux.bat :
# Lea-Setup-vX.Y.Z.exe /VERYSILENT /CONFIG=enroll.txt
#
# L'installeur lit ce fichier au demarrage et remplit les
# informations d'enrolement SANS interface graphique.
#
# A FAIRE : renseigner les valeurs ci-dessous (remplacer les
# CONFIGURE_ME), enregistrer, puis lancer install_silencieux.bat.
#
# Format : CLE=valeur, une ligne par parametre, # = commentaire.
# NOTE : ce fichier sert l'INSTALL NEUVE. Sur une mise a jour,
# l'installeur preserve tout seul l'identite du poste et
# IGNORE ce fichier (voir la voie GPO).
# ============================================================
# --- Identite du collaborateur ---
USER_NAME=Prenom Nom
USER_EMAIL=prenom.nom@clinique-wallerstein.fr
USER_ID=
# --- Connexion au serveur Lea ---
# Exemples de SERVER_URL :
# LAN clinique (DGX) : http://192.168.1.178:5005/api/v1
# Internet : https://lea.labs.laurinebazin.design/api/v1
SERVER_URL=CONFIGURE_ME
# Token d'authentification (fourni par l'administrateur AIVANOV)
API_TOKEN=CONFIGURE_ME

View File

@@ -0,0 +1,73 @@
@echo off
chcp 65001 >nul 2>&1
setlocal enabledelayedexpansion
title Lea - Installation silencieuse (nouveau poste)
:: ============================================================
:: install_silencieux.bat
:: Installe Lea sur un NOUVEAU poste, sans interface graphique.
::
:: Pre-requis : ce script, l'installeur "Lea-Setup-v*.exe" et
:: "enroll.txt" (rempli) doivent etre dans le MEME dossier.
::
:: Installation PER-USER : aucun droit administrateur requis.
:: ============================================================
set "HERE=%~dp0"
set "ENROLL=%HERE%enroll.txt"
set "LOG=%TEMP%\Lea-install-silencieux.log"
echo.
echo ============================================================
echo Lea - Installation silencieuse (nouveau poste)
echo ============================================================
echo.
:: --- 1. Localiser l'installeur (Lea-Setup-v*.exe, version la plus recente) ---
set "EXE="
for /f "delims=" %%f in ('dir /b /o-n "%HERE%Lea-Setup-v*.exe" 2^>nul') do (
if not defined EXE set "EXE=%HERE%%%f"
)
if not defined EXE (
echo ERREUR : aucun "Lea-Setup-v*.exe" trouve dans ce dossier.
echo Placez ce script a cote de l'installeur Lea.
echo.
pause
exit /b 1
)
echo Installeur detecte : !EXE!
:: --- 2. Verifier enroll.txt ---
if not exist "%ENROLL%" (
echo ERREUR : "enroll.txt" introuvable a cote de ce script.
echo.
pause
exit /b 1
)
findstr /C:"CONFIGURE_ME" "%ENROLL%" >nul 2>&1
if not errorlevel 1 (
echo.
echo ATTENTION : "enroll.txt" contient encore des valeurs CONFIGURE_ME.
echo Ouvrez enroll.txt, renseignez SERVER_URL / API_TOKEN / USER_*,
echo enregistrez, puis relancez ce script.
echo.
pause
exit /b 1
)
:: --- 3. Installation silencieuse (per-user, pas d'admin) ---
echo Installation en cours (silencieuse, ~1-2 min)... ne fermez pas cette fenetre.
"!EXE!" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /CONFIG="%ENROLL%" /LOG="%LOG%"
set "RC=!errorlevel!"
echo.
if "!RC!"=="0" (
echo Installation terminee - OK.
echo Lea est enrolle et pret. Journal : %LOG%
) else (
echo ERREUR : l'installation a echoue ^(code !RC!^).
echo Consultez le journal : %LOG%
)
echo.
pause
endlocal