Fusion #69 (chantier 2) — Alertes unifiées, côté ObsiGate.
Audit (vérifié sur main, pas supposé)
ObsiGate n'expose AUCUNE notification entrante consultable par l'utilisateur : ses /api/notify/* (router backend/routers/notify.py) sont des canaux d'envoi sortants (discord/telegram/smtp/webhook, CRUD réservé aux administrateurs, secrets masqués *** + has_secret). Il n'existe ni table ni endpoint de journal de notifications entrantes. La section ObsiGate du panneau le dit honnêtement et renvoie vers l'accueil d'ObsiGate — aucune alerte inventée, aucun faux lien vers un élément.
Les autres sources (même audit que les autres PR du chantier) : Flowdeck GET /api/notifications (non lues = actives), TikTak GET /api/notifications (non lues = actives ; lien /?task={id}), Kanbante GET /api/events (aucun état lu/non lu → tout historique, jamais compté actif).
Verrou constaté côté ObsiGate comme visualiseur : sa CSP connect-src ne nommait que self/CDN/agent → la lecture des API sœurs depuis og(-dev) était bloquée. ObsiGate n'a pas besoin de CORS (aucune API source à exposer).
Ce qui change (cette PR ObsiGate)
frontend/draco-alertes.js (nouveau, module partagé, pas un fichier ui/barre-apps.*) + frontend/draco-alertes.css : panneau Alertes (actives d'abord, puis historique, par application, origine/titre/date/état/lien profond ; textContent uniquement). Pastille via DRACO_BAR.setCounts({alertes: n}). Bases résolues dans l'ordre barre v0.1.6 : config explicite > hôte -dev dérivé > href rendu (window.DRACO_URLS injecté par le backend) > défaut prod.
frontend/index.html : branche alertes → DRACO_ALERTES.open() (repli : message honnête « module non chargé », jamais le placeholder) ; le toast « Alertes unifiées : arrive avec la fédération » DISPARAÎT ; chargement du module et de son CSS (servis /static/draco-alertes.* via le montage FRONTEND_DIR existant).
backend/main.py (SecurityHeadersMiddleware) : CSP connect-src += origines sœurs résolues par draco_config.urls_publiques() (explicite > dérivation depuis l'hôte de l'agent > défaut officiel).
Test : tests/frontend/draco-alertes.test.mjs (4 tests Node, patron des tests frontend existants).
Limites, dites honnêtement
Agrégation À LA DEMANDE, pas une fédération temps réel (relecture à l'ouverture + au chargement pour la pastille).
Vue unifiée complète seulement quand les 4 PR du chantier sont déployées ; sinon la section manquante affiche « Connexion requise » ou « injoignable » avec son lien natif, jamais de faux contenu.
Pastille = Flowdeck non lues + TikTak non lues uniquement. ObsiGate ne contribue ni actives ni historique (aucune source) — c'est un constat d'audit, pas un oubli.
Aucun bump de version, aucun merge, aucune fermeture d'issue dans cette PR (coordinateur).
Vérification isolée de la dérivation CSP (backend/draco_config.py, sans dépendances lourdes) : origines prod exactes flowdeck, kanbante, og, tiktak .dracodev.net.
python3 -m py_compile backend/main.py : OK ; node --check frontend/draco-alertes.js : OK.
Non fait ici (delta explicite) : la suite pytest ObsiGate n'a pas pu tourner dans la sandbox — l'import de backend.main exige la cascade complète de dépendances du backend (frontmatter, snowballstemmer, …) ; à lancer par la CI / le coordinateur. Le rendu authentifié complet et la pastille inter-apps en conditions réelles restent à valider par Bruno après déploiement des 4 PR.
Rebase de la PR #39 sur main post-#70 (conflit frontend/index.html résolu : suppression du bouton ••• et du relais menu de #70 conservées — le bouton natif #header-menu-btn d'ObsiGate reste inchangé —, ajouts #69 appliqués : CSS/JS draco-alertes, handler alertes, CSP connect-src sœurs. Contenu par ailleurs identique à #39.
Fusion #69 (chantier 2) — Alertes unifiées, côté ObsiGate.
## Audit (vérifié sur main, pas supposé)
- ObsiGate n'expose AUCUNE notification entrante consultable par l'utilisateur : ses `/api/notify/*` (router `backend/routers/notify.py`) sont des canaux d'envoi sortants (discord/telegram/smtp/webhook, CRUD réservé aux administrateurs, secrets masqués `***` + `has_secret`). Il n'existe ni table ni endpoint de journal de notifications entrantes. La section ObsiGate du panneau le dit honnêtement et renvoie vers l'accueil d'ObsiGate — aucune alerte inventée, aucun faux lien vers un élément.
- Les autres sources (même audit que les autres PR du chantier) : Flowdeck `GET /api/notifications` (non lues = actives), TikTak `GET /api/notifications` (non lues = actives ; lien `/?task={id}`), Kanbante `GET /api/events` (aucun état lu/non lu → tout historique, jamais compté actif).
- Verrou constaté côté ObsiGate comme visualiseur : sa CSP `connect-src` ne nommait que self/CDN/agent → la lecture des API sœurs depuis og(-dev) était bloquée. ObsiGate n'a pas besoin de CORS (aucune API source à exposer).
## Ce qui change (cette PR ObsiGate)
- `frontend/draco-alertes.js` (nouveau, module partagé, pas un fichier `ui/barre-apps.*`) + `frontend/draco-alertes.css` : panneau Alertes (actives d'abord, puis historique, par application, origine/titre/date/état/lien profond ; `textContent` uniquement). Pastille via `DRACO_BAR.setCounts({alertes: n})`. Bases résolues dans l'ordre barre v0.1.6 : config explicite > hôte -dev dérivé > href rendu (`window.DRACO_URLS` injecté par le backend) > défaut prod.
- `frontend/index.html` : branche `alertes` → `DRACO_ALERTES.open()` (repli : message honnête « module non chargé », jamais le placeholder) ; le toast « Alertes unifiées : arrive avec la fédération » DISPARAÎT ; chargement du module et de son CSS (servis `/static/draco-alertes.*` via le montage `FRONTEND_DIR` existant).
- `backend/main.py` (`SecurityHeadersMiddleware`) : CSP `connect-src` += origines sœurs résolues par `draco_config.urls_publiques()` (explicite > dérivation depuis l'hôte de l'agent > défaut officiel).
- Test : `tests/frontend/draco-alertes.test.mjs` (4 tests Node, patron des tests frontend existants).
## Limites, dites honnêtement
- Agrégation À LA DEMANDE, pas une fédération temps réel (relecture à l'ouverture + au chargement pour la pastille).
- Vue unifiée complète seulement quand les 4 PR du chantier sont déployées ; sinon la section manquante affiche « Connexion requise » ou « injoignable » avec son lien natif, jamais de faux contenu.
- Pastille = Flowdeck non lues + TikTak non lues uniquement. ObsiGate ne contribue ni actives ni historique (aucune source) — c'est un constat d'audit, pas un oubli.
- Aucun bump de version, aucun merge, aucune fermeture d'issue dans cette PR (coordinateur).
## Tests (chiffres réels, sandbox)
- `node tests/frontend/draco-alertes.test.mjs` : 4 passed (logique du module + gabarit livré).
- Vérification isolée de la dérivation CSP (`backend/draco_config.py`, sans dépendances lourdes) : origines prod exactes `flowdeck, kanbante, og, tiktak .dracodev.net`.
- `python3 -m py_compile backend/main.py` : OK ; `node --check frontend/draco-alertes.js` : OK.
- Non fait ici (delta explicite) : la suite pytest ObsiGate n'a pas pu tourner dans la sandbox — l'import de `backend.main` exige la cascade complète de dépendances du backend (frontmatter, snowballstemmer, …) ; à lancer par la CI / le coordinateur. Le rendu authentifié complet et la pastille inter-apps en conditions réelles restent à valider par Bruno après déploiement des 4 PR.
---
Rebase de la PR #39 sur main post-#70 (conflit frontend/index.html résolu : suppression du bouton ••• et du relais menu de #70 conservées — le bouton natif #header-menu-btn d'ObsiGate reste inchangé —, ajouts #69 appliqués : CSS/JS draco-alertes, handler alertes, CSP connect-src sœurs. Contenu par ailleurs identique à #39.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fusion #69 (chantier 2) — Alertes unifiées, côté ObsiGate.
Audit (vérifié sur main, pas supposé)
/api/notify/*(routerbackend/routers/notify.py) sont des canaux d'envoi sortants (discord/telegram/smtp/webhook, CRUD réservé aux administrateurs, secrets masqués***+has_secret). Il n'existe ni table ni endpoint de journal de notifications entrantes. La section ObsiGate du panneau le dit honnêtement et renvoie vers l'accueil d'ObsiGate — aucune alerte inventée, aucun faux lien vers un élément.GET /api/notifications(non lues = actives), TikTakGET /api/notifications(non lues = actives ; lien/?task={id}), KanbanteGET /api/events(aucun état lu/non lu → tout historique, jamais compté actif).connect-srcne nommait que self/CDN/agent → la lecture des API sœurs depuis og(-dev) était bloquée. ObsiGate n'a pas besoin de CORS (aucune API source à exposer).Ce qui change (cette PR ObsiGate)
frontend/draco-alertes.js(nouveau, module partagé, pas un fichierui/barre-apps.*) +frontend/draco-alertes.css: panneau Alertes (actives d'abord, puis historique, par application, origine/titre/date/état/lien profond ;textContentuniquement). Pastille viaDRACO_BAR.setCounts({alertes: n}). Bases résolues dans l'ordre barre v0.1.6 : config explicite > hôte -dev dérivé > href rendu (window.DRACO_URLSinjecté par le backend) > défaut prod.frontend/index.html: branchealertes→DRACO_ALERTES.open()(repli : message honnête « module non chargé », jamais le placeholder) ; le toast « Alertes unifiées : arrive avec la fédération » DISPARAÎT ; chargement du module et de son CSS (servis/static/draco-alertes.*via le montageFRONTEND_DIRexistant).backend/main.py(SecurityHeadersMiddleware) : CSPconnect-src+= origines sœurs résolues pardraco_config.urls_publiques()(explicite > dérivation depuis l'hôte de l'agent > défaut officiel).tests/frontend/draco-alertes.test.mjs(4 tests Node, patron des tests frontend existants).Limites, dites honnêtement
Tests (chiffres réels, sandbox)
node tests/frontend/draco-alertes.test.mjs: 4 passed (logique du module + gabarit livré).backend/draco_config.py, sans dépendances lourdes) : origines prod exactesflowdeck, kanbante, og, tiktak .dracodev.net.python3 -m py_compile backend/main.py: OK ;node --check frontend/draco-alertes.js: OK.backend.mainexige la cascade complète de dépendances du backend (frontmatter, snowballstemmer, …) ; à lancer par la CI / le coordinateur. Le rendu authentifié complet et la pastille inter-apps en conditions réelles restent à valider par Bruno après déploiement des 4 PR.Rebase de la PR #39 sur main post-#70 (conflit frontend/index.html résolu : suppression du bouton ••• et du relais menu de #70 conservées — le bouton natif #header-menu-btn d'ObsiGate reste inchangé —, ajouts #69 appliqués : CSS/JS draco-alertes, handler alertes, CSP connect-src sœurs. Contenu par ailleurs identique à #39.