Chargement de la documentation…

veilforge. ← Accueil Swagger ↗

DOCUMENTATION

Tout ce qu'il faut pour
mettre Veilforge en route.

Cette page explique le fonctionnement de la passerelle, ses endpoints, son format de jetons et son modèle de sécurité. Elle complète la page d'accueil, qui contient une démonstration interactive, et le Swagger, qui décrit chaque route au format OpenAPI.

Version1.0.0
LicenceApache-2.0
Entrée/v1
Mode par défautStrict

01

Démarrage rapide

Veilforge est une application Python (FastAPI) qui s'exécute en local. Aucune base externe n'est nécessaire : les correspondances sont stockées dans un fichier SQLite chiffré à côté du projet.

1
Installer les dépendances

Python 3.11 ou plus récent est requis.

2
Préparer la configuration

Copiez .env.example vers .env et renseignez les secrets pour tout usage au-delà du développement.

3
Lancer le service

Ouvrez ensuite http://localhost:8787 : la page d'accueil contient la démonstration.

Windows · PowerShell
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
copy .env.example .env
uvicorn veilforge.main:app --reload --port 8787
macOS / Linux
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
uvicorn veilforge.main:app --reload --port 8787
Ce que vous obtenez
  • http://localhost:8787 — page de présentation avec la démonstration masque/restaure ;
  • http://localhost:8787/docs — cette documentation ;
  • http://localhost:8787/swagger — interface Swagger / OpenAPI ;
  • http://localhost:8787/v1 — point d'entrée compatible OpenAI.

02

Comment marche l'exemple

La démonstration de la page d'accueil exécute exactement deux appels à votre instance locale. Aucun modèle n'est sollicité : c'est le même mécanisme que la passerelle, isolé pour que vous puissiez le voir.

  1. Mask — POST /api/v1/mask reçoit votre texte, détecte les valeurs sensibles, remplace chacune par un jeton et renvoie l'identifiant de session.
  2. Transport — vous envoyeriez ce texte protégé au modèle. Dans la démonstration, le texte reste chez vous.
  3. Unmask — POST /api/v1/unmask reçoit la réponse contenant les jetons, la même session, et rétablit les valeurs d'origine.
curl · masquer puis restaurer
# 1) Masquage
curl -s http://localhost:8787/api/v1/mask \
  -H "Authorization: Bearer local-dev-key" \
  -H "Content-Type: application/json" \
  -d '{"text":"Écrire à ana@example.com au +33 6 12 34 56 78"}'

# → {"masked_text":"Écrire à [[EMAIL_001]] au [[PHONE_001]]",
#     "session_id":"vf_...", "entities":[...]}

# 2) Restauration (même session)
curl -s http://localhost:8787/api/v1/unmask \
  -H "Authorization: Bearer local-dev-key" \
  -H "Content-Type: application/json" \
  -d '{"text":"Réponse : [[EMAIL_001]] sera prévenu.","session_id":"vf_..."}'

# → {"text":"Réponse : ana@example.com sera prévenu.","unresolved":[]}
Le point important — tant que la session est la même, une même valeur reçoit toujours le même jeton : le modèle comprend que deux occurrences désignent la même personne, sans jamais la voir.

03

Passerelle compatible OpenAI

Veilforge implémente le contrat de /v1/chat/completions. Vous ne changez rien dans votre code : vous modifiez seulement l'URL de base et la clé.

Avec un fournisseur

Définissez VEILFORGE_UPSTREAM_URL (URL de base, sans /chat/completions) et VEILFORGE_UPSTREAM_API_KEY. La passerelle masque la requête, la transmet, puis restaure la réponse.

Sans fournisseur

La passerelle renvoie un écho de développement marqué "mock": true. Ce contenu n'est jamais présenté comme une réponse de modèle : il sert uniquement à tester la chaîne.

Python · client OpenAI
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8787/v1",
    api_key="local-dev-key",          # VEILFORGE_API_KEY
)

reponse = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user",
               "content": "Écris un mail à ana@example.com"}],
)
print(reponse.choices[0].message.content)
curl · passerelle
curl -s http://localhost:8787/v1/chat/completions \
  -H "Authorization: Bearer local-dev-key" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini",
       "messages":[{"role":"user","content":"Contact ana@example.com"}]}'
  • Streaming — si "stream": true, les événements SSE sont transmis et démasqués à la volée ; l'en-tête X-Veilforge-Session renvoie la session utilisée.
  • Session réutilisable — envoyez X-Veilforge-Session: vf_... pour conserver les mêmes jetons d'une requête à l'autre.
  • Échec amont — en mode strict, une erreur du fournisseur renvoie 502 sans jamais restituer le texte protégé : la demande est refusée plutôt que risquée.
  • Champ protégés — le masquage s'applique récursivement aux messages, aux schémas d'outils, aux arguments et aux résultats d'outils (chaînes uniquement), en ignorant model, role, stream, temperature et max_tokens.

04

Référence API

Toutes les routes /api/v1/* exigent l'en-tête Authorization: Bearer <VEILFORGE_API_KEY>. Le budget est de 120 requêtes par minute et par adresse IP. La page /api/v1/health et la racine sont exemptées.

MéthodeCheminRôle
POST/api/v1/detectListe les entités détectées, sans créer de session ni de jeton.
POST/api/v1/maskRemplace les valeurs par des jetons, crée (ou réutilise) la session et chiffre les correspondances.
POST/api/v1/unmaskRétablit les valeurs d'origine. session_id obligatoire.
POST/api/v1/analyzeCombine masquage et évaluation : renvoie l'aperçu protégé et un risque high / none.
POST/api/v1/sessionsCrée une session vide et renvoie son identifiant.
GET/api/v1/sessionsListe les 100 sessions les plus récentes (identifiant, création, échéance).
GET/api/v1/analyticsCompteurs locaux : masquages, sessions, rétention.
GET/api/v1/healthÉtat du service : mode, fournisseur configuré. Sans authentification.
POST/v1/chat/completionsPasserelle compatible OpenAI, avec restauration de la réponse.

Corps de requête commun

JSON
{
  "text": "Texte à analyser",
  "session_id": "vf_...",                  // optionnel : réutilise une session
  "custom_dictionary": {                   // optionnel : valeurs à protéger
    "CLIENT_INTERNE": ["nom de code Projet Sirius"]
  }
}

Réponse de POST /api/v1/mask

JSON
{
  "masked_text": "Écrire à [[EMAIL_001]] avant le [[DATE_OF_BIRTH_001]]",
  "session_id": "vf_Kd8s...",
  "entities": [
    {
      "type": "EMAIL",
      "placeholder": "[[EMAIL_001]]",
      "value": "ana@example.com",
      "start": 9,
      "end": 24,
      "confidence": 0.99,
      "source": "rules",
      "fingerprint": "1d420a5c0cf5948a"
    },
    {
      "type": "DATE_OF_BIRTH",
      "placeholder": "[[DATE_OF_BIRTH_001]]",
      "value": "12/07/1988",
      "start": 34,
      "end": 44,
      "confidence": 0.88,
      "source": "rules",
      "fingerprint": "7c19be03f8a41d55"
    }
  ]
}
Pourquoi la valeur figure ici — c'est le client qui a envoyé le texte : l'API ne fait que renvoyer ce qu'il connaît déjà, et les positions start/end servent à surligner chaque champ détecté dans l'aperçu local. Le champ value n'est jamais écrit dans le journal d'audit, qui ne conserve que des catégories, des comptages et des empreintes SHA-256 tronquées.

05

Jetons & sessions

Un jeton a la forme [[TYPE_001]] : un type en majuscules, puis un numéro séquentiel sur trois chiffres, propre à chaque session.

RègleExplication
Stable dans la sessionLa même valeur reçoit toujours le même jeton : le contexte du dialogue est préservé.
Isolé entre sessionsDeux sessions indépendantes ne partagent aucune correspondance.
Numérotation continueLe compteur reprend au valeur la plus élevée déjà utilisée pour ce type.
Inconnu = conservéUn jeton absent du coffre (session expirée, clé changée) reste tel quel et apparaît dans unresolved.
RétentionLes sessions expirent après VEILFORGE_RETENTION_HOURS (24 h par défaut).
Clé de chiffrement — si VEILFORGE_ENCRYPTION_KEY n'est pas définie, une clé éphémère est générée au démarrage : après un redémarrage, les anciennes correspondances deviennent illisibles et les jetons sont conservés comme « inconnus ». Définissez toujours une clé stable en production.

06

Détection

Le détecteur par défaut repose sur des règles déterministes, vérifiables et rapides. Chaque entité est associée à un score de confiance ; les chevauchements sont résolus en gardant le span le plus fiable.

TypeExempleConfianceRemarque
EMAILana@example.com0,99—
CREDIT_CARD4242 4242 4242 42420,99Contrôle de Luhn obligatoire
SECRETsk_live_…, ghp_…, JWT0,99Préfixes d'API, tokens JWT, en-têtes de clé privée
PASSWORDmot de passe : …, pwd= …0,99Mots de passe en clé/valeur, français et anglais
BANK_ACCOUNTcompte n° 1234567890120,93Libellé bancaire suivi d'un numéro
IBANFR76 3000 6000 0112 …0,96Format bancaire conservateur
IP_ADDRESS192.168.1.240,94—
NATIONAL_IDpasseport AB12345670,91Mot-clé contextuel requis
DATE_OF_BIRTHné le 12/07/19880,88Indice multilingue requis
PHONE+33 6 12 34 56 780,83Formes internationales
PERSONclient Jean Dupont0,69Uniquement avec un indice humain à proximité
ADDRESS24 rue des Oliviers, 69001 Lyon0,90Numéro + voie, code postal et ville optionnels
Valeur personnaliséeProjet Sirius1,00Via custom_dictionary
  • Multilingue — indices en anglais, français, malgache, allemand et espagnol.
  • Cas d'usage du dictionnaire — noms internes, codenames, clients récurrents : envoyez-les dans custom_dictionary pour un masquage certain.
  • Étendre — branchez un NER local (spaCy, Presidio) en implémentant le protocole Detector : le reste de la chaîne ne change pas.
  • Limite honnête — une détection par règles n'est pas une garantie de conformité. Faites toujours relire les sorties sensibles.
JSON · dictionnaire personnalisé
{
  "text": "Le client Projet Sirius demande un devis.",
  "custom_dictionary": {
    "CLIENT": ["Projet Sirius", "Compte Azurelion"]
  }
}

07

Configuration

Tout se règle par variables d'environnement, lues au démarrage du service.

VariableDéfautRôle
VEILFORGE_API_KEYlocal-dev-keyClé portée par les clients (Authorization: Bearer …). À changer impérativement en production.
VEILFORGE_ENCRYPTION_KEYéphémèreClé Fernet du coffre. Sans elle, les correspondances ne survivent pas à un redémarrage.
VEILFORGE_UPSTREAM_URLvideURL de base du fournisseur compatible OpenAI. Vide = écho de développement.
VEILFORGE_UPSTREAM_API_KEYvideClé transmise au fournisseur en amont.
VEILFORGE_FAIL_CLOSEDtruetrue : refuse toute forme non prise en charge. false : mode permissif, à éviter.
VEILFORGE_RETENTION_HOURS24Durée de vie des sessions et de leurs correspondances.
VEILFORGE_DB_PATHveilforge.dbChemin du fichier SQLite (chiffré au repos).
.env — production
VEILFORGE_API_KEY=change-me-in-production
VEILFORGE_ENCRYPTION_KEY=<python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())">
VEILFORGE_UPSTREAM_URL=https://api.openai.com/v1
VEILFORGE_UPSTREAM_API_KEY=sk-...
VEILFORGE_FAIL_CLOSED=true
VEILFORGE_RETENTION_HOURS=24

08

Sécurité

Le principe directeur : seul du contenu tokenisé franchit la frontière. Tout le reste reste sur la machine qui exécute le service.

Ce qui est chiffré

Les correspondances jeton → valeur sont chiffrées avec Fernet et isolées par session. Le fichier SQLite ne contient donc aucune valeur sensible en clair.

Ce qui est journalisé

Uniquement des catégories, des comptages et des empreintes SHA-256 tronquées. Aucune valeur détectée n'est écrite dans le journal d'audit.

Mode strict

Les formes de contenu non prises en charge et les pannes amont sont refusées. Le diagnostic est audité, la divulgation n'a pas lieu.

Contrôle d'accès

Clé API obligatoire sur les routes métier, limitation à 120 requêtes par minute et par IP, sessions à durée de vie limitée.

Checklist de mise en production

  1. Remplacer local-dev-key par une longue valeur aléatoire.
  2. Définir VEILFORGE_ENCRYPTION_KEY et la conserver stable (gestionnaire de secrets).
  3. Toujours VEILFORGE_FAIL_CLOSED=true.
  4. Servir le service en HTTPS derrière un reverse proxy, exposé seulement à vos applications.
  5. Choisir un VEILFORGE_DB_PATH sur un volume chiffré et sauvegardé.
  6. Surveiller le journal d'audit (événements mask, unmask, upstream_error).
  7. Relire les limites de la section Détection avant de déclarer une conformité.
Ce que Veilforge ne fait pas — pas de traitement d'image, d'OCR ni de détection de visage : ces entrées sont refusées en mode strict plutôt que transmises à l'aveugle. La détection par règles ne remplace pas une analyse juridique.

09

Architecture

Le service est volontairement linéaire : un détecteur, un coffre de correspondances chiffré, une passerelle HTTP. Aucune donnée n'est envoyée à un tiers autre que le fournisseur que vous configurez.

Votre prompt passe par le coffre chiffré de Veilforge avant d'atteindre le modèle, puis la réponse revient se faire restaurer.
Chemin d'une requête
client ─▶ Veilforge (détection + coffre chiffré) ─▶ fournisseur
client ◀─────────── restauration ◀──────────────── fournisseur

POST /v1/chat/completions
  1. création/réutilisation de la session
  2. masquage récursif du payload (messages, tools, results)
  3. transmission au fournisseur, ou écho marqué mock:true
  4. restauration de la réponse (y compris le flux SSE)
  5. audit : types, comptages, empreintes

Le code est organisé en trois modules : veilforge/detection.py (règles et protocole Detector), veilforge/vault.py (sessions, chiffrement, journal) et veilforge/main.py (routes FastAPI et passerelle).

10

Tests & Docker

Tests
python -m pytest -q
# 3 passed — détection, aller-retour masque/restauration, jetons inconnus
Docker Compose
docker compose up --build
# service sur le port 8787, données dans le volume veilforge-data (/data)

Le conteneur expose le port 8787, place la base dans /data et redémarre automatiquement. Pensez à fournir un .env (le compose le lit) contenant les secrets décrits dans Configuration.

11

Questions fréquentes

Mes données partent-elles vers un modèle ?

Seul le texte masqué est transmis, et uniquement si vous avez configuré VEILFORGE_UPSTREAM_URL. Sans fournisseur, la passerelle renvoie un écho de développement. La démonstration de la page d'accueil n'appelle aucun modèle.

Puis-je utiliser Veilforge sans interface ?

Oui. Le projet est API-first : la page d'accueil et la démonstration sont des clients de plus des routes /api/v1/*, documentées dans le Swagger.

Que se passe-t-il si je change la clé de chiffrement ?

Les correspondances anciennes deviennent illisibles : les jetons concernés sont conservés tels quels et remontés dans unresolved, jamais dévoilés par erreur. Créez une nouvelle session pour repartir proprement.

Comment ajouter un détecteur plus précis ?

Implémentez le protocole Detector (méthode detect) avec un modèle NER local, puis remplacez l'instance dans vault.detector. Le coffre, la passerelle et les jetons restent inchangés.

Où sont stockées les données ?

Dans un fichier SQLite local (VEILFORGE_DB_PATH), avec les correspondances chiffrées. Le journal d'audit ne contient que des catégories, des comptages et des empreintes.

Comment montrer un modèle à un client sans révéler ses données ?

Lancez la démonstration de la page d'accueil : le texte devient [[EMAIL_001]], puis revient à l'identique. C'est la même mécanique que la passerelle, en local.

Prêt à essayer ?

Lancez la démonstration interactive sur la page d'accueil, ou explorez les routes dans le Swagger.