Version 1.0.0
Chaîne d'approvisionnement : ce qui se vérifie
La nomenclature CycloneDX, le dossier VEX et sa règle de justification, les scans et leur cadence, le contrôle « zéro symbole de sortie réseau » sur l'artefact construit, les signatures et la livraison.
Cette page décrit les artefacts et les contrôles de la chaîne d’approvisionnement logicielle, avec le chemin du fichier ou du workflow qui les produit. Chaque affirmation renvoie à ce qu’un acheteur peut vérifier lui-même. Chaque version est livrée avec sa nomenclature (SBOM), sa déclaration d’exploitabilité (VEX) et ses signatures (livre blanc sécurité V3, section 9.1). Les axes que le livre blanc ne couvre pas sont décrits dans Ce qui reste à construire.
La nomenclature logicielle (SBOM CycloneDX)
Section intitulée « La nomenclature logicielle (SBOM CycloneDX) »Le workflow .github/workflows/sbom-release.yml produit une nomenclature
CycloneDX de toutes les dépendances npm du dépôt, générée par Trivy sur une
version figée :
trivy fs --format cyclonedx --output source.cdx.json ./Le document est attaché à la version sous un nom adressable et versionné,
lemniscate-source-<tag>.cdx.json, et livré avec elle. Il couvre les services de
la passerelle, les extensions et leurs dépendances, et vous pouvez le charger
dans vos outils de gestion des vulnérabilités (livre blanc sécurité V3, section
9.1). Il n’est pas committé : c’est un dérivé reproductible d’une version figée,
que vous pouvez rejouer avec un autre outil et comparer.
Un garde-fou précède l’attachement. Le workflow échoue si le document n’annonce
pas bomFormat: CycloneDX, s’il n’a pas de version de spécification, ou s’il ne
contient aucun composant. Le décompte des composants est écrit dans le résumé du
job.
Le mécanisme s’auto-vérifie : toute modification de ce workflow ou de
l’installation de Trivy déclenche une génération et une validation de la
nomenclature. L’étape d’attachement se déclenche sur l’événement release : une
nomenclature accompagne chaque version.
Le dossier VEX et sa règle de justification
Section intitulée « Le dossier VEX et sa règle de justification »Un scanner qui rend une liste de vulnérabilités sur une nomenclature ne dit pas
lesquelles atteignent le produit. La réponse à « vous avez N CVE, justifiez »
vit dans security/vex/, sous forme de documents OpenVEX versionnés.
Ces documents sont committés. Ce sont des décisions humaines tracées : l’historique git dit qui a justifié quoi, et quand. La déclaration VEX est générée à chaque version et livrée avec elle : pour chaque vulnérabilité publiée sur une dépendance, elle dit si le produit est affecté et ce qui est fait (livre blanc sécurité V3, section 9.1).
Le validateur de justification
Section intitulée « Le validateur de justification »Le validateur security/lib/vex.ts rejette tout statement not_affected
dépourvu de l’une des cinq justifications du référentiel CISA :
component_not_presentvulnerable_code_not_presentvulnerable_code_not_in_execute_pathvulnerable_code_cannot_be_controlled_by_adversaryinline_mitigations_already_exist
Le rejet intervient avant que le scanner ne consomme le dossier. Aucune CVE
n’est retirée d’un rapport sans justification recevable, et cette garantie ne
dépend pas du comportement d’un outil tiers. Elle est couverte par
security/vex/vex-validation.test.ts.
Le contrôle porte aussi sur le dossier réel, pas seulement sur des fixtures :
security/vex/vex-dir-compliance.test.ts valide security/vex/ tel qu’il est
committé. Un statement non conforme fait échouer l’intégration continue.
Le jugement d’exploitabilité
Section intitulée « Le jugement d’exploitabilité »Le jugement d’exploitabilité est humain. Aucune analyse automatisée
d’atteignabilité n’est employée (décision D3 de
specs/2026-07-29-sbom-vex/spec.md). Deux raisons sont consignées : les moteurs
crédibles pour JavaScript et TypeScript sont des services hébergés aux
États-Unis, ce qui les exclut pour un produit destiné à des environnements
isolés ; et leur mode d’échec est le faux négatif, c’est-à-dire une affirmation
de conformité fausse.
Les scans et leur cadence
Section intitulée « Les scans et leur cadence »| Contrôle | Fichier | Déclenchement | Effet |
|---|---|---|---|
| OSV différentiel sur une proposition de modification | .github/workflows/osv-scanner-pr.yml | à chaque proposition | bloquant si elle en introduit une |
| OSV, dépôt complet | scripts/cron-local/jobs/osv-scan.sh | lundi 11h00, sur le poste de l’éditeur | rapport et décompte, signalés à l’éditeur |
| Secrets (Trivy) | scripts/cron-local/jobs/trivy-secret.sh | lundi 11h30, sur le poste de l’éditeur | rapport et décompte, signalés à l’éditeur |
| Images de conteneurs (Trivy) | scripts/cron-local/jobs/trivy-image.sh | lundi 12h00, sur le poste de l’éditeur | construction locale puis scan |
| Dépendances après suppression VEX (Trivy) | scripts/cron-local/jobs/trivy-vex.sh | lundi 12h30, sur le poste de l’éditeur | liste résiduelle, chaque retrait justifié |
Les quatre scans planifiés tournent sur le poste de l’éditeur, sous des minuteries
systemd déclarées dans scripts/cron-local/schedule.yaml, sur une copie propre
de main. Chacun se termine par un message envoyé à une personne : un scan qui
n’a rien trouvé le dit, et un scan qui n’a pas pu mesurer échoue. Les workflows
.github/workflows/trivy-secret-scan.yml, trivy-image-scan.yml et
trivy-vex-scan.yml gardent un déclencheur manuel ; les deux derniers
s’auto-testent aussi sur une proposition qui les modifie.
La porte différentielle exécute deux scans, l’un sur la branche cible, l’autre sur la branche courante, et n’échoue que si la modification introduit une vulnérabilité. Une dette héritée ne bloque pas le travail courant ; une régression ne passe pas. Le contrôle ne dépend d’aucune fonctionnalité payante de la forge.
Le scan « après suppression VEX » consomme les documents du dépôt : sa sortie est
la liste de ce qui reste à traiter, chaque retrait étant adossé à un document
justifié et signé par un auteur identifiable. Son comportement est vérifié sur
une vulnérabilité figée dans security/vex/vex-suppression.integration.test.ts.
Le scan de secrets est éprouvé par un canari :
security/trivy/secret-scan.integration.test.ts place un secret factice et
vérifie qu’il est détecté.
Un job dédié, .github/workflows/security-checks.yml, exécute le typage et les
tests du paquet security/ sur toute proposition qui y touche.
L’intégrité de la chaîne d’outillage
Section intitulée « L’intégrité de la chaîne d’outillage »Un scanner téléchargé sans vérification annule l’intérêt du scan. Trois règles s’appliquent :
- Trivy est épinglé par version et vérifié par empreinte. L’action
.github/actions/install-trivy/action.ymlcentralise la version pour tous les workflows de sécurité et compare l’archive au fichier de sommes publié dans la même release avant de l’exécuter. Aucun tag mouvant, aucunlatest(identifiantSEC-9.3-04). - Les actions tierces des workflows de sécurité sont épinglées par empreinte de commit, avec la version en commentaire.
- Les dépendances sont installées par
npm cicontre les fichiers de verrouillage, ce qui valide l’empreinte d’intégrité de chaque paquet installé.
Le contrôle « zéro symbole de sortie réseau » sur l’artefact construit
Section intitulée « Le contrôle « zéro symbole de sortie réseau » sur l’artefact construit »Ce contrôle ne porte pas sur les sources mais sur le binaire livré. Il se vérifie sans accès au code.
Lemniscate se construit selon un profil de déploiement choisi à la construction,
et non par un réglage à l’exécution : dans l’artefact on-premise, la couche de
sortie réseau n’est pas désactivée, elle est absente du graphe de modules. Une
garantie qui dépend d’un réglage se falsifie par un changement de
configuration ; celle-ci se falsifie par inspection de l’artefact.
npm run build --prefix extensions/clinpm run esbuild-base --prefix extensions/vscode(cd gui && NODE_OPTIONS=--max-old-space-size=6144 npx vite build)npm run build --prefix llm-gatewaynpm run build --prefix gateway-adminLe script connaît six unités déployables : cli, vscode, gui,
llm-gateway, gateway-admin et intellij. Sans option, il les inspecte
toutes ; l’option répétable --composant restreint l’inspection aux composants
nommés. Un composant demandé mais non construit n’est pas jugé conforme : il est
signalé comme absent, et le contrôle échoue. L’invocation ci-dessous nomme les
cinq unités JavaScript ; le greffon JetBrains, qui exige une construction
Gradle, est inspecté hors de l’intégration continue.
node scripts/verify-onprem-artifact.mjs \ --composant cli --composant vscode --composant gui \ --composant llm-gateway --composant gateway-adminLe script applique quatre contrôles indépendants :
- Les symboles présents dans le texte des artefacts construits : domaines, clés de projet, noms de bibliothèques. C’est le seul angle vérifiable par un tiers sans lire le code source.
- Les entrées des manifestes de construction esbuild. Un bundle minifié peut ne plus porter le nom du paquet qu’il embarque ; le manifeste liste chaque module entré dans le graphe. Ce second angle survit à la minification.
- L’inventaire des unités déployables : l’apparition d’une unité non déclarée fait échouer le contrôle.
- L’absence d’appel, au chargement d’un module, d’une frontière de profil de déploiement, c’est-à-dire d’un point où la sortie réseau est substituée.
Ce contrôle n’a aucune option de désactivation et aucune liste d’exceptions. Le
critère d’acceptation de l’arbitrage AR-03 (specs/securite/arbitrages.md) est
zéro occurrence. Un symbole qui réapparaît se retire du graphe de modules ; il
ne se met pas sur une liste dérogatoire.
Le contrôle s’exécute dans .github/workflows/pr.yaml sur chaque proposition de
modification : les deux contrôles qui lisent les sources tournent sur chaque
proposition, avec l’option --sans-artefacts, et l’inspection des artefacts
construits tourne dans le job qui les construit. Le script est lui-même couvert
par scripts/verify-onprem-artifact.test.mjs.
Le détail des flux, côté produit, est décrit dans Où passent les données.
Les signatures
Section intitulée « Les signatures »Aucun artefact n’est livré sans signature. Les images de conteneurs, image de session comprise, et les composants du poste sont signés. La clé de signature vous est remise avec la première livraison, et son empreinte vous est communiquée par un canal distinct, ce qui permet de détecter une substitution. Les mises à jour se vérifient ensuite hors ligne, avant leur installation (livre blanc sécurité V3, sections 9.1 et 9.3).
À la publication d’une version, la signature est posée par cosign
(.github/actions/sign-release-blobs). Elle couvre aussi la nomenclature
CycloneDX des sources et le manifeste de livraison, qui liste chaque fichier
installable avec son empreinte SHA-256. Les signatures sont attachées à la
version, à côté des artefacts.
La livraison et les mises à jour
Section intitulée « La livraison et les mises à jour »Les artefacts vous parviennent par l’un de deux chemins (livre blanc sécurité V3, section 9.3) :
- en mode connecté, ils sont poussés dans votre registre privé ;
- en mode isolé, ils sont livrés sur média, sous forme d’archive signée, avec la nomenclature et la déclaration VEX.
Dans les deux cas, l’installation commence par la vérification des signatures avec la clé que vous détenez. Votre équipe applique ensuite l’installation ou la mise à jour : ni les services ni les extensions ne se mettent à jour seuls, et le produit ne dépend d’aucun service externe. La version précédente est conservée pour un retour arrière.
Les scénarios d’évasion
Section intitulée « Les scénarios d’évasion »Une batterie de scénarios d’évasion est exécutée avant chaque livraison, en six familles : sortie réseau depuis le bac à sable, lecture ou écriture hors de la copie du dépôt, modification d’un fichier exécuté par un tiers, injection d’instructions par un fichier du dépôt, épuisement de ressources, contournement de la politique de commandes. Le rapport d’exécution est joint à la version, au même titre que la nomenclature et la déclaration VEX, et une régression bloque la publication. Vous pouvez rejouer ces scénarios sur votre déploiement (livre blanc sécurité V3, section 9.2).
Signaler une vulnérabilité
Section intitulée « Signaler une vulnérabilité »Le canal est SECURITY.md, à la racine du dépôt : signalement par courriel à
security@lemniscate-tech.com, sans ouverture d’issue publique, avec
description, étapes de reproduction, appréciation de l’impact et mitigations
éventuelles.
C’est un canal de signalement, pas un programme de prime aux vulnérabilités. Ce qu’il ne porte pas est décrit dans Ce qui reste à construire.
Résumé des artefacts obtenables
Section intitulée « Résumé des artefacts obtenables »- Des artefacts signés, vérifiables hors ligne avec la clé qui vous est remise.
- Une nomenclature CycloneDX des sources, générée et validée par version.
- Le rapport des scénarios d’évasion joué sur la version livrée.
- Un dossier OpenVEX versionné, où chaque exclusion porte un auteur, une date et une justification du référentiel CISA ; le retrait est refusé par le code du dépôt si la justification manque.
- Des rapports de scan reproductibles : porte différentielle bloquante, scan complet hebdomadaire, secrets, images, dépendances après suppression VEX.
- Une politique de divulgation publiée, avec un canal dédié.
- Un contrôle « zéro symbole de sortie réseau » exécuté sur l’artefact construit, vérifiable par un tiers sans accès au code source.
- Une méthode de preuve traçable : 286 identifiants
SEC-*, statuts adossés à des preuvesfichier:ligne, arbitrages datés avec leurs options écartées (posture de conformité).