Commit Graph
6 Commits
Author SHA1 Message Date
bruno 16f73fe39e feat: Add plugins — catalogue on/off à effet réel (v7.58.0, phase 8/8)
FlowDeck CI / lint (push) Successful in 2m14s
FlowDeck CI / docker (push) Canceled after 0s
FlowDeck CI / test (push) Canceled after 2h7m52s
- app/services/plugins.py + migration 35 : table plugins (slug, name,
  description, enabled) pré-remplie avec 3 modules câblés — web-tools,
  web-clipper, automations ; ligne absente = activé (défaut sûr)
- automations OFF → dépendance FastAPI posée à l'include_router dans main.py
  (aucun router touché) → toutes les routes /workspace/automations* refusées +
  garde de tick du scheduler en arrière-plan
- web-clipper OFF → GET /extensions et tout /api/v2/web-clipper/* refusés
- web-tools OFF → web_search et fetch_url retirés du schéma ET de execute()
  via ToolRegistry._all() : le LLM ne les voit plus
- UI rendue côté serveur : global Jinja plugin_enabled(slug) — nav
  « Extensions » / « Automations » en {% if %} (absentes du DOM), sections
  conditionnées en x-show dans settings.html
- menu + : l'entrée « Add plugins » devient vivante (fini disabled:true) —
  liste des 3 plugins avec bascule, GET/PATCH /api/agent/plugins[/slug]
  (slug inconnu → 404, 401 sans session)
- tests : tests/test_v758_plugins.py (10 tests) — routes refusées (302 hors
  /api, 404 JSON pour /api*), outils retirés, nav disparue, persistance,
  câblage ; assertions disabled:true == 0 dans les tests des phases 1/3/4/5/7
- livraison : VERSION + app/main = 7.58.0, OpenAPI 525 chemins, CHANGELOG,
  ROADMAP phase 8 cochée (menu + complet), avenant phase 8 (docs)
2026-10-07 10:19:25 -04:00
bruno 1d1cdbd618 fix: side peek des bases repasse en vanilla JS + largeur 1100px standard (v7.49.0)
FlowDeck CI / test (push) Failing after 3h13m58s
FlowDeck CI / lint (push) Successful in 2m12s
FlowDeck CI / docker (push) Skipped
- Panneau peek: les bindings Alpine (x-data absent du conteneur) rendaient
  loovverture et le redimensionnement inoperants -> cblage direct sur le document.
- Helper unique window.fdWirePeekResize (app.js): pointer capture, 300px-90vw,
  clic=fermer, largeur persiste fd_peek_width partagee entre les 4 peeks.
- database-table-container margin:0 (tableau colle a gauche, marge Library).
- .lib-container remonte dans app.css (trash etait pleine largeur), .db-index 1100px.
- ObsiGate verifie sans code: creation .xlsx OK (openpyxl, #186).
2026-10-05 22:47:36 -04:00
bruno 770fdc2b68 fix: A43 TERMINÉ + A38 phase 1 — CSRF rendu côté serveur, helper unique (v7.33.0)
FlowDeck CI / lint (push) Successful in 1m57s
FlowDeck CI / test (push) Successful in 15m20s
FlowDeck CI / docker (push) Canceled after 0s
A43 (les 4 items sont clos) :
- `__CSRF_PLACEHOLDER__` supprimé : ContextVar CSRF_TOKEN posée par
  CSRFMiddleware avant call_next (même mécanique que le nonce CSP),
  global `{{ csrf_token() }}` dans templating, base.html rend
  `{"X-CSRF-Token":{{ csrf_token()|tojson }}}` — vide si cookie absent,
  `htmx:configRequest` re-lit le cookie à chaque appel → plus jamais de
  jeton factice servi.
- Palette : `fetch('/api/search…')` SANS header (GET ∈ SAFE_METHODS →
  CSRF inapplicable) — le JSON.parse du body-attr par frappe disparaît.
- utcnow déprécié = 0 dans app/**.py ; health loggé (A25) + booléens db/
  gitea = raison ; probe réseau = voulu (test de connectivité).

A38 phase 1 (CSRF unifié) :
- `window.getCsrf()` unique dans le <head> de base.html.
- 76 lectures brutes du cookie → getCsrf() dans 13 fichiers (47 formes
  `(…||[])[1]||''`, 25 déclarations `const X = match(…)` avec conversion
  de leurs usages `X?X[1]:''` → `X` (noms collectés PAR FICHIER, jamais
  de règle globale), 4 formes espacées).
- Définitions dupliquées supprimées : card_detail.html (multi-lignes),
  database_table.js (1 ligne dans IIFE → chute sur le global).
- Les 3 variantes de base.html (IIFE getCsrf + 2 getCsrfToken) →
  `return getCsrf()`.
- welcome.html garde sa lecture locale (page autonome sans base) ;
  reste exactement 1 raw dans base.html (la déf head) + 2 dans welcome.

Test : test_csrf_server_rendered_no_placeholder (pas de placeholder +
token du hx-headers == cookie csrf_token).

suite **1092/1092** · ruff OK · node --check vert · docs à jour
2026-10-02 08:45:27 -04:00
bruno c718fe06de fix: A20 (partiel) — CSP nonce par requête, unsafe-inline sort de script-src (v7.7.0)
FlowDeck CI / lint (push) Canceled after 0s
FlowDeck CI / test (push) Canceled after 0s
FlowDeck CI / docker (push) Canceled after 0s
- ContentSecurityPolicyMiddleware : nonce aléatoire par requête dans la
  ContextVar `CSP_NONCE` (posée avant `call_next` → visible des templates),
  `script-src 'self' 'unsafe-eval' 'nonce-…'` — plus aucun script inline
  sans nonce ne tourne (fin des XSS injectés en JS)
- 38 tags `<script>` des templates : `nonce="{{ csp_nonce() }}"` (passage
  scripté, vérifié : 0 restant) ; `LOCAL_LOGIN_HTML` (constante de module) :
  helper `_with_nonce()` au rendu ; collections.py : 3 scripts Python
  (chart/form/map) noncés
- `<meta name="htmx-config" content='{"inlineScriptNonce": …}'>` dans base.html
  : htmx ré-injecte les <script> des réponses boostées avec le bon nonce
- `script-src-attr 'unsafe-inline'` : les 74 handlers `onclick=` inline
  restent couverts (le nonce les aurait désactivés aussi)
- chart.js (cdn.jsdelivr.net) et leaflet (unpkg) ajoutés à script-src/style-src
  : vues chart/map déjà BLOQUÉES par la CSP depuis toujours
  (commentaire ponytail: upgrade = vendoriser puis retirer les hôtes)
- reste d'A20 : unsafe-eval (Alpine x-data → @alpinejs/csp), externalisation
  JS (A27), resserrer img-src/connect-src

test : test_csp_nonce_per_request (page base.html + page hors template,
nonce unique par requête)

suite **1037/1037** · `ruff check app tests` OK · docs à jour
2026-10-01 10:41:39 -04:00
bruno 937ecfc2e0 fix: A30 + A37 + A39 + A40 + A41 — fin du P2/P3 XS/S (v7.4.0)
FlowDeck CI / lint (push) Canceled after 0s
FlowDeck CI / test (push) Canceled after 0s
FlowDeck CI / docker (push) Canceled after 0s
- A30 — `require_scope()` câblé : 69 sites stricts de api_v2.py passent par la
  factory (Bearer + scope en 1 appel, contrôle manuel supprimé) ; sémantique
  alignée sur celle des handlers (pas de default "read" → 0 changement de
  comportement) ; 12 top-level morts supprimés (0 ref app ET tests) :
  unsync_block, find_referring, _b64url, strip_markdown, format_number,
  get_auto_property_value, get_next_unique_id, local_date_in_tz,
  verify_device_token, _get_dynamic_groups, _require_user_gitea,
  validate_upload_request
- A37 — CORS sans `*` : origines = app_base_url + allow_origin_regex
  (localhost/dev, origines d'extension pour le Web Clipper), méthodes et
  entêtes minutées, allow_credentials explicite + test test_cors_no_star
- A39 — htmx : décision « rien » documentée (32 attributs hx-* réels sur 6
  templates, conversion = refonte du view-switching sans test E2E)
- A40 — version d'assets à source unique : ENV.globals["asset_version"] lu au
  boot depuis le fichier VERSION ; littéraux `?v=` de base.html éliminés ;
  test test_asset_version_single_source
- A41 — app.css : 91 règles mortes purgées (-10 274 octets, 121 618 → 111 344),
  scan templates/JS/CSS/Python à 0 référence

suite **1031/1031** · `ruff check app tests` OK · OpenAPI 511 chemins / 7.4.0
docs (ROADMAP/CHANGELOG/WORKLOAD/VERSION) à jour
2026-10-01 09:30:37 -04:00
bruno 69a0aceba6 fix: A10 — autoescape Jinja2 activé partout via un Environment partagé
FlowDeck CI / docker (push) Successful in 1m44s
FlowDeck CI / lint (push) Successful in 1m49s
FlowDeck CI / test (push) Successful in 21m54s
- `app/templating.py` : `ENV = Environment(loader=FileSystemLoader("app/templates"), autoescape=select_autoescape(["html"]))`
- les 29 instantiations `Environment(loader=FileSystemLoader("app/templates"))` (9 routers) remplacées par `env = ENV` — plus aucune interpolation `{{ … }}` servie crue, les `|safe` redeviennent efficaces
- re-tri des `|safe` : `card_detail.html` corps d'issue et commentaires échappés (XSS stocké), placeholder de description sorti du ternaire, `sidebar_config` passé en dict + `|tojson` (échappement `</script>` en contexte script)
- `|safe` conservé sur `right_actions` (HTML fabriqué dans les templates, fiable)
- `ruff check app tests` OK · suite **1016/1016 verts**
2026-09-30 22:28:48 -04:00