diff --git a/ansible/roles/portail/tasks/03-code.yml b/ansible/roles/portail/tasks/03-code.yml index 05b9e88..b03c8a2 100644 --- a/ansible/roles/portail/tasks/03-code.yml +++ b/ansible/roles/portail/tasks/03-code.yml @@ -41,6 +41,9 @@ - "--exclude=/storage" - "--exclude=/bootstrap/cache" - "--exclude=/public/build" + # Produit sur le serveur par `npm run build` (scripts/copier-vendor.mjs), + # donc appartenant à root : ne jamais le synchroniser depuis le Mac. + - "--exclude=/public/vendor" - "--exclude=/public/hot" - "--exclude=/.git" register: portail_code_synchronise diff --git a/docs/dette.md b/docs/dette.md index 57cd40c..c479fdc 100644 --- a/docs/dette.md +++ b/docs/dette.md @@ -14,14 +14,14 @@ retirer la ligne (et le noter dans le journal) quand c'est fait. | Vitrine : 52 scripts en ligne ; Pyodide et sql.js depuis jsDelivr (`/ide`) ; vidéo YouTube possible (`/cours/…/cm`) | CSP vitrine avec `'unsafe-inline'` ; tiers déclarés dans `/confidentialite`. Polices, xterm.js et CodeMirror sont auto-hébergés depuis l'étape 14. Héberger Pyodide/sql.js, passer les scripts en fichiers. | Avant ouverture publique | Étapes 12 et 14 | | xterm.js 5.5.0 (6.0.0 disponible) | Version majeure à évaluer séparément. | Bloc B | Étape 12 | | NodeSource installé par `curl … \| bash` | Script distant exécuté en root au premier déploiement. Déclarer le dépôt (deb822) avec une clé vérifiée. | Bloc B | Étape 8 | -| Aucune vérification dans un vrai navigateur | Extension Chrome non connectée (étapes 8, 12 et 14). La CSP n'est contrôlée que par ses rapports. À vérifier en priorité : `/ide` (Pyodide, WebAssembly) et les pages vitrine qui utilisent xterm.js/CodeMirror désormais servis par le portail. | Dès que possible | Étapes 8, 12, 14 | +| Aucune vérification dans un vrai navigateur | Extension Chrome non connectée (étapes 8, 12 et 14). La CSP n'est contrôlée que par ses rapports. Adam a testé `/ide` le 2026-10-09 (erreurs corrigées) ; à revérifier : exécution Python et SQL de `/ide`, pages vitrine utilisant xterm.js/CodeMirror servis par le portail. | Dès que possible | Étapes 8, 12, 14 | | Pas de sonde hors du serveur | Si le serveur tombe, personne n'est prévenu. | À décider avec Adam | Étape 7 | | Kolla installé depuis une branche, pas un tag | Reproductibilité. | Montée de version | ADR 0001 | | Correction séquentielle (~5 s pour le lab 08) | Acceptable ; à paralléliser si la charge l'exige. | Bloc B | Étape 11 | | Jeton de console : ≈ 1,1 s par appel Nova `remote-consoles` | Plus gros poste de l'ouverture d'un lab (2,8 s au total, critère < 5 s tenu). Préparer les jetons à l'attribution si besoin. | Bloc B | Étape 13 | | Tâches Ansible toujours « modifiées » (composer, npm, build, cache) | Brouille la lecture de l'idempotence. | Bloc B | Étape 8 | | `Permissions-Policy` ferme caméra et micro | À ouvrir pour la visio. | Étape 15 | Étape 12 | -| Mentions légales à compléter | Forme juridique, SIREN et adresse du siège d'Esquisse Formation ; délégué à la protection des données s'il en est désigné ; article « Disponibilité et responsabilité » des CGU. | Avant le pilote | Étape 14 | +| Mentions légales à compléter | Article « Disponibilité et responsabilité » des CGU ; délégué à la protection des données s'il en est désigné (éditeur, SIREN et adresse complétés le 2026-10-09). | Avant le pilote | Étape 14 | | Slogans « du lycée au master » | Le catalogue va aujourd'hui du lycée au BUT. Positionnement laissé tel quel : décision éditoriale d'Adam. | À décider | Étape 14 | | Ancien `storage/logs/laravel.log` | Fichier unique d'avant la rotation quotidienne (étape 14) : jamais purgé, à supprimer ou archiver (accord d'Adam). | Dès que possible | Étape 14 | | Pages d'aperçu publiques (32) | Signalées comme aperçus avec données fictives ; à retirer ou remplacer au fur et à mesure que les fonctions réelles arrivent. | Au fil du bloc B | Étape 14 | diff --git a/docs/journal.md b/docs/journal.md index ea29e2a..d8f0f15 100644 --- a/docs/journal.md +++ b/docs/journal.md @@ -600,3 +600,15 @@ Une politique de confidentialité n'est pas un texte juridique à recopier : c'e - Adam : compléter forme juridique, SIREN, adresse du siège (et DPO s'il y en a un) dans `/legal` et `/confidentialite` ; vérifier `/ide` dans un navigateur. - Étape 15 : visio de classe — seulement après validation des étapes 1 à 11 (le prompt l'exige). + +## 2026-10-09 — Étape 14 (suite) : retours du test d'Adam dans son navigateur + +Adam a ouvert `/ide` et transmis la console du navigateur, plus sa fiche INPI. + +- **`/ide` n'a jamais fonctionné en production** : « Uncaught SyntaxError: Unexpected token '.' ». Dans la maquette `design/` elle-même, des `!!x` (conversion en booléen) sont devenus `.x` (4 occurrences, seulement dans `/ide`, vérifié par une recherche sur tous les scripts). Corrigé dans le portail (pas dans `design/`). **Nouveau test Pest** : chaque script en ligne de chaque page publique est analysé par `node --check` ; vérifié qu'il échoue sur l'ancienne version. +- **Aperçu HTML de `/ide` hors de son bac à sable** : `sandbox="allow-scripts allow-same-origin"` faisait tourner le code de l'élève avec l'origine `syllabuslab.fr`. Passé à `allow-scripts` seul ; la vérification automatique s'exécute dans l'aperçu et renvoie ses résultats par `postMessage` (délai de 3 s si la page de l'élève ne répond pas). +- **Régression introduite à l'étape 14** : `public/css/syllabus-theme.css` importait Mulish (police principale de tout le site) depuis Google par `@import`. Mon test ne regardait que le HTML ; la CSP durcie bloquait l'appel, donc plus de fuite d'IP, mais le site s'affichait avec une police de remplacement. Mulish ajoutée aux polices servies par le portail, `@import` retiré, test étendu aux feuilles de style de `public/css`. +- **Déploiement en échec passé inaperçu** : `npm run build`, lancé en root sur le serveur, a créé `public/vendor/` au nom de root ; le `rsync` suivant (compte `adam`) n'a pas pu y écrire. Mon filtre de sortie n'affichait ni l'échec ni le récapitulatif : je l'ai pris pour un succès, et c'est la vérification en production qui a montré que rien n'avait changé. `public/vendor/` exclu du `rsync` (même piège qu'à l'étape 9). Règle pour la suite : toujours lire la ligne `PLAY RECAP` (et le code de sortie) avant de conclure. +- **Mentions légales complétées** d'après la fiche INPI : Adam Belkacemi, entrepreneur individuel (EI), nom commercial Esquisse Formation, SIREN 838 093 268, SIRET 838 093 268 00087, 30 rue Lorenzaccio, 38100 Grenoble. La date de naissance de la fiche n'est pas reprise. Restent à compléter : l'article « Disponibilité et responsabilité » des CGU, et un éventuel délégué à la protection des données. + +Vérifié en production : `/ide` 1 script en ligne, 0 erreur de syntaxe, `sandbox="allow-scripts"` ; Mulish déclarée par le portail ; aucun `@import` vers Google ; `/vendor/xterm/xterm.js` et `/vendor/codemirror/codemirror.js` en 200. 35 tests Pest. diff --git a/portail/public/css/syllabus-theme.css b/portail/public/css/syllabus-theme.css index 793b0c9..2014f70 100644 --- a/portail/public/css/syllabus-theme.css +++ b/portail/public/css/syllabus-theme.css @@ -1,5 +1,5 @@ /* Syllabus — thème global. Surcharge les anciennes classes néo-brutalistes pour appliquer la DA "SaaS doux" de la bibliothèque v2. */ -@import url('https://fonts.googleapis.com/css2?family=Mulish:wght@400;500;600;700;800&display=swap'); +/* Mulish : servie par le portail (Vite::fonts(), vite.config.js), plus par Google Fonts (étape 14). */ :root { --sy-bg:#f5f6f8; --sy-surface:#fff; --sy-line:#b8c1cf; --sy-ink:#111827; --sy-muted:#6b7280; --sy-blue:#1d5cf5; --sy-blue-dark:#174bd0; --sy-navy:#1e3a8a; } html, body { background: var(--sy-bg) !important; color: var(--sy-ink) !important; font-family: Mulish, system-ui, sans-serif !important; } body * { font-family: inherit; } diff --git a/portail/resources/views/confidentialite.blade.php b/portail/resources/views/confidentialite.blade.php index 5981518..b7091c5 100644 --- a/portail/resources/views/confidentialite.blade.php +++ b/portail/resources/views/confidentialite.blade.php @@ -31,7 +31,7 @@

Qui est responsable

-

Syllabus est édité par Esquisse Formation (voir les mentions légales).

+

Syllabus est édité par Adam Belkacemi, entrepreneur individuel (EI), sous le nom commercial Esquisse Formation (voir les mentions légales).

Quand un établissement utilise Syllabus avec ses élèves, l’établissement est responsable du traitement et Esquisse Formation agit comme sous-traitant, sur ses instructions. Pour les comptes enseignants, Esquisse Formation est responsable du traitement.

Délégué à la protection des données : [à compléter si désigné]. Contact : adam@belkacemi.me

diff --git a/portail/resources/views/ide.blade.php b/portail/resources/views/ide.blade.php index f864b7b..d416e3b 100644 --- a/portail/resources/views/ide.blade.php +++ b/portail/resources/views/ide.blade.php @@ -117,7 +117,7 @@
Clique sur ▶ Exécuter pour lancer ton code.
- +
@@ -217,17 +217,23 @@ afficher([['Requête valide', true], ['Bonnes lignes, dans le bon ordre', obtenu === attendu]]); }); if (cur.lang === 'web') { - var f = $('p-apercu'); f.srcdoc = code; onglet('apercu'); - return new Promise(function (ok) { f.onload = function () { - var d = f.contentDocument, b = d && d.getElementById('bouton'), m = d && d.getElementById('message'); - var r = [['Le bouton #bouton existe',.b], ['Le paragraphe #message existe',.m]]; - if (b && m) { b.click(); r.push(['Le clic affiche « Bonjour ! »', /Bonjour/.test(m.textContent)]); } - afficher(r); ok(); - }; }); + // La vérification tourne DANS l'aperçu, isolé (sandbox sans + // allow-same-origin : le code de l'élève ne peut pas agir sur + // la page) ; elle renvoie ses résultats par postMessage. + var f = $('p-apercu'); onglet('apercu'); + var verif = '#s', $this->get('/'.ltrim($route->uri(), '/'))->getContent(), $scripts); + foreach ($scripts[1] as $i => $code) { + $fichier = tempnam(sys_get_temp_dir(), 'js').'.js'; + file_put_contents($fichier, $code); + $resultat = Process::run(['node', '--check', $fichier]); + unlink($fichier); + if ($resultat->failed()) { + $erreurs[] = "/{$route->uri()} script {$i} : ".strtok($resultat->errorOutput(), "\n"); + } + } + } + + expect($erreurs)->toBe([]); +}); diff --git a/portail/vite.config.js b/portail/vite.config.js index d881696..726b66a 100644 --- a/portail/vite.config.js +++ b/portail/vite.config.js @@ -21,6 +21,10 @@ export default defineConfig({ bunny('IBM Plex Mono', { weights: [400, 600], }), + // Police principale du thème (public/css/syllabus-theme.css). + bunny('Mulish', { + weights: [400, 500, 600, 700, 800], + }), ], }), tailwindcss(),