NeuralWall Rules Kit

Guide de contribution

Ce document couvre le flow de contribution par PR, les règles de versioning, le système de trust tier, le DCO, et les points de friction à connaître avant de soumettre une fiche.


Sommaire

  1. Flow PR
  2. Versioning des fiches
  3. Trust tier
  4. DCO — Developer Certificate of Origin
  5. Anti-patterns relevés par le linter
  6. Champs experts : mitre_attack et threat_model
  7. Rappel des invariants clés

1. Flow PR

fork → branche → fiche → validate + lint + render → PR → revue mainteneur → merge

Étapes détaillées

a. Forker et créer une branche

git clone https://github.com/your-org/neuralwall-rules-kit.git
cd neuralwall-rules-kit
git checkout -b feat/mon-scenario

b. Créer la fiche depuis le gabarit

cp templates/fiche.template.yaml profiles/<categorie>/<id>.yaml

Convention d'id : snake_case, descriptif, format recommandé <verbe>_<sujet> ou <service>_<direction> (ex. expose_https_public, saas_outbound_access). L'id est une clé primaire stable : ne pas le modifier après merge.

c. Éditer la fiche

  • Remplir tous les champs obligatoires (voir docs/format-spec.md).
  • Prose uniquement en locale-map {fr: "...", en: "..."} — jamais de texte brut.
  • Enums strictement issus de taxonomy/taxonomy.yaml.
  • Aucune marque propriétaire (vendor-agnostic, invariant 3).

d. Valider localement avant de pousser

# Validation JSON Schema (structure)
python scripts/validate.py profiles/<categorie>/<id>.yaml

# Linter sécurité (anti-patterns)
python scripts/lint.py profiles/<categorie>/<id>.yaml

# Prévisualiser les trois représentations
python scripts/render.py profiles/<categorie>/<id>.yaml --locale fr,en --out build/

Les trois commandes doivent passer sans erreur. Le répertoire build/ est ignoré par Git (ne rien commiter depuis ce dossier).

Si vous modifiez taxonomy/taxonomy.yaml, régénérez le schéma et committez-le :

python scripts/gen_schema.py   # met à jour schema/fiche.schema.json
git add schema/fiche.schema.json taxonomy/taxonomy.yaml
git commit -s -m "chore(schema): regenerer les enums depuis la taxonomie"

La CI bloquera toute PR où le schéma n'est pas en phase avec la taxonomie (python scripts/gen_schema.py --check doit sortir avec code 0).

e. Commiter avec sign-off DCO

git add profiles/<categorie>/<id>.yaml
git commit -s -m "feat(profiles): ajouter fiche <id>"
# L'option -s ajoute automatiquement la ligne Signed-off-by

f. Ouvrir la PR

  • Titre : feat(profiles): <description courte>
  • Description : scénario couvert, sources utilisées pour mitre_attack, justification du trust_tier si différent de community.

g. Revue par un mainteneur

Le mainteneur vérifie : conformité schéma, cohérence threat model, absence de marque, qualité du rationale. Il peut promouvoir le trust_tier à reviewed après merge.


2. Versioning des fiches

Deux versions coexistent dans chaque fiche — elles ne se confondent pas (invariant 7).

Champ Rôle Géré par
schema_version Version du contrat d'ingestion (JSON Schema). Identique pour toutes les fiches compatibles. Mainteneurs core
version Version sémantique du contenu de cette fiche. Auteur de la fiche

Règles de bump de version (ADR-0002 §4)

Type de changement Bump Exemples
Clarification de prose, correction typo, amélioration du rationale patch (1.0.01.0.1) Reformuler une description, corriger une faute
Ajout d'un contrôle (nouvelle règle, nouveau profil de sécurité) minor (1.0.01.1.0) Ajouter sandboxing, ajouter une règle de dépendance DNS
Changement d'intent ou modification structurante major (1.0.02.0.0) Changer l'action d'une règle, modifier les zones, changer le scénario couvert

Un bump de schema_version n'est décidé que par les mainteneurs core, il signale une évolution du contrat d'ingestion incompatible avec les versions précédentes.


3. Trust tier

Chaque fiche porte un trust_tier obligatoire (ADR-0002 §3, invariant 6). Il est pondéré par NeuralWall à l'ingestion : une fiche community n'a pas le même poids dans le RAG qu'une fiche verified. C'est le principal rempart contre l'empoisonnement de la base de connaissance.

Valeur Signification Qui l'attribue
community Contribution non revue. Défaut pour toute PR entrante. Automatique à la soumission
reviewed Revue explicite par un mainteneur du portail. Mainteneur (après merge ou via PR de mise à jour)
verified Validée par un éditeur ou une source autoritaire (ex. CERT, éditeur de firewall). Mainteneurs core uniquement

Comment le tier évolue

  1. Toute fiche mergée commence à community.
  2. Un mainteneur qui a relu en profondeur ouvre un commit de mise à jour changeant trust_tier: communitytrust_tier: reviewed avec un bump patch de version.
  3. verified est réservé aux fiches issues d'une source institutionnelle vérifiée ; le mainteneur core crée un commit documentant la source.

Pourquoi ce tier est critique

NeuralWall ingère les fiches pour alimenter un RAG de génération de règles. Une fiche community mal rédigée (mauvaise action, profils manquants) pourrait conduire à la suggestion de règles faibles. Le tier permet à NeuralWall de pondérer la confiance et d'éviter qu'une fiche non revue influence autant qu'une fiche validée par un expert.


4. DCO — Developer Certificate of Origin

Ce projet n'utilise pas de CLA (Contributor License Agreement). À la place, il suit le Developer Certificate of Origin 1.1, mécanisme léger et standard qui atteste que vous avez le droit de soumettre votre contribution sous la licence du projet (CC-BY-4.0).

Comment signer

Ajoutez l'option -s à chaque git commit :

git commit -s -m "votre message de commit"

Git ajoute automatiquement en fin de message :

Signed-off-by: Prénom Nom <email@exemple.org>

Cette ligne est votre attestation du DCO. L'email doit correspondre à l'identité Git configurée. Aucune signature électronique ni procédure externe n'est requise.

Texte du Developer Certificate of Origin 1.1

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

Attribution CC-BY-4.0

En signant le DCO, vous attestez que votre contribution peut être distribuée sous CC-BY-4.0. Veillez à renseigner le champ authors de votre fiche avec votre nom (et optionnellement email/org) pour que l'attribution soit correctement propagée dans les rendus.


5. Anti-patterns relevés par le linter

Le script python scripts/lint.py détecte les configurations risquées. Ces règles sont minimales en Phase 1 et extensibles.

a. allow sans security_profiles

# ANTI-PATTERN — le linter ECHOUE sur ceci :
action: allow
# security_profiles absent

# CORRECT — posture next-gen (invariant CLAUDE.md) :
action: allow
security_profiles:
  antivirus: { action: default }
  ips: { action: block, min_severity: medium }

Une règle allow sans aucun profil de sécurité laisse passer le trafic sans inspection. Si l'omission est intentionnelle et justifiée (ex. flux de management ultra-contrôlé), le linter l'accepte si un rationale explicite est présent sur la règle.

b. decryption: mode: none sur du sortant à risque

# ANTI-PATTERN — flux sortant vers internet sans déchiffrement :
direction: outbound
zones:
  source: [trust]
  destination: [internet]
decryption:
  mode: none
# Sans rationale : le linter AVERTIT

# CORRECT — soit déchiffrer, soit justifier :
decryption:
  mode: ssl_forward_proxy
# OU :
decryption:
  mode: none
rationale:
  fr: "Trafic vers service avec cert-pinning (client lourd) — déchiffrement impossible."
  en: "Traffic to cert-pinned service (thick client) — decryption not feasible."

Sans déchiffrement, les profils AV/IPS/sandboxing voient un flux chiffré opaque et ne peuvent pas inspecter le contenu.

c. application: unknown non justifié

# ANTI-PATTERN :
application:
  app_id: unknown
  category: unknown
# Sans rationale : le linter AVERTIT

# CORRECT — toujours justifier un unknown :
application:
  app_id: unknown
  category: unknown
rationale:
  fr: "Trafic legacy non identifiable L7 — port restreint, périmètre isolé."
  en: "Legacy traffic not identifiable at L7 — restricted port, isolated perimeter."

d. url_filtering riche sans déchiffrement (LNT-004)

allow_list/block_list (filtrage par chemin d'URL) et credential_phishing n'opèrent qu'avec decryption.mode: ssl_forward_proxy : sans déchiffrement, le firewall ne voit que le domaine (SNI), pas l'URL complète ni les soumissions de formulaire (taxonomie §7.1 + §8).

# ANTI-PATTERN — protection dégradée (le linter le relève) :
action: allow
security_profiles:
  url_filtering:
    credential_phishing: block      # exige le déchiffrement pour être effectif
decryption:
  mode: none

# CORRECT — activer le déchiffrement sortant :
decryption:
  mode: ssl_forward_proxy
# OU justifier explicitement le mode none via rationale (cert-pinning, etc.).

Posture next-gen : identifier l'application, pas le port

Identifiez toujours l'application au niveau L7 (app_id). Le champ service.ports est un complément pour la cohérence, pas le critère de matching. Un contrôle par port seul est un fallback à justifier explicitement dans rationale.


6. Champs experts : mitre_attack et threat_model

Ces deux champs sont auteurés par un expert humain (ADR-0002 §2, invariant 5). La carte RAG les rend ; elle ne les déduit pas des autres champs. C'est ce qui garantit le « zéro drift » : la connaissance experte est explicite, pas implicite.

mitre_attack[]

Tableau des techniques MITRE ATT&CK couvertes ou atténuées par le scénario.

mitre_attack:
  - technique_id: "T1071"          # Format : T\d{4} ou T\d{4}.\d{3}
    name: "Application Layer Protocol"
    tactic: "command-and-control"
  - technique_id: "T1071.001"      # Sous-technique
    name: "Web Protocols"
    tactic: "command-and-control"

Gabarit de recherche : consultez attack.mitre.org pour trouver les techniques pertinentes à votre scénario. Raisonnez en termes de flux atténué : quelle technique l'attaquant ne peut plus exécuter grâce à ces règles ?

Exemples courants par scénario :

Scénario Techniques pertinentes
Ingress HTTPS public T1190 (Exploit Public-Facing App), T1071.001 (Web Protocols)
Sortant SaaS T1048 (Exfiltration Over Alt Protocol), T1567 (Exfiltration to Cloud Storage)
DNS T1071.004 (DNS), T1568 (Dynamic Resolution)

threat_model

Modèle de menace structuré au niveau fiche.

threat_model:
  summary:
    fr: "Ce scénario expose un serveur web en DMZ. Sans inspection TLS inbound,
         un attaquant peut exploiter des vulnérabilités applicatives masquées dans
         le flux chiffré. Les profils IPS et sandboxing atténuent ce risque."
    en: "This scenario exposes a web server in the DMZ. Without inbound TLS inspection,
         an attacker can exploit application vulnerabilities hidden in encrypted traffic.
         IPS and sandboxing profiles mitigate this risk."
  attacker_goal:
    fr: "Compromettre le serveur web exposé pour accéder au réseau interne."
    en: "Compromise the exposed web server to gain access to the internal network."
  key_controls:
    - ssl_inbound_inspection   # Identifiants libres, conventions : clés canoniques de taxonomie
    - ips
    - sandboxing

Conseils pour threat_model :

  • summary : décrivez la surface d'attaque principale et comment les règles la réduisent.
  • attacker_goal : formulez en termes d'objectif attaquant (pas de contrôle).
  • key_controls : listez les contrôles qui font réellement la différence — renvoyez aux clés canoniques de security_profiles ou à decryption.mode.

La friction documentée ici est intentionnelle (ADR-0002) : un threat model vide ou générique sera signalé lors de la revue mainteneur.


7. Rappel des invariants clés

Ces invariants dérivent de CLAUDE.md et des ADR. Les violer entraîne un refus de PR.

# Invariant Conséquence si violé
1 Source unique. Une fiche = un fichier YAML. Pas de prose parallèle. Drift garantis — refus immédiat
2 Structure neutre linguistiquement. Enums/clés en snake_case anglais, jamais traduits. Schéma invalide, validate échoue
3 Vendor-agnostic strict. Aucune marque dans les fiches. Refus PR
4 Enums ⊆ taxonomie. Toute valeur doit exister dans taxonomy/taxonomy.yaml. validate échoue
5 MITRE & threat_model auteurés. Ne pas laisser vides ni remplir mécaniquement. Refus revue mainteneur
6 trust_tier obligatoire. validate échoue
7 schema_versionversion. Ne pas les confondre ni les synchroniser. Erreur d'ingestion NeuralWall
8 Rendus non commités. Le dossier build/ n'appartient pas au repo. CI rejette le commit
9 Actions alignées OpenC2. allow/deny/drop/reset uniquement. validate échoue
10 DCO sign-off obligatoire. git commit -s sur chaque commit. PR bloquée

Bascule CMS (ADR-0004) — la base devient la source

Depuis l'ADR-0004, la source de vérité d'une fiche est la base de données (table fiche, colonne content JSON validée au schéma à l'écriture). Le YAML de profiles/ et les rendus deviennent des exports reproductibles.

Tant que la migration de bascule (seed) n'a pas été appliquée en production, les YAML de profiles/ restent la source de fait : continuez à contribuer par PR + DCO comme ci-dessus. La bascule est atomique à l'étape « seed » (cf. plan ADR-0004 §2-5).

Outils CMS (backend api/) :

Outil Rôle
Endpoints POST/GET/PUT /fiches Cycle de vie éditorial. Toute écriture valide + linte le content avant persistance (rejet 422 si schéma invalide ou finding lint de sévérité high).
python scripts/seed_fiches.py Import one-shot des profiles/*/fiche.yaml → table fiche (idempotent ; nécessite alembic upgrade head au préalable).
python scripts/export_fiches.py [--check] Export inverse DB → profiles/<id>/fiche.yaml (canonique, déterministe). --check = garde-fou CI : exit 1 si l'export YAML diverge de la base (anti-drift).

Le content_hash (SHA-256 du JSON canonique) garantit la détection de drift entre la base et les exports.