BUG-108 — closeContextMenu() retirait le nœud du menu AVANT de déférencer
_menu : le retrait émet focusout en synchrone (le menu tient le focus), qui
rappelle closeContextMenu() ; le second remove() sur un nœud démonté lève
NotFoundError et avorte le handler de l'action « Coller » du viewer — le
coller par menu contextuel était silencieusement mort (régression de la
fermeture au focus #179, reproduite par l'E2E « coller une plage », CI
#850→#854). Déférencement avant retrait.
Sécurité CI (job security, run #853) :
- plancher multidict>=6.9.1 (CVE-2026-104874 ; 6.7.x préinstallée dans la
toolcache de l'image du runner, même piège « already satisfied » que pypdf
BUG-093) + entrée dans le garde-fou TestDependencySecurityFloors ;
- exception documentée CVE-2026-85394 (python-jose, AUCUN correctif upstream) :
non atteignable ici, jwt.decode passe toujours algorithms=["HS256"] avec un
secret symétrique serveur — jamais de clé publique comme clé HMAC.
Vérifié : E2E -g « coller une plage » 1/1 ; xlsx-menus 11/11,
xlsx-formula 14/14, ai 100/100, ai-quick-actions 13/13 ; pytest 1586
passés ; ruff/mypy 0 erreur ; ISSUES_TODOLIST + CHANGELOG à jour.
- clic sur un repertoire de l'arbre (modes focus vault et All) ouvre un onglet de navigation dedie qui coexiste avec les onglets de fichiers ouverts
- vue: sous-repertoires cliquables, facettes Vaults/Tags/Extensions (meme mecanisme que la recherche), tris Pertinence/Date, bouton Sauver; tags indexes exposes par GET /api/vault/{v}/files
- BUG-100: showWelcome re-injecte la section Raccourcis & Astuces et goHome efface la recherche globale + le filtre de la sidebar
pip-audit bloquait sur PYSEC-2026-3910 (outlines) et PYSEC-2026-3911 (XForm),
toutes deux atteignables via backend/pdf_reader.py. Le plancher pypdf>=4.0 ne
protégeait rien : l'image Act du runner embarque 6.16.0 dans sa toolcache
Python, donc pip répondait « already satisfied » sans jamais aligner.
Au passage, le garde-fou TestSemgrepStep était en régression depuis la
désactivation de semgrep (v2.39.9) et aurait rougi le job `test` : il vérifie
désormais que l'étape n'exécute que son avertissement et que bandit et
pip-audit restent bloquants. Nouveau TestDependencySecurityFloors pour
verrouiller les planchers de sécurité (contre-preuve : pypdf remis à >=4.0).
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
L'édition d'un .xlsx pouvait détruire une partie du classeur, le
concurrencer en silence, ou diffuser une injection de formule.
- BUG-085 : inspect_workbook() détecte ce qu'un round-trip openpyxl perd
(valeurs calculées en cache, slicers, contrôles, connexions, custom
XML, signature, commentaires enrichis, macros) → xlsx_lossy_features
exposé en lecture, bandeau FR/EN, et 409 xlsx_lossy_content sans
`force` (confirmation explicite puis reprise). Périmètre réel
revalidé : graphiques, images et TCD survivent au round-trip.
- BUG-086 : écriture atomique (fichier .tmp + os.replace) : un plantage
ne peut plus tronquer le classeur, le backup reste intact.
- BUG-087 : verrou par fichier autour du read-modify-write (timeout 15 s,
409 conflict) ; endpoint xlsx/save devenu synchrone pour que
l'attente s'exécute dans le threadpool.
- BUG-088 : une saisie en '=' ou '@' est stockée en texte, sauf opt-in
`allow_formula` ou le bouton f(x) de la visionneuse. Le handler
ServiceError expose désormais code + details, que api() propage.
- BUG-084 : la suppression d'une vault purge enfin l'index inversé
(documents fantômes qui continuaient de matcher) et is_stale() devient
is_ready(), le nom étant trompeur (la staleness n'existe plus).
Tests : 1390 pytest, 10 JSDOM (xlsx-viewer.test.mjs, branché au CI),
3 E2E Playwright, suite E2E complète verte, ruff/mypy 0.
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
VERSION (racine) devient la source unique de verite MAJEUR.MINEUR.CORRECTIF, incrementee a chaque commit par le hook prepare-commit-msg (BREAKING -> majeur, feat -> mineur, sinon correctif) ; post-commit rattache les fichiers derives au commit et cree le tag vX.Y.Z, publie au push (push.followTags). Tous les derives sont resynchronises : package.json, desktop Tauri, README.md/README.fr.md, docs/ROADMAP.md, CHANGELOG.md. Backend, image Docker et desktop lisent le meme fichier (plus de numero code en dur). Outils : scripts/bump_version.py, scripts/install-hooks.sh. Tests : tests/test_version.py (46, garde-fou de coherence globale).
Le conteneur d'edition (#editor-container, CodeMirror ou iframe Forge) est deplace dans la zone de contenu du document (#content-area ou pane active) au lieu de l'overlay plein ecran : le mode edition remplace la vue lecture. L'overlay reste monte (transparent, pointer-events: none) car le ruban d'edition mobile y est ancre ; il ne sert plus que de repli quand la cible n'est pas le document affiche. Garde-fou dans renderFile() pour liberer proprement la session (destroy CodeMirror/Yjs, retrait de l'iframe Forge) ; forge-close passe par closeEditor() ; cache d'onglet invalide au retour en lecture.
Assistant IA : app_context.editing annonce le document en cours d'edition (frontend bookslm.js + backend bookslm.py), et chaque ecriture d'outil (edit_file, append_to_file, create_file, restore_backup) recharge le document affiche (obsigate:file-written) — tampon CodeMirror remplace avec auto-save neutralisee, parent-reload pour l'iframe Forge, re-rendu de la vue lecture sinon.
Tests : tests/frontend/editor-inline.test.mjs (19), tests/test_bookslm.py::TestGeneralPrompt (3 nouveaux). Fiche : docs/features/editeur-inline.md.
- Signature des mises a jour Tauri : paire de cles minisign generee, cle publique dans tauri.conf.json, createUpdaterArtifacts actif, secrets CI exposes (repli build non signe si secret absent).
- Wizard 1er lancement : etat persistant wizard_done cote Rust (get_wizard_state/complete_wizard) pour ne plus reafficher la banniere, retro-compatible.
- Protocole des 6 tests E2E manuels : docs/DESKTOP_E2E_CHECKLIST.md.
- CI : desktop.test.mjs ajoute au job lint.
- Docs : ROADMAP, fiche desktop-tauri, CHANGELOG, README desktop, guide releases.
- fix(build): retirer les libs WeasyPrint inutiles du stage builder Docker.
BUG-003: annotations de types, gardes None sur get_user(), PdfReader: Any et import PROVIDERS manquant (bug latent main.py:4523). Etape mypy du CI rendue bloquante (etait advisory).
BUG-004: lien README.md -> docs/CONTRIBUTING.md corrige (+ DELIVERY_WORKFLOW.md), arbre projet mis a jour, parite README.fr.md.
Verifie: mypy 0 erreur, ruff OK, pytest 728 passed / 5 skipped, frontend OK, liens md OK.
Les fixtures copiees via docker cp appartiennent a root ; l'app tourne en UID 1000 et os.access(W_OK) renvoyait False -> POST /api/file 403 'Vault is read-only' -> le test E2E de creation .excalidraw (C8) echouait. Ajout d'un chmod -R a+rwX apres le health check.
Le job 'CI / build' échouait avec :
failed to fetch anonymous token: dial tcp: lookup auth.docker.io on
127.0.0.11:53: server misbehaving
Le résolveur DNS embarqué du daemon Docker sur le runner GitHub Actions
est bogué de manière intermittente. Cette PR ajoute :
1. Étape 'Configure DNS' qui configure /etc/docker/daemon.json avec
les DNS publics Google/Cloudflare/Quad9 (8.8.8.8, 1.1.1.1, 9.9.9.9)
puis redémarre le daemon Docker
2. Retry jusqu'à 3 fois (10s, 20s d'attente) sur la commande
docker build pour absorber les flakes réseau ponctuels
Aucun changement au Dockerfile lui-même — il fonctionne en local
et le bug est purement infrastructure.
- ci.yml e2e : les bind mounts C:\dev\git\python\ObsiGate sont vides en docker-in-docker (chemin du job container inexistant sur l hote) -> docker create + docker cp des fixtures + docker start
- obsigate.spec.ts : placeholder de recherche attendu mis a jour (Rechercher dans toutes les vaults...)
- obsigate.spec.ts : theme par defaut accepte defaut-obsigate (moteur themes.js) en plus de dark (ui.js legacy)
- test_vault/ et test_dir/ : fixtures markdown pour les tests E2E Playwright (22 fichiers, .obsigate-backup ignore)
- ci.yml e2e : health check et BASE_URL via IP passerelle docker (localhost du job container ne voit pas le port publie sur l hote)
- ci.yml e2e : l etape Start ObsiGate echoue explicitement si l app n est pas joignable
- backend/VERSION est gitignore et genere par build.sh, mais le job build du CI ne le generait pas : docker build echouait avec /backend/VERSION: not found
fix(ci): job e2e - reparation de l etape Start ObsiGate (YAML imbrique casse, port 2029, nettoyage du container stale)