Sprint 5 : integration et production -- securite, performance, API publique, documentation

Backend: rate limiter, security headers, blockchain cache service avec RPC,
public API (7 endpoints read-only), WebSocket auth + heartbeat, DB connection
pooling, structured logging, health check DB. Frontend: API retry/timeout,
WebSocket auth + heartbeat + typed events, notifications toast, mobile hamburger
+ drawer, error boundary, offline banner, loading skeletons, dashboard enrichi.
Documentation: guides utilisateur complets (demarrage, vote, sanctuaire, FAQ 30+),
guide deploiement, politique securite. 123 tests, 155 fichiers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-02-28 15:12:50 +01:00
parent 3cb1754592
commit 403b94fa2c
31 changed files with 4472 additions and 356 deletions

View File

@@ -5,13 +5,61 @@ description: Architecture, API et reference technique de Glibredecision
# Documentation technique
Bienvenue dans la documentation technique de Glibredecision.
Bienvenue dans la documentation technique de Glibredecision, la plateforme de decisions collectives pour la communaute Duniter/G1.
## Presentation
Glibredecision est une plateforme de gouvernance decentralisee qui permet aux membres de la Toile de Confiance (WoT) Duniter V2 de gerer des documents de reference modulaires sous vote permanent, prendre des decisions collectives multi-etapes, attribuer des mandats et archiver de maniere immuable les resultats via IPFS et la blockchain Duniter.
## Stack technique
| Couche | Technologie |
| ------------ | -------------------------------------------------- |
| Frontend | Nuxt 4 + Nuxt UI v3 + Pinia + UnoCSS |
| Backend | Python FastAPI + SQLAlchemy 2.0 (async) + Pydantic v2 |
| Base de donnees | PostgreSQL 16 (asyncpg) |
| Authentification | Duniter V2 Ed25519 challenge-response |
| Sanctuaire | IPFS (kubo) + hash on-chain (system.remark) |
| CI/CD | Woodpecker CI + Docker + Traefik |
| Temps reel | WebSocket pour les mises a jour de vote en direct |
## Historique des sprints
| Sprint | Contenu principal | Statut |
| ------ | ----------------- | ------ |
| Sprint 1 | Architecture, modeles de base (documents, items, versions, identites, protocoles, formules), API documents et authentification | Termine |
| Sprint 2 | Sanctuaire (IPFS + on-chain), gestion complete des items (CRUD, reorder), verification d'integrite, archivage de documents | Termine |
| Sprint 3 | Systeme de vote complet (sessions, votes signes, seuil WoT, criteres Smith/TechComm), meta-gouvernance, simulateur de formules, WebSocket temps reel | Termine |
| Sprint 4 | Decisions multi-etapes (workflow, avancement, vote lie), mandats (candidature, election, assignation, revocation), vote nuance | Termine |
| Sprint 5 | Stabilisation, documentation complete, deploiement production, audit securite | En cours |
## Version et statut
- **Version** : 1.0.0-rc
- **Statut** : Release candidate -- Sprint 5 (documentation et stabilisation)
- **Depot** : [git.duniter.org/tools/glibredecision](https://git.duniter.org/tools/glibredecision)
## Sections
- [Architecture](/dev/architecture) -- Vue d'ensemble de l'architecture
- [Reference API](/dev/api-reference) -- Endpoints et schemas
- [Schema de base de donnees](/dev/database-schema) -- Tables et relations
- [Formules](/dev/formulas) -- Formules mathematiques de seuil
- [Integration blockchain](/dev/blockchain-integration) -- Duniter V2, IPFS, on-chain
- [Contribution](/dev/contributing) -- Guide de contribution
### Architecture et conception
- [Architecture](/dev/architecture) -- Vue d'ensemble de l'architecture, stack, flux de communication
### Reference technique
- [Reference API](/dev/api-reference) -- Tous les endpoints REST et WebSocket avec schemas
- [Schema de base de donnees](/dev/database-schema) -- Tables, colonnes, relations et diagramme
### Domaines fonctionnels
- [Formules](/dev/formulas) -- Formules mathematiques de seuil WoT, criteres Smith/TechComm, simulateur, meta-gouvernance
- [Integration blockchain](/dev/blockchain-integration) -- Duniter V2 RPC, IPFS, ancrage on-chain
### Operations
- [Deploiement](/dev/deployment) -- Docker, Traefik, migrations, sauvegarde, mise a jour, troubleshooting
- [Securite](/dev/security) -- Authentification, integrite des votes, rate limiting, en-tetes, audit
### Contribution
- [Guide de contribution](/dev/contributing) -- Installation locale, conventions, tests, processus de contribution

View File

@@ -0,0 +1,405 @@
---
title: Deploiement
description: Guide de deploiement en production de Glibredecision
---
# Deploiement
Ce guide couvre le deploiement complet de Glibredecision en production avec Docker, Traefik, PostgreSQL et IPFS.
## Prerequis
| Composant | Version minimale | Description |
| --------- | ---------------- | ----------- |
| Docker | 24+ | Moteur de conteneurs |
| Docker Compose | 2.20+ | Orchestration multi-conteneurs |
| Nom de domaine | -- | Domaine pointe vers le serveur (ex: `glibredecision.org`) |
| Certificat TLS | -- | Genere automatiquement par Traefik via Let's Encrypt |
| Traefik | 2.10+ | Reverse proxy avec terminaison TLS (reseau externe `traefik`) |
| Serveur | 2 vCPU, 4 Go RAM, 40 Go SSD | Ressources recommandees |
### Reseau Traefik
Le deploiement suppose qu'un reseau Docker externe `traefik` existe deja avec une instance Traefik configuree. Si ce n'est pas le cas, creez-le :
```bash
docker network create traefik
```
Et deployez Traefik separement (voir section [Configuration Traefik](#configuration-traefik)).
## Configuration .env
Copiez le fichier `.env.example` et configurez chaque variable pour la production :
```bash
cp .env.example .env
```
### Variables d'environnement
| Variable | Description | Valeur par defaut | Production |
| -------- | ----------- | ----------------- | ---------- |
| `POSTGRES_DB` | Nom de la base de donnees | `glibredecision` | `glibredecision` |
| `POSTGRES_USER` | Utilisateur PostgreSQL | `glibredecision` | `glibredecision` |
| `POSTGRES_PASSWORD` | Mot de passe PostgreSQL | `change-me-in-production` | **Generer un mot de passe fort** (32+ caracteres) |
| `DATABASE_URL` | URL de connexion asyncpg | `postgresql+asyncpg://...@localhost:5432/...` | Construite automatiquement dans docker-compose |
| `SECRET_KEY` | Cle secrete pour les tokens de session | `change-me-in-production-with-a-real-secret-key` | **Generer une cle aleatoire** (`openssl rand -hex 64`) |
| `DEBUG` | Mode debug | `true` | **`false`** |
| `CORS_ORIGINS` | Origines CORS autorisees | `["http://localhost:3002"]` | `["https://glibredecision.org"]` |
| `DUNITER_RPC_URL` | URL du noeud Duniter V2 RPC | `wss://gdev.p2p.legal/ws` | URL du noeud de production |
| `IPFS_API_URL` | URL de l'API IPFS (kubo) | `http://localhost:5001` | `http://ipfs:5001` (interne Docker) |
| `IPFS_GATEWAY_URL` | URL de la passerelle IPFS | `http://localhost:8080` | `http://ipfs:8080` (interne Docker) |
| `NUXT_PUBLIC_API_BASE` | URL publique de l'API pour le frontend | `http://localhost:8002/api/v1` | `https://glibredecision.org/api/v1` |
| `DOMAIN` | Nom de domaine | `glibredecision.org` | Votre domaine |
### Generer les secrets
```bash
# Generer POSTGRES_PASSWORD
openssl rand -hex 32
# Generer SECRET_KEY
openssl rand -hex 64
```
::callout{type="warning"}
Ne commitez jamais le fichier `.env` contenant les secrets de production. Ajoutez-le au `.gitignore`.
::
## Lancement avec docker-compose
### Premier deploiement
```bash
# Se placer dans le repertoire du projet
cd /opt/glibredecision
# Cloner le depot
git clone https://git.duniter.org/tools/glibredecision.git .
# Configurer l'environnement
cp .env.example .env
# Editer .env avec les valeurs de production
# Construire et demarrer les services
docker compose -f docker/docker-compose.yml up -d --build
# Verifier que tous les services sont sains
docker compose -f docker/docker-compose.yml ps
```
### Services deployes
| Service | Description | Port interne | Expose |
| ------- | ----------- | ------------ | ------ |
| `postgres` | Base de donnees PostgreSQL 16 | 5432 | Non (interne uniquement) |
| `backend` | API FastAPI | 8002 | Via Traefik (`/api/*`) |
| `frontend` | Application Nuxt 4 | 3000 | Via Traefik (racine) |
| `ipfs` | Noeud IPFS kubo | 5001, 8080 | Non (interne uniquement) |
### Verifier le deploiement
```bash
# Statut des conteneurs
docker compose -f docker/docker-compose.yml ps
# Logs d'un service specifique
docker compose -f docker/docker-compose.yml logs -f backend
# Health check de l'API
curl -s https://glibredecision.org/api/health | jq .
```
## Migration de base de donnees (Alembic)
Glibredecision utilise Alembic pour les migrations de schema PostgreSQL.
### Appliquer les migrations
```bash
# Executer les migrations dans le conteneur backend
docker compose -f docker/docker-compose.yml exec backend alembic upgrade head
```
### Verifier l'etat des migrations
```bash
docker compose -f docker/docker-compose.yml exec backend alembic current
```
### Creer une nouvelle migration
```bash
# En developpement uniquement
docker compose -f docker/docker-compose.yml exec backend alembic revision --autogenerate -m "description de la migration"
```
### Rollback d'une migration
```bash
# Revenir d'une migration
docker compose -f docker/docker-compose.yml exec backend alembic downgrade -1
```
## Seed des donnees initiales
Apres la premiere migration, vous pouvez charger les donnees de seed (documents de reference initiaux) :
```bash
# Executer le script de seed dans le conteneur backend
docker compose -f docker/docker-compose.yml exec backend python -m app.seed
```
Les donnees de seed incluent :
- La Licence G1 avec ses items
- L'Engagement Forgeron v2.0.0
- L'Engagement Comite Technique v2.0.0
- Le template de processus de Runtime Upgrade
- Les protocoles de vote par defaut avec leurs formules
## Configuration Traefik
### Configuration minimale Traefik
Si vous n'avez pas encore Traefik, voici une configuration minimale. Creez un fichier `docker-compose.traefik.yml` :
```yaml
version: "3.9"
services:
traefik:
image: traefik:v2.10
restart: unless-stopped
command:
- "--api.dashboard=false"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=traefik"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.email=admin@glibredecision.org"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "letsencrypt:/letsencrypt"
networks:
- traefik
volumes:
letsencrypt:
networks:
traefik:
external: true
```
```bash
docker compose -f docker-compose.traefik.yml up -d
```
### Routage
Le `docker-compose.yml` de Glibredecision configure automatiquement les labels Traefik :
- **Frontend** : `Host(glibredecision.org)` sur le port 3000
- **Backend** : `Host(glibredecision.org) && PathPrefix(/api)` sur le port 8002
- Les deux utilisent le certificat Let's Encrypt (`certresolver=letsencrypt`)
- Redirection HTTP vers HTTPS automatique
### Certificat TLS
Le certificat est genere automatiquement par Traefik via Let's Encrypt (challenge TLS-ALPN-01). Assurez-vous que :
1. Le domaine pointe vers l'adresse IP du serveur (enregistrement DNS A)
2. Les ports 80 et 443 sont ouverts dans le firewall
3. L'adresse email dans la configuration Traefik est valide
## Monitoring
### Health checks
Le service PostgreSQL dispose d'un health check integre (`pg_isready`). Le backend expose un endpoint de sante :
```bash
# Health check de l'API
curl -s https://glibredecision.org/api/health
# Reponse attendue : {"status": "healthy"}
```
### Logs
```bash
# Suivre les logs de tous les services
docker compose -f docker/docker-compose.yml logs -f
# Logs d'un service specifique
docker compose -f docker/docker-compose.yml logs -f backend
docker compose -f docker/docker-compose.yml logs -f frontend
docker compose -f docker/docker-compose.yml logs -f postgres
# Derniers 100 lignes
docker compose -f docker/docker-compose.yml logs --tail=100 backend
```
### Metriques
Surveillez les indicateurs suivants :
| Indicateur | Commande | Seuil d'alerte |
| ---------- | -------- | --------------- |
| CPU/RAM conteneurs | `docker stats` | > 80% RAM |
| Espace disque | `df -h` | > 85% |
| Connexions PostgreSQL | `docker exec postgres psql -U glibredecision -c "SELECT count(*) FROM pg_stat_activity;"` | > 80 |
| Taille base de donnees | `docker exec postgres psql -U glibredecision -c "SELECT pg_size_pretty(pg_database_size('glibredecision'));"` | Information |
| Statut IPFS | `docker exec ipfs ipfs id` | Erreur |
## Sauvegarde PostgreSQL
### Sauvegarde manuelle
```bash
# Dump complet de la base
docker compose -f docker/docker-compose.yml exec postgres \
pg_dump -U glibredecision -Fc glibredecision > backup_$(date +%Y%m%d_%H%M%S).dump
```
### Restauration
```bash
# Restaurer un dump
docker compose -f docker/docker-compose.yml exec -T postgres \
pg_restore -U glibredecision -d glibredecision --clean < backup_20260228_120000.dump
```
### Sauvegarde automatique (cron)
Ajoutez un crontab pour des sauvegardes quotidiennes :
```bash
# Editer le crontab
crontab -e
# Ajouter une sauvegarde quotidienne a 3h du matin
0 3 * * * cd /opt/glibredecision && docker compose -f docker/docker-compose.yml exec -T postgres pg_dump -U glibredecision -Fc glibredecision > /opt/backups/glibredecision_$(date +\%Y\%m\%d).dump && find /opt/backups -name "glibredecision_*.dump" -mtime +30 -delete
```
Cette commande :
1. Execute un dump quotidien a 3h du matin
2. Stocke les sauvegardes dans `/opt/backups/`
3. Supprime automatiquement les sauvegardes de plus de 30 jours
## Mise a jour
### Procedure standard
```bash
cd /opt/glibredecision
# 1. Tirer les dernieres images
docker compose -f docker/docker-compose.yml pull
# 2. Redemarrer les services avec les nouvelles images
docker compose -f docker/docker-compose.yml up -d --remove-orphans
# 3. Appliquer les migrations de base de donnees
docker compose -f docker/docker-compose.yml exec backend alembic upgrade head
# 4. Nettoyer les anciennes images
docker image prune -f
# 5. Verifier le deploiement
docker compose -f docker/docker-compose.yml ps
curl -s https://glibredecision.org/api/health
```
### Pipeline CI/CD (Woodpecker)
La pipeline Woodpecker CI automatise le deploiement lors d'un push sur `main` :
1. **test-backend** : execution des tests Python (`pytest`)
2. **test-frontend** : build du frontend Nuxt (`npm run build`)
3. **docker-backend** : construction et push de l'image Docker backend
4. **docker-frontend** : construction et push de l'image Docker frontend
5. **deploy** : connexion SSH au serveur, pull des nouvelles images, redemarrage
Les secrets CI sont configures dans l'interface Woodpecker :
| Secret | Description |
| ------ | ----------- |
| `docker_registry` | URL du registre Docker |
| `docker_username` | Identifiant du registre |
| `docker_password` | Mot de passe du registre |
| `deploy_host` | Adresse du serveur de production |
| `deploy_username` | Utilisateur SSH |
| `deploy_key` | Cle privee SSH |
## Troubleshooting
### Le backend ne demarre pas
**Symptome** : Le conteneur backend redemoarre en boucle.
```bash
# Verifier les logs
docker compose -f docker/docker-compose.yml logs backend
# Causes courantes :
# 1. DATABASE_URL incorrecte -> verifier .env
# 2. PostgreSQL pas encore pret -> verifier le health check
# 3. Migrations non appliquees -> executer alembic upgrade head
```
### Erreur de connexion a PostgreSQL
**Symptome** : `connection refused` ou `password authentication failed`.
```bash
# Verifier que PostgreSQL est sain
docker compose -f docker/docker-compose.yml exec postgres pg_isready
# Verifier les variables d'environnement
docker compose -f docker/docker-compose.yml exec backend env | grep DATABASE
# Reinitialiser le mot de passe si necessaire (attention : destructif)
docker compose -f docker/docker-compose.yml down -v # supprime les volumes
docker compose -f docker/docker-compose.yml up -d # recree avec le nouveau mot de passe
```
### Certificat TLS non genere
**Symptome** : Le site est inaccessible en HTTPS ou affiche un certificat invalide.
1. Verifier que le DNS A/AAAA pointe vers le serveur : `dig glibredecision.org`
2. Verifier que les ports 80 et 443 sont ouverts : `ss -tlnp | grep -E '80|443'`
3. Consulter les logs Traefik : `docker logs traefik 2>&1 | grep -i acme`
### IPFS ne repond pas
**Symptome** : Erreur lors de l'archivage dans le Sanctuaire.
```bash
# Verifier le statut du noeud IPFS
docker compose -f docker/docker-compose.yml exec ipfs ipfs id
# Verifier l'espace disque disponible
docker compose -f docker/docker-compose.yml exec ipfs df -h /data/ipfs
# Redemarrer le noeud IPFS
docker compose -f docker/docker-compose.yml restart ipfs
```
### Erreur WebSocket
**Symptome** : L'indicateur de connexion temps reel est rouge.
1. Verifier que Traefik supporte les WebSockets (actif par defaut)
2. Verifier le routage : le WebSocket est sur `/api/v1/ws`
3. Verifier les logs backend pour les erreurs de connexion WebSocket

View File

@@ -0,0 +1,278 @@
---
title: Securite
description: Politique de securite et mesures de protection de Glibredecision
---
# Securite
Ce document decrit les mesures de securite implementees dans Glibredecision pour proteger l'integrite de la plateforme, des votes et des donnees des utilisateurs.
## Authentification Duniter V2 (Ed25519 challenge-response)
### Principe
Glibredecision n'utilise ni mot de passe ni systeme d'inscription classique. L'authentification repose entierement sur la cryptographie Ed25519 de la blockchain Duniter V2.
### Flux challenge-response
```
Client Serveur
| |
|-- POST /auth/challenge ----------->|
| { address: "5Grw..." } |
| |-- Genere challenge (64 hex)
| |-- Stocke en memoire (TTL 5 min)
|<-------- { challenge: "a1b2..." } -|
| |
|-- Signe le challenge localement |
| (cle privee Ed25519) |
| |
|-- POST /auth/verify ------------->|
| { address, challenge, signature}|
| |-- Verifie signature Ed25519
| |-- Verifie identite WoT
| |-- Cree/retrouve DuniterIdentity
| |-- Genere token de session
|<-------- { token: "..." } --------|
```
### Garanties de securite
| Propriete | Mecanisme |
| --------- | --------- |
| **Cle privee jamais transmise** | Seule la signature est envoyee, pas la cle |
| **Anti-replay** | Chaque challenge est usage unique, expire apres 5 minutes |
| **Anti-interception** | HTTPS/TLS obligatoire en production |
| **Identite verifiee** | L'adresse SS58 est verifiee sur la blockchain via `substrate-interface` |
### Verification de la signature
```python
from substrateinterface import Keypair
keypair = Keypair(ss58_address=address)
is_valid = keypair.verify(challenge_bytes, signature_bytes)
```
La cle publique est derivee de l'adresse SS58 sans aucun appel reseau. La verification est locale et instantanee.
## Integrite des votes
### Signature cryptographique des votes
Chaque vote soumis est accompagne d'une **signature Ed25519** qui garantit son authenticite et son integrite.
### Payload signe
Le payload signe contient :
```json
{
"session_id": "uuid-de-la-session",
"vote_value": "for",
"timestamp": "2026-02-28T12:00:00Z"
}
```
Ce payload est signe par la cle privee du votant. La signature est stockee en base de donnees avec le vote, permettant une verification independante a tout moment.
### Proprietes garanties
| Propriete | Description |
| --------- | ----------- |
| **Authenticite** | Seul le proprietaire de l'adresse Duniter peut soumettre un vote en son nom |
| **Integrite** | Le payload ne peut pas etre modifie apres signature sans invalider la signature |
| **Non-repudiation** | Le votant ne peut pas nier avoir vote ; la preuve cryptographique est publique |
| **Transparence** | Les votes signes sont publics et verifiables par quiconque |
### Verification d'un vote
```python
from substrateinterface import Keypair
keypair = Keypair(ss58_address=voter_address)
is_valid = keypair.verify(signed_payload.encode(), signature_bytes)
```
### Protection contre la modification
Quand un votant modifie son vote, l'ancien vote est marque `is_active = false` mais conserve en base. Les deux votes (ancien et nouveau) conservent leur signature. L'historique complet est auditable.
## Rate limiting
### Limites par endpoint
Pour prevenir les abus et les attaques par deni de service, des limites de taux sont appliquees :
| Categorie | Endpoints | Limite | Fenetre |
| --------- | --------- | ------ | ------- |
| Authentification | `/auth/challenge`, `/auth/verify` | 10 requetes | 1 minute |
| Vote | `/votes/sessions/{id}/vote` | 5 requetes | 1 minute |
| Ecriture | `POST`, `PUT`, `DELETE` | 30 requetes | 1 minute |
| Lecture | `GET` | 200 requetes | 1 minute |
| WebSocket | `/ws` | 3 connexions | simultanees par IP |
### Reponse en cas de depassement
Le serveur retourne un code HTTP **429 Too Many Requests** avec un header `Retry-After` indiquant le temps d'attente en secondes.
## En-tetes de securite
Les en-tetes HTTP suivants sont configures en production :
| En-tete | Valeur | Description |
| ------- | ------ | ----------- |
| `Strict-Transport-Security` | `max-age=63072000; includeSubDomains; preload` | Force HTTPS pendant 2 ans, inclut les sous-domaines |
| `Content-Security-Policy` | `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' wss:; img-src 'self' data: https://ipfs.io` | Restreint les sources de contenu autorisees |
| `X-Content-Type-Options` | `nosniff` | Empeche le navigateur de deviner le type MIME |
| `X-Frame-Options` | `DENY` | Empeche l'inclusion dans un iframe (anti-clickjacking) |
| `X-XSS-Protection` | `1; mode=block` | Active la protection XSS du navigateur |
| `Referrer-Policy` | `strict-origin-when-cross-origin` | Limite les informations de referer |
| `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` | Desactive les APIs sensibles non necessaires |
### CSP detaillee
La Content Security Policy est configuree pour :
- Autoriser les scripts uniquement depuis l'origine (`'self'`)
- Autoriser les styles inline (necessaires pour UnoCSS)
- Autoriser les connexions WebSocket (`wss:`)
- Autoriser les images depuis IPFS gateway (`https://ipfs.io`) pour l'affichage des contenus archives
- Bloquer tout le reste
## Sanctuaire : triple preuve d'integrite
### Chaine de verification
```
Contenu --> [SHA-256] --> hash
|
+---> [IPFS] --> CID (content-addressable)
|
+---> [system.remark on-chain] --> preuve horodatee
|
v
Triple preuve :
1. Hash local = hash enregistre (integrite)
2. CID IPFS = contenu identique (distribution)
3. Remark on-chain = hash confirme (immutabilite temporelle)
```
### Garanties
| Preuve | Ce qu'elle garantit | Point de defaillance |
| ------ | ------------------- | -------------------- |
| SHA-256 | Le contenu n'a pas ete modifie | Aucun (mathematique) |
| IPFS CID | Le contenu est distribue et adressable par contenu | Disponibilite des noeuds IPFS |
| On-chain remark | Le hash existait a la date du bloc | Securite de la blockchain Duniter |
### Format du remark on-chain
```
glibredecision:sanctuary:{content_hash_sha256}
```
Le prefixe `glibredecision:sanctuary:` permet d'identifier les ancrages de Glibredecision parmi tous les remarks de la blockchain.
## WebSocket : authentification et securite
### Authentification par token
La connexion WebSocket est authentifiee via le token de session obtenu lors du challenge-response :
```
ws://server/api/v1/ws?token={session_token}
```
Le serveur verifie le token avant d'accepter la connexion. Les connexions non authentifiees sont rejetees.
### Protections WebSocket
| Protection | Description |
| ---------- | ----------- |
| Token valide requis | Pas de connexion anonyme |
| Limite de connexions | Maximum 3 connexions simultanees par IP |
| Heartbeat | Ping/pong periodique pour detecter les connexions mortes |
| Taille maximale des messages | Limite a 64 Ko pour prevenir les abus |
| Broadcast read-only | Les clients recoivent les mises a jour mais ne peuvent pas modifier l'etat via WebSocket |
## Session management
### Tokens de session
| Propriete | Valeur |
| --------- | ------ |
| Duree de vie (TTL) | 24 heures |
| Stockage serveur | Hash SHA-256 du token en base (table `sessions`) |
| Stockage client | Token en clair dans le `localStorage` du navigateur |
| Invalidation | Suppression de l'entree en base via `/auth/logout` |
### Securite des tokens
- Le token est genere avec un generateur cryptographiquement sur (CSPRNG)
- Seul le **hash** du token est stocke en base de donnees. Si la base est compromise, les tokens bruts ne sont pas exposes.
- A chaque requete authentifiee, le token fourni est hashe et compare au hash en base
- Les tokens expires sont nettoyes periodiquement
### Deconnexion
L'appel a `POST /auth/logout` invalide la session cote serveur en supprimant l'entree de la table `sessions`. Le client supprime le token de son `localStorage`.
## Audit logging
### Evenements traces
Les actions suivantes sont enregistrees pour auditabilite :
| Evenement | Donnees enregistrees |
| --------- | -------------------- |
| Authentification reussie | Adresse SS58, timestamp, IP |
| Authentification echouee | Adresse SS58, raison, timestamp, IP |
| Vote soumis | Session ID, voter ID, vote, signature, timestamp |
| Vote modifie | Session ID, voter ID, ancien vote (desactive), nouveau vote |
| Decision creee/avancee | Decision ID, auteur, action, timestamp |
| Document archive | Document ID, hash, CID, tx_hash |
| Session de vote cloturee | Session ID, resultat, seuils |
| Mandat assigne/revoque | Mandate ID, mandataire, action |
### Conservation
Les logs d'audit sont conserves de maniere permanente dans la base de donnees. Les votes et leurs signatures sont particulierement importants car ils constituent la preuve cryptographique des decisions collectives.
## Signalement de vulnerabilite (Responsible disclosure)
### Processus
Si vous decouvrez une vulnerabilite de securite dans Glibredecision, merci de suivre cette procedure de divulgation responsable :
1. **Ne divulguez pas publiquement** la vulnerabilite avant qu'un correctif soit disponible.
2. **Contactez l'equipe** via le canal securise indique sur le depot Git Duniter ou via le forum Duniter (message prive aux mainteneurs).
3. **Decrivez la vulnerabilite** avec autant de details que possible :
- Type de vulnerabilite (injection, XSS, CSRF, contournement d'authentification, etc.)
- Etapes pour reproduire
- Impact potentiel
- Suggestion de correctif (si applicable)
4. **Delai de correction** : l'equipe s'engage a accuser reception sous 48 heures et a fournir un correctif sous 14 jours pour les vulnerabilites critiques.
5. **Credit** : les chercheurs en securite qui signalent des vulnerabilites de maniere responsable seront credites dans le changelog (sauf s'ils preferent l'anonymat).
### Perimetre
Le perimetre de la politique de securite couvre :
| Inclus | Exclus |
| ------ | ------ |
| API backend (FastAPI) | Infrastructure d'hebergement tiers |
| Frontend (Nuxt 4) | Blockchain Duniter V2 elle-meme |
| Authentification challenge-response | Extension Polkadot.js |
| Integrite des votes et signatures | Noeud IPFS (kubo) lui-meme |
| WebSocket | Traefik |
| Base de donnees (acces, injection) | -- |
### Exclusions
Les types de signalement suivants sont hors perimetre :
- Deni de service par volume (DDoS)
- Ingenierie sociale
- Attaques physiques sur l'infrastructure
- Vulnerabilites dans les dependances tierces deja connues et trackees (utiliser les issues du depot)