Aller au contenu

Session 26 — Scripts UI v3 · Onglet Runs · Droits JMeter/Scripts

Durée

~4h


Objectifs

  • Enrichir Scripts UI avec les nouvelles fonctionnalités post-déploiement Phase 10
  • Ajouter la persistance des runs sur disque (onglet 🏃 Runs)
  • Étendre le système de droits admin avec deux nouveaux accès : JMeter et Scripts
  • Corriger un XSS résiduel dans l'interface de gestion des comptes

Ce qui a été livré

Scripts UI — nouvelles fonctionnalités (v3)

Dépendances locales (zéro réseau)

Toutes les dépendances CDN et Google Fonts ont été remplacées par des fichiers locaux dans scripts-ui/public/vendor/ :

Fichier Source Licence
codemirror.min.css cdnjs — CodeMirror 5.65.16 MIT ✅
dracula.min.css cdnjs — thème Dracula MIT ✅
codemirror.min.js cdnjs — CodeMirror 5.65.16 MIT ✅
python.min.js cdnjs — mode Python MIT ✅

L'application fonctionne désormais sans accès internet — cas d'usage NAS offline.

Drag & drop de l'arborescence

Les fichiers .robot et .py peuvent être glissés d'un dossier vers un autre directement dans l'arborescence de gauche.

Événement Comportement
dragstart sur un fichier Opacité 0.5 — feedback visuel
dragover sur un dossier Fond violet + bordure drag-over
dragleave Guard !row.contains(e.relatedTarget) — pas de flash enfant
drop POST /api/moveloadTree() + loadCommits()
Dépôt sur le dossier parent No-op silencieux (srcPath === dstPath)
Fichier ouvert déplacé currentFile.path mis à jour automatiquement

Filtrage par extension

Le bouton ▶ Lancer est désormais grisé pour tous les fichiers non exécutables (.gitkeep, tout autre format). La validation est double :

  • Côté UI (openFile()) : btnRun.disabled = !(ext === 'robot' || ext === 'pytest')
  • Côté serveur (POST /api/run) : path.extname().toLowerCase() → HTTP 400 si hors .robot/.py

Bouton « ⬇️ Pull Forgejo »

Le bouton « 🔄 Sync Git » a été renommé en « ⬇️ Pull Forgejo » avec un tooltip explicite. 5 occurrences mises à jour (HTML, JS état running, JS restauration, toasts succès/échec).

Onglet 🏃 Runs (persistance sur disque)

Nouveau troisième onglet dans le panneau bas, aux côtés de « 📋 Résultat » et « 📜 Historique ».

Persistance : à la fin de chaque exécution (PASS, FAIL ou erreur), un dossier /rf-logs/runs/<runId>/ est créé avec :

Fichier Contenu
meta.json script, startedAt, endedAt, status, rc
output.txt Sortie complète du run (stdout + stderr)
result.xml Copie du XML JUnit (si présent dans /rf-logs/)

Routes backend :

Route Description
GET /api/runs Liste des 50 derniers runs, triés date desc
GET /api/runs/:id Détail d'un run (meta + output) — validation anti-traversal

UI :

  • Chaque ligne affiche : badge PASS/FAIL/ERR · nom du script · durée · date
  • Clic sur une ligne → bascule sur l'onglet Résultat avec l'output complet
  • accountsById rechargé à chaque loadRuns() — pas de fuite mémoire

Volume nécessaire : ./test-runner/logs:/rf-logs monté sur perfshop-scripts-ui sans :ro — ajouté dans les 3 docker-compose lors de cette session.


Droits JMeter et Scripts — nouvelle migration V31

Deux nouveaux droits d'accès ajoutés à la table admin_users :

Colonne SQL Champ Java Rôle
can_access_jmeter canAccessJmeter Accès interface JMeter
can_access_scripts canAccessScripts Accès interface Scripts UI

Migration Flyway V31__add_jmeter_scripts_rights.sql

ALTER TABLE admin_users
    ADD COLUMN can_access_jmeter  BOOLEAN NOT NULL DEFAULT FALSE,
    ADD COLUMN can_access_scripts BOOLEAN NOT NULL DEFAULT FALSE;

UPDATE admin_users
SET can_access_jmeter = TRUE, can_access_scripts = TRUE
WHERE is_superadmin = TRUE;

Les comptes existants restent à FALSE par défaut (accès refusé, comportement conservateur). Le superadmin est mis à jour automatiquement par la migration SQL et par le guard bootstrapSuperAdmin() en Java (double filet de sécurité).

Fichiers modifiés

Fichier Modifications
V31__add_jmeter_scripts_rights.sql Nouveau — ALTER TABLE + UPDATE superadmin
AdminUser.java +2 champs @Column avec nullable = false
AdminUserService.java createAdmin() +2 params · updateRights() +2 params · bootstrapSuperAdmin() guard V31
AdminController.java login() +2 clés JSON · createAccount() +2 params · updateRights() +2 params · adminToDto() +2 champs
admin-users.html Tableau +2 colonnes · formulaire +2 cases à cocher

Interface admin-users.html

Le tableau des comptes administrateurs affiche maintenant 9 colonnes : Email · Chaos-admin · Monitoring · Backoffice · JMeter · Scripts · Rôle · Créé le · Actions

Les nouvelles cases à cocher (Backoffice, JMeter, Scripts) sont décochées par défaut lors de la création d'un compte — principe du moindre privilège.


Correction XSS dans renderTable()

Bug préexistant corrigé : l'email passait dans un attribut onclick inline entre apostrophes. Un email contenant ' (ex : o'reilly@test.fr) cassait le JavaScript.

Correction — pattern délégation + registre mémoire :

// Registre : id → account object (données jamais dans le DOM)
const accountsById = new Map();

// HTML généré : seul l'entier id transite dans data-*
`<button class="btn btn-delete" data-id="${a.id}">🗑 Supprimer</button>`

// Délégation d'événements — email lu depuis JS, jamais depuis le DOM
tbody.onclick = e => {
  const btn     = e.target.closest('button[data-id]');
  const id      = Number(btn.dataset.id);
  const account = accountsById.get(id);
  if (btn.classList.contains('btn-delete')) deleteAccount(id, account.email);
  if (btn.classList.contains('btn-save'))   openPasswordModal(id);
};

Bénéfices collatéraux : un seul listener au lieu de N handlers inline, clear() à chaque rechargement évite toute fuite mémoire.


docker-compose — modifications (3 fichiers)

Modification Détail
Service perfshop-filebrowser supprimé Remplacé fonctionnellement par Scripts UI
Volume filebrowser-data supprimé Plus aucun consommateur
./test-runner/logs:/rf-logs ajouté sur perfshop-scripts-ui Sans :ro — écriture nécessaire pour les runs
./test-runner/logs:/rf-logs:ro conservé sur Promtail Inchangé
Typo ci@perfshep.fr corrigée → ci@perfshop.fr Dans docker-compose.build.yml

Déploiement

Scripts UI (redémarrage simple)

# Le volume /rf-logs étant nouveau, down/up obligatoire (pas un restart)
docker compose stop perfshop-scripts-ui
docker compose up -d perfshop-scripts-ui
docker logs -f perfshop-scripts-ui

Backend Spring Boot (rebuild + migration Flyway automatique)

docker compose build perfshop-app
docker compose up -d perfshop-app
# Vérifier dans les logs :
# Flyway: Successfully applied 1 migration ... V31
# [AdminUserService] Droits JMeter/Scripts ajoutés au superadmin

chaos-admin (rebuild image nginx)

docker compose build perfshop-chaos-admin
docker compose up -d perfshop-chaos-admin

Suppression Filebrowser (NAS)

docker compose stop perfshop-filebrowser
docker compose rm -f perfshop-filebrowser
docker volume rm perfshop_filebrowser-data

Validation post-déploiement

Test Attendu
Bouton « ⬇️ Pull Forgejo » visible
Glisser un .robot vers un sous-dossier ✅ Déplacé dans Forgejo
Lancer un .robot → onglet 🏃 Runs rempli après fin
Clic ligne dans Runs → onglet Résultat avec output
Créer un compte admin avec case JMeter cochée
Email avec apostrophe dans la liste → aucun bug JS
Bouton ▶ Lancer grisé sur .gitkeep
Logs backend : [Run] run-1-xxx — PASSED (rc=0)

Erreurs documentées

Affichage fichiers : view vs cat dans la conversation

Contexte : pour afficher de gros fichiers dans la conversation, view produisait un rendu JSON échappé illisible dans l'UI Claude.
Fix : Filesystem:write_file directement sur Windows — aucun affichage dans la conversation.
Règle adoptée : gros fichiers → écriture directe Windows, pas d'affichage dans la conversation.