Aller au contenu principal

Importer le corpus de l'ancien projet

Un script peuple la base depuis _source-oldproject, l'application Python que SekoiaCraft remplace. Il importe les technologies, leurs messages types, leurs templates et leurs données.

pnpm db:seed [chemin-du-corpus]

Le chemin est optionnel : à défaut, _source-oldproject à la racine du dépôt.

C'est l'étape « données de référence » du démarrage. La commande construit au passage les packages dont l'import dépend — il les charge par leur nom, donc depuis leur dist/. Sans ce build, l'équivalent bas niveau pnpm --filter @sekoiacraft/database seed:source échoue sur une résolution de module tant que le dépôt n'a pas été construit.

Le corpus est hors dépôt

_source-oldproject/ est dans le .gitignore — il contient les clés d'intake de production des communities SEKOIA. Le sondage du corpus est donc un geste local, jamais une dépendance de test ni de CI. Si le dossier manque, la commande ne s'arrête pas pour autant : elle charge l'instantané SQL versionné dans le dépôt.

Ce qu'il importe​

SourceDestinationVolume
generators/__init__.pyTechnologies (nom, format, alertes seules)28
<technologie>.pyMessages types, avec leurs poids470
event/<source>/templates/*.jinjaTemplates Nunjucks470
event/<source>/data/*.jsonPools d'échantillons383
conf/{users,servers,web}/*.jsonPopulations6

Le script exige python3 : c'est sa seule dépendance. Il importe réellement les classes du registre plutôt que d'en lire la source, parce que les listes de messages types sont parfois héritées et que les poids sont calculés, pas déclarés.

Sans le corpus, l'instantané​

Ces deux exigences — le dossier et Python — n'ont leur place ni dans une image Docker ni dans un runner de CI. pnpm db:seed choisit donc seul : le corpus quand il est présent, et sinon l'instantané SQL de packages/database/prisma/seed/corpus/, un fichier par technologie, versionné en clair. C'est par là que les environnements déployés reçoivent leurs technologies, leurs messages types et leurs gabarits.

L'instantané n'est pas une seconde source de vérité : il est photographié depuis une base que cet import vient d'écrire. Le corollaire est à retenir — un rafraîchissement du corpus, ou une correction des règles de réécriture des gabarits, ne prend effet en CI et en déploiement qu'après un pnpm db:snapshot.

Ce qu'il déduit​

Rien de tout cela n'est écrit dans la source : le script appelle chaque générateur et note ce qu'il demande à rendre. Le rapport final compte chaque déduction, pour qu'aucune approximation ne passe pour un fait.

Le template — la convention « un message type rend par le fichier .jinja qui porte son nom » ne vaut plus. windows/process-created rend par security-4688.jinja, les 24 messages types de Microsoft IIS passent tous par iis-access.jinja, et Sekoia Agent choisit son corps selon l'OS de l'entité. Le script observe le gabarit réellement atteint ; quand un message type en atteint plusieurs, ils sont réunis derrière un {% if %}.

Les constantes — le générateur source calculait hors du gabarit ce qui distingue deux messages types partageant un même fichier : remote-auth-success et local-auth-success rendent tous deux par security-logon.jinja et ne diffèrent que par leur enveloppe. Ces valeurs sont posées en préambule {% set %}, une fois par message type — près de 5 000 lignes sur l'ensemble du corpus.

La catégorie — l'ancien projet n'en a aucune notion. Elle est déduite du nom du message type (auth-failure → AUTH, dns-query-result → DNS, process-created → PROCESS…). Sur les 470, 297 sont déduites et 173 reçoivent la valeur par défaut NETWORK, à corriger depuis l'interface.

Le format de sortie — il est lu dans les templates, sur le corps une fois les balises de tête retirées. La majorité fait loi au niveau de la technologie ; celui qui déroge reçoit une valeur propre — aujourd'hui pan_ngfw/dns, seul objet JSON d'un générateur qui émet du CSV positionnel.

Le rattachement des données — un message type reçoit le pool que le générateur lui donne réellement, identifié par le contenu du fichier et non par son nom : zscaler-event est alimenté par zscaler.json, et sept messages types d'Office 365 se partagent message-trace.json. 420 des 470 sont rattachés ainsi ; les autres passent par le nom, ou n'ont pas de fichier de données dans la source — ce qui est normal.

Ce qu'il écarte​

Le corpus source n'est pas le catalogue : certains messages types n'ont pas leur place dans SekoiaCraft, quoi qu'en dise l'ancien projet. Ils sont listés dans packages/database/prisma/seed/excluded-event-types.ts, et le rapport final les nomme — un retrait volontaire doit se lire, pas se deviner d'un compte qui baisse.

TechnologieMessage typeMotif
Akamai WAFwaf-allowTrafic autorisé, retiré du catalogue — 800 des 850 points de poids

L'exclusion coupe aux deux bouts : ni message type, ni pool de données. C'est ici qu'elle est portée, et non par une suppression depuis l'interface, parce que l'import est rejoué à chaque seed:source — ce qui n'est retiré qu'en base reviendrait au passage suivant. Le script purge d'ailleurs ce qu'un import antérieur avait créé, pour qu'une base déjà peuplée converge.

Il est rejouable​

Tout passe par des upsert : un second passage ne duplique rien. Il ne réécrit pas un template que vous auriez édité à la main — sauf demande explicite :

pnpm db:seed --overwrite-templates

Si une technologie existe déjà sous un nom dérivé de son dossier, elle est renommée en place plutôt que dupliquée : ses datasets restent les siens.

Repartir d'une base vide​

L'import complète une base ; il ne la nettoie pas. Pour effacer et recharger d'un coup :

pnpm db:reset [chemin-du-corpus] [--overwrite-templates]

Quatre étapes enchaînées : build des packages dont le seed dépend, prisma db push --force-reset (drop de la base puis schéma), purge des files BullMQ, puis cet import — auquel les arguments sont transmis tels quels.

La purge Redis efface les clés du seul préfixe courant (REDIS_QUEUE_PREFIX, sekoiacraft-dev en local), jamais tout Redis : dev et preprod partagent la même instance. Elle est nécessaire parce que les jobs log-dispatch en attente référencent des lots d'envoi qui viennent de disparaître.

Développement uniquement

Le drop est irréversible et sans confirmation. Le script refuse de démarrer si DATABASE_URL ou REDIS_URL ne pointent pas sur localhost — un .env recopié de .env.preprod ne peut donc pas emporter la base de preprod. Passer outre demande un ALLOW_REMOTE_RESET=1 explicite.

Ce qui ne rend pas encore​

L'import remplit la base ; il ne rend pas tout fonctionnel pour autant. Sur les 470 messages types :

rendent et valident457
rendent une sortie invalide13
ne rendent pas0
sans template0

Les treize restants butent tous sur la même chose : des idiomes propres à Jinja2 que Nunjucks ne connaît pas — filename.endswith(…), _map.get(…), rsplit, le littéral dictionnaire {{{. Ils se corrigent un par un, dans le gabarit, depuis l'éditeur.

Le contexte de rendu, lui, ne manque plus : les 470 messages types ne référencent plus une seule racine que le moteur n'expose pas. Ce que le générateur source calculait au-dehors — constantes d'enveloppe, identifiants, valeurs tirées de l'entité ou du pool — est posé en préambule à l'import.

Un template cassé s'importe quand même

Plus aucun gabarit ne refuse de compiler aujourd'hui, mais le garde-fou reste : quand un template ne compile pas, il est stocké tel quel et signalé au rapport (Templates cassés). Le perdre priverait de ce qu'il faut corriger, et l'éditeur situe l'erreur à la ligne.

Les trois qui figuraient ici — sekoia_agent/registry-value-set, vmware_vcenter/lro-operation et vmware_vcenter/local-auth-failure — butaient sur la tranche Python (op_id[:8]), que Nunjucks ne sait pas analyser : son [ ouvre un accès indexé, et le : y est une erreur de syntaxe. Elle est désormais traduite en truncate à l'import. La même passe a réglé le formatage % de Python, plus sournois puisqu'il compilait : en JavaScript le % est un modulo, si bien que '%03d' % 45 rendait NaN dans l'horodatage de 32 gabarits vCenter et Salesforce, sans qu'aucune validation ne s'en aperçoive — la sortie restait un JSON valide.