Aller au contenu

Construire un workflow (schéma JSON)

Un workflow TechWatchAlert est un graphe d’automatisation : un déclencheur réagit à un événement (nouvelle CVE, fin de vie qui approche, certificat qui expire…), des conditions filtrent, et des actions notifient ou agissent. Ce graphe est décrit par un objet JSON que vous manipulez via l’éditeur visuel, l’assistant Vigie, ou l’import/export de workflow.

Le graphe (workflow.graph) a exactement deux clés :

{
"nodes": [ /* les tuiles */ ],
"edges": [ /* les connexions entre tuiles */ ]
}
{
"id": "c1",
"type": "condition.cvss",
"params": { "op": "gte", "value": 9 },
"position": { "x": 320, "y": 140 }
}
ChampTypeDescription
idstringIdentifiant unique dans le graphe (libre : trigger, c1, a1…).
typestringType de tuile (voir le catalogue).
paramsobjectParamètres de la tuile (selon son type). {} si aucun.
positionobject (optionnel)Coordonnées { x, y } dans le canevas. Omettez-le : l’éditeur dispose automatiquement les tuiles.
{ "id": "e1", "source": "trigger", "target": "c1", "sourceHandle": "out" }
ChampTypeDescription
sourcestringid de la tuile de départ.
targetstringid de la tuile d’arrivée.
sourceHandlestringSortie utilisée sur la tuile de départ : out (déclencheurs et actions) ou true / false (conditions). Défaut : out.
idstring (optionnel)Identifiant de la connexion.

Un graphe est refusé (avec un message explicite) s’il enfreint l’une de ces règles :

  • Un seul déclencheur par workflow, et exactement un (trigger.*).
  • Un déclencheur ne peut pas avoir d’entrée (aucune connexion ne pointe vers lui).
  • Les conditions ont deux sorties : true et false. Le sourceHandle d’une connexion partant d’une condition doit être true ou false.
  • Les déclencheurs et les actions ont une seule sortie : out.
  • Le graphe est acyclique (DAG) — aucune boucle.
  • 30 tuiles maximum (MAX_NODES), profondeur 20 maximum depuis le déclencheur.
  • id de tuile unique ; toute connexion référence des tuiles existantes.
  • Les tuiles non reliées au déclencheur sont ignorées à l’exécution (tolérées à l’enregistrement pour ne pas bloquer un brouillon).
  • 10 workflows maximum par projet.

Le registre complet est aussi servi par l’API interne (GET /projects/{id}/workflows/node-types) pour générer la palette de l’éditeur.

Un déclencheur réagit à un événement. Le contexte (CVE, EOL ou certificat) détermine quelles conditions ont un sens en aval. Aucun n’a de paramètre.

TypeÉvénementContexteDéclenché quand…
trigger.cve_new_matchcve.new_matchCVEune nouvelle CVE correspond à votre stack surveillée.
trigger.cve_updatedcve.updatedCVEune CVE suivie est mise à jour (score, etc.).
trigger.cve_poc_publishedcve.poc_publishedCVEun PoC public apparaît pour une CVE suivie.
trigger.cve_kev_addedcve.kev_addedCVEune CVE suivie entre au catalogue KEV de la CISA.
trigger.eol_approachingeol.approachingEOLla fin de vie d’un produit suivi approche.
trigger.eol_support_endingeol.support_endingEOLla fin de support actif approche.
trigger.eol_new_releaseeol.new_releaseEOLune nouvelle version d’un produit suivi sort.
trigger.url_cert_expiringurl.cert_expiringCertificatle certificat HTTPS d’une URL surveillée expire bientôt.

Chaque condition a deux sorties (true / false). Une condition d’une autre famille que le déclencheur (ex. condition CVE après un déclencheur EOL) est sans effet utile.

TypeContexteParamètres
condition.severityCVEopgte | eq | in ; value (une sévérité) pour gte/eq, values (liste) pour in.
condition.cvssCVEopgt | gte | lt | lte ; value nombre 0 → 10.
condition.epssCVEopgt | gte | lt | lte ; value nombre 0 → 1.
condition.has_pocCVE(aucun) — vrai si un PoC public existe.
condition.is_kevCVE(aucun) — vrai si la CVE est au catalogue KEV.
condition.product_nameCVEopcontains | starts_with | ends_with | equals ; value texte (≤ 100).
condition.vendor_nameCVEidem product_name, sur l’éditeur.
condition.match_typeCVEvaluevendor | product | keyword (comment la CVE a matché votre stack).
condition.case_statusCVEopeq | ne ; value ∈ statut de suivi ou NONE.
condition.has_tagCVEtag_id (UUID d’un tag de l’organisation).
condition.eol_days_remainingEOLop (numérique) ; value jours −3650 → 3650.
condition.eol_is_pastEOL(aucun) — vrai si la date de fin de vie est dépassée.
condition.eol_product_nameEOLop (texte) ; value texte (≤ 100).
condition.cert_days_remainingCertificatop (numérique) ; value jours −3650 → 3650.
condition.cert_is_expiredCertificat(aucun) — vrai si le certificat est expiré.
condition.url_containsCertificatop (texte) ; value texte (≤ 100).

Sévérités : CRITICAL, HIGH, MEDIUM, LOW, NONE, UNKNOWN. Statuts de suivi : PENDING, ANALYZING, FIXING, ACCEPTED, RESOLVED, NOT_APPLICABLE.

Les actions s’exécutent quand le flux les atteint. Elles ont une sortie out et peuvent s’enchaîner.

TypeParamètresEffet
action.notify_inapp(aucun)Notification dans l’application.
action.send_emailrecipients (optionnel) : liste d’IDs membres ; vide = tous les membres concernés.E-mail.
action.fire_webhookswebhook_id (optionnel) : un webhook précis, vide = tous les webhooks actifs ; formatjson | slack | discord.Webhook sortant (HMAC).
action.create_casestatus ∈ statut de suivi (requis).Crée une fiche d’alerte (suivi). Nécessaire pour qu’une alerte apparaisse dans « Alertes » et que l’e-mail contienne le bouton « Voir l’alerte ».
action.ai_enrichinstruction (optionnel, ≤ 500) : consigne pour l’analyse (ex. « focus remédiation Debian »).Génère une analyse IA (résumé, risque, remédiation) à partir des seules données techniques publiques ; le résultat est mis à disposition des actions suivantes (e-mail, webhook, notification). Aucune donnée personnelle n’est envoyée au modèle.
action.add_tagtag_id (UUID, requis).Ajoute un tag à la CVE dans le projet (auto-classement).

Valide (un workflow doit avoir exactement un déclencheur), mais n’agit pas.

{
"nodes": [
{ "id": "trigger", "type": "trigger.cve_new_match", "params": {} }
],
"edges": []
}

« Quand une nouvelle CVE touche ma stack avec un CVSS ≥ 9, notifie Slack. »

{
"nodes": [
{ "id": "trigger", "type": "trigger.cve_new_match", "params": {} },
{ "id": "c1", "type": "condition.cvss", "params": { "op": "gte", "value": 9 } },
{ "id": "a1", "type": "action.fire_webhooks", "params": { "format": "slack" } }
],
"edges": [
{ "id": "e1", "source": "trigger", "target": "c1", "sourceHandle": "out" },
{ "id": "e2", "source": "c1", "target": "a1", "sourceHandle": "true" }
]
}

La connexion c1 → a1 utilise sourceHandle: "true" : l’action ne se déclenche que si la condition est vraie.

« KEV → fiche d’alerte + e-mail ; sinon → notification in-app simple. »

{
"nodes": [
{ "id": "trigger", "type": "trigger.cve_new_match", "params": {} },
{ "id": "kev", "type": "condition.is_kev", "params": {} },
{ "id": "case", "type": "action.create_case", "params": { "status": "PENDING" } },
{ "id": "mail", "type": "action.send_email", "params": {} },
{ "id": "inapp", "type": "action.notify_inapp", "params": {} }
],
"edges": [
{ "id": "e1", "source": "trigger", "target": "kev", "sourceHandle": "out" },
{ "id": "e2", "source": "kev", "target": "case", "sourceHandle": "true" },
{ "id": "e3", "source": "case", "target": "mail", "sourceHandle": "out" },
{ "id": "e4", "source": "kev", "target": "inapp", "sourceHandle": "false" }
]
}

Les actions s’enchaînent (case → mail via out). La branche false mène à une notification légère.

{
"nodes": [
{ "id": "trigger", "type": "trigger.cve_kev_added", "params": {} },
{ "id": "ai", "type": "action.ai_enrich", "params": { "instruction": "Priorise la remédiation." } },
{ "id": "mail", "type": "action.send_email", "params": {} }
],
"edges": [
{ "id": "e1", "source": "trigger", "target": "ai", "sourceHandle": "out" },
{ "id": "e2", "source": "ai", "target": "mail", "sourceHandle": "out" }
]
}

ai_enrich est placé avant l’e-mail : son analyse est incluse dans le message.

{
"nodes": [
{ "id": "trigger", "type": "trigger.eol_approaching", "params": {} },
{ "id": "c1", "type": "condition.eol_days_remaining", "params": { "op": "lte", "value": 90 } },
{ "id": "a1", "type": "action.send_email", "params": {} }
],
"edges": [
{ "id": "e1", "source": "trigger", "target": "c1", "sourceHandle": "out" },
{ "id": "e2", "source": "c1", "target": "a1", "sourceHandle": "true" }
]
}
MessageCause
Le workflow doit contenir exactement un déclencheurZéro ou plusieurs tuiles trigger.*.
Sortie '…' invalide pour …sourceHandle incohérent (ex. out sur une condition, ou true sur une action).
Le workflow contient une boucleLe graphe n’est pas acyclique.
Un déclencheur ne peut pas avoir d'entréeUne connexion pointe vers le trigger.*.
Paramètre requis '…' manquant pour …Paramètre obligatoire absent (ex. value sur condition.cvss).
Valeur '…' invalide pour …Valeur hors de la liste autorisée (sévérité, statut, opérateur…).
Valeur hors bornes pour …Nombre hors plage (CVSS 0–10, EPSS 0–1, jours −3650–3650).
Trop de tuiles (max 30) / Workflow trop profond (max 20)Graphe trop grand.
  • Le plus simple : décrivez votre besoin à Vigie (assistant IA) sur la page Workflows — elle génère le graphe, que vous approuvez.
  • L’éditeur visuel produit et relit ce même JSON ; l’export d’un workflow donne un fichier { name, description, graph } réimportable.
  • Voir aussi : Workflows (API).