

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Guide du développeur de plugins
<a name="sbomgen-plugin-developer-guide"></a>

 Ce guide explique comment étendre le générateur Amazon Inspector SBOM (inspectors-sbomgen) avec des plugins Lua personnalisés. Les plugins vous permettent de prendre en charge de nouveaux écosystèmes de paquets sans modifier le code source de sbomgen ni avoir à le recompiler. 

 Pour le catalogue complet des fonctions, consultez le[Référence de l'API du plugin](sbomgen-plugin-api-reference.md). Pour obtenir des conseils sur la rédaction de tests, consultez le[Guide de test des plugins](sbomgen-plugin-testing-guide.md). 

## Présentation de
<a name="sbomgen-plugin-developer-guide-overview"></a>

 Les plugins Sbomgen sont écrits en Lua et suivent un pipeline en deux étapes : 
+ **Découverte** : scannez la liste des fichiers de l'artefact et signalez quels fichiers sont pertinents pour votre écosystème.
+ **Collection** — analyse chaque fichier découvert et transfère les résultats du package dans le SBOM.

### Modèle d'événement du plugin
<a name="sbomgen-plugin-developer-guide-plugin-event-model"></a>

 Les plugins de découverte ont besoin d'un moyen d'indiquer aux plugins de collection que des fichiers contenant des métadonnées de package ont été découverts dans l'artefact en cours d'inventaire. Pour faciliter ce partage de données, les plugins de découverte définissent un **nom d'événement** et renvoient une liste de chemins de fichiers. Les plugins de collection **s'abonnent** à cet événement et reçoivent chaque chemin de fichier correspondant. Cela permet de dissocier la détection des fichiers de l'analyse : un plugin de découverte peut alimenter plusieurs collecteurs (modèle de fan-out). Cependant, chaque plugin de découverte doit avoir un nom d'événement unique, et chaque plugin de collection doit avoir un nom de collecteur unique. Consultez [Règles de collision des plugins](#sbomgen-plugin-developer-guide-plugin-collision-rules) pour plus de détails. 

 Les développeurs peuvent le reconnaître comme le modèle de conception de l'**observateur**. 

 Cette conception permet à un seul plugin de découverte de déclencher plusieurs analyses indépendantes de manière performante. Par exemple, un plugin de découverte peut localiser chaque élément `requirements.txt` d'un artefact, puis alimenter : 
+ Un **collecteur de packages** qui analyse chaque ligne dans les résultats SBOM (). `name==version`
+ Un **collecteur de secrets** qui signale les lignes contenant des clés d'API ou des jetons accidentellement épinglés en tant que versions.
+ Un **collecteur de politiques** qui signale les spécificateurs de version non épinglés ou génériques.

 Chaque collecteur s'exécute indépendamment sur la même liste de fichiers sans avoir à modifier le système de fichiers de l'artefact. Cela permet également aux auteurs de plugins d'ajouter de nouveaux plugins de collection qui s'abonnent aux événements existants sans avoir à modifier le plugin de découverte correspondant. 

## Démarrage rapide : création de nouveaux plugins
<a name="sbomgen-plugin-developer-guide-quick-start-creating-new-plugins"></a>

 Le moyen le plus rapide de créer un nouveau plugin est d'utiliser la commande d'échafaudage intégrée : 

```
inspector-sbomgen plugin new
```

 La commande demande le nom du plugin et le répertoire du projet. Appuyez sur Entrée pour accepter la valeur par défaut indiquée entre crochets : 

```
Plugin name (identifies the software ecosystem your plugin will inventory, e.g. debian-dpkg, rhel-rpm, python-pip, cmake) [my-custom-ecosystem]: cmake
Project directory [my-sbomgen-plugins]:
```

 Vous pouvez également transmettre des arguments directement : 

```
inspector-sbomgen plugin new --name cmake --path /tmp/custom-plugins
```

### Commencer par un exemple pratique
<a name="sbomgen-plugin-developer-guide-starting-with-a-working-example"></a>

 Si vous souhaitez expérimenter avec des plugins avant d'écrire votre propre logique, créez un nouveau plugin en utilisant le `--with-example` drapeau : 

```
inspector-sbomgen plugin new --with-example
```

 Cela génère un projet de plugin entièrement fonctionnel avec un exemple d'analyseur de fichier de verrouillage, des données de test et des tests réussis. L'exemple de plugin découvre `example.lock` les fichiers, analyse les `name==version` entrées et envoie les packages dans le SBOM. Vous pouvez exécuter les tests immédiatement pour voir le système de plugins en action, puis modifier le code pour cibler votre écosystème actuel. 

 Pour un échafaudage avancé qui inclut toutes les fonctions de dérogation optionnelles (`get_scanner_name`,,, `get_event_name``get_scanner_groups`, découverte de plusieurs événements, etc.), utilisez le `--with-overrides` drapeau (nous y reviendrons plus loin) : 

```
inspector-sbomgen plugin new --with-overrides
```

### Compléter votre plugin
<a name="sbomgen-plugin-developer-guide-completing-your-plugin"></a>

 Après l'échafaudage, les fichiers de plug-in générés contiennent des `TODO` marqueurs indiquant où ajouter la logique spécifique à votre écosystème. Utilisez ces marqueurs pour transformer l'échafaudage en un plugin fonctionnel : 
+ Remplacez tous les `TODO` marqueurs par vos valeurs réelles
+ Mettez à jour le modèle de fichier `discover()` pour qu'il corresponde à vos fichiers cibles
+ Implémenter une logique d'analyse `collect()` et un appel `sbomgen.push_package()` pour chaque package

### Testez votre plugin
<a name="sbomgen-plugin-developer-guide-test-your-plugin"></a>

 Il existe deux manières de tester vos plugins : 

 **1. Harnais de test intégré** : `inspector-sbomgen plugin test` à utiliser pour valider la logique du plugin pendant le développement. Cela exécute vos fichiers de `init_test.lua` test sans avoir besoin d'un véritable artefact à scanner : 

```
inspector-sbomgen plugin test --path ./my-plugins
```

 Consultez le [Guide de test des plugins](sbomgen-plugin-testing-guide.md) pour plus de détails sur l'écriture de fichiers de test et l'utilisation de l'`testing.*`API. 

 **2. End-to-end**scan — Appelez votre plugin à l'aide des commandes standard sbomgen pour vérifier qu'il fonctionne avec de vrais artefacts. Pour cette approche, vous devez fournir à la fois un artefact contenant les fichiers que votre plugin cible (par exemple, un répertoire avec `requirements.txt` ou équivalent) et le chemin d'accès au répertoire de votre plugin : 

```
inspector-sbomgen directory \
    --path /path/to/test/dir \
    --plugin-dir ./my-plugins \
    --disable-native-scanners \
    -o sbom.json
```

 L'`--disable-native-scanners`indicateur garantit que seuls vos plugins Lua s'exécutent, ce qui facilite les tests sans sortie des scanners (natifs) intégrés. 

## Configuration de l'IDE
<a name="sbomgen-plugin-developer-guide-ide-setup"></a>

 Sbomgen fournit la complétion du code, la vérification de type et la documentation en ligne pour l'ensemble de l'`sbomgen.*`API dans VS Code. 

### VS Code avec serveur de langage Lua
<a name="sbomgen-plugin-developer-guide-vs-code-with-lua-language-server"></a>
+ [Installez l'extension Lua : sumneko.lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua)
+ Ouvrez n'importe quel `.lua` fichier dans votre projet de plugin

 Voilà tout\! La `plugin new` commande génère `.vscode/settings.json` et `library/sbomgen.lua` est automatiquement détectée par le serveur de langue Lua. Vous obtiendrez immédiatement : 
+ Complétion du code pour toutes les `sbomgen.*` fonctions
+ Indications de paramètres avec types
+ Survolez la documentation
+ Vérification du type

## Structure du répertoire des plugins
<a name="sbomgen-plugin-developer-guide-plugin-directory-structure"></a>

 Les plugins de découverte et de collecte Sbomgen doivent respecter la structure de répertoires suivante : 

```
{plugin-dir}/
├── discovery/
│   └── {platform}/
│       └── {category}/
│           └── {ecosystem}/
│               └── init.lua          # REQUIRED entrypoint
└── collection/
    └── {platform}/
        └── {category}/
            └── {ecosystem}/
                └── init.lua          # REQUIRED entrypoint
```

 Ces noms de répertoires ont une signification sémantique : sbomgen les utilise pour dériver les métadonnées par défaut de votre plugin, notamment le nom du scanner, le nom de l'événement, les groupes de scanners et le filtrage de plateforme. Cela réduit le nombre de tâches standard que les développeurs auraient autrement à écrire. Le choix des bonnes valeurs garantit que votre plugin s'intègre correctement au modèle de sélection et d'exécution du scanner de sbomgen. 

 Les sections ci-dessous explorent la structure du répertoire plus en détail, en fournissant des conseils sur le sens sémantique et les conventions. 

### Plateforme
<a name="sbomgen-plugin-developer-guide-platform"></a>

 Le répertoire de la plateforme contrôle les systèmes d'exploitation sur lesquels votre plugin s'exécute. 


| **Valeur** | **Quand l’utiliser** | 
| --- | --- | 
| cross-platform | Le plugin fonctionne sur n'importe quel système d'exploitation (la plupart des plugins) | 
| linux | Logique de détection spécifique à Linux | 
| windows | Logique de détection spécifique à Windows | 
| macos | Logique de détection spécifique à macOS | 

### Catégorie
<a name="sbomgen-plugin-developer-guide-category"></a>

 Le répertoire des catégories détermine les groupes de scanners par défaut assignés à votre plugin, qui détermine s'il s'exécute par défaut ou s'il nécessite une inscription explicite. Découvrez comment [Sélection du scanner](#sbomgen-plugin-developer-guide-scanner-selection) les groupes affectent l'exécution. 


| **Valeur** | **Groupes par défaut** | **Quand l’utiliser** | 
| --- | --- | --- | 
| proglang | programming-language-packages, pkg-scanner | Paquets de langage de programmation (pip, npm, maven, etc.) | 
| os | os, pkg-scanner | gestionnaires de paquets du système d'exploitation (dpkg, rpm, apk, etc.) | 
| extra-ecosystems | extra-ecosystems, pkg-scanner | Applications et environnements d'exécution (nginx, curl, wordpress, etc.) | 

 Si vous utilisez un nom de catégorie qui ne correspond à aucune des catégories ci-dessus, le nom de catégorie lui-même est utilisé comme groupe. 

### Écosystème
<a name="sbomgen-plugin-developer-guide-ecosystem"></a>

 Nom de l'écosystème de packages spécifique (par exemple`python-pip`,`python-poetry`,`debian-dpkg`,`curl`). Les noms avec trait d'union sont une convention courante, mais pas une obligation stricte. 

 Le nom du scanner et le nom du collecteur sont dérivés directement du nom du répertoire de l'écosystème. 

### Jumelage des noms de l'événement
<a name="sbomgen-plugin-developer-guide-event-name-pairing"></a>

 Les plugins de découverte et de collecte situés sur le même chemin de répertoire sont automatiquement associés. Par exemple, un plugin de découverte at `discovery/cross-platform/proglang/python-pip/` se couple automatiquement avec`collection/cross-platform/proglang/python-pip/`. 

 Vous pouvez contourner cela en définissant `get_event_name()` et `subscribe_to_event()` dans vos plugins. 

## Plug-ins Discovery
<a name="sbomgen-plugin-developer-guide-discovery-plugins"></a>

 Un plugin de découverte n'a besoin que de cette `discover()` fonction. Toutes les autres fonctions sont facultatives ; les valeurs par défaut sont dérivées du chemin du répertoire. 

 La plupart des plugins de découverte fonctionnent en localisant les fichiers dont les noms ou les chemins identifient un écosystème spécifique, par exemple, `requirements.txt` pour Python pip, `package.json` pour npm ou `Cargo.lock` pour Rust cargo. Les `sbomgen.find_files_by_*` fonctions effectuent cette correspondance en dehors de la machine virtuelle Lua, ce qui les rend nettement plus rapides que l'itération de la liste complète des fichiers dans Lua : 

```
-- REQUIRED: Scans the artifact and returns a table of file paths.
function discover()
    return sbomgen.find_files_by_name({"requirements.txt"})
end
```

 `discover()`doit renvoyer une table Lua (tableau) de chaînes. Si aucun fichier n'est trouvé, renvoyez une table vide`{}`. 

### Modèles de découverte courants
<a name="sbomgen-plugin-developer-guide-common-discovery-patterns"></a>


| **Objectif** | **Fonction recommandée** | 
| --- | --- | 
| Faites correspondre un ou plusieurs noms de fichiers exacts | sbomgen.find\_files\_by\_name({names}) | 
| Faites correspondre les noms de fichiers sans distinction majuscules/majuscules | sbomgen.find\_files\_by\_name\_icase({names}) | 
| Correspondance par suffixe de chemin (par exemple,/pom.properties) | sbomgen.find\_files\_by\_suffix({suffixes}) | 
| Correspondance par regex à chemin complet | sbomgen.find\_files\_by\_path\_regex({patterns}) | 
| Correspondance du nom de base de style global (par exemple,) \*.lock | sbomgen.glob\_find\_files(pattern) | 

 Lorsque votre logique nécessite un post-filtrage, par exemple en conservant les fichiers correspondant à un suffixe mais en excluant les répertoires de construction et de sortie, combinez un `find_files_by_*` appel avec une boucle Lua : 

```
function discover()
    local found = {}
    for _, f in ipairs(sbomgen.find_files_by_suffix({".conda-meta.json"})) do
        if not f:match("[/\\]%.cache[/\\]") then
            table.insert(found, f)
        end
    end
    return found
end
```

 Évitez `sbomgen.get_file_list()` le processus de découverte à moins qu'aucun autre outil de comparaison ne vous convienne : il copie tous les chemins dans la machine virtuelle Lua et peut prendre plusieurs secondes sur de gros artefacts. Consultez le [Référence de l'API du plugin](sbomgen-plugin-api-reference.md) pour plus de détails. 

### Découverte de plusieurs événements
<a name="sbomgen-plugin-developer-guide-multi-event-discovery"></a>

 Par défaut, tous les fichiers renvoyés par `discover()` sont publiés dans un seul événement (depuis`get_event_name()`). Si votre scanner doit acheminer différents fichiers vers différents collecteurs, renvoyez plutôt un tableau à clés : 

```
function discover()
    return {
        EventNameFoundCurl = sbomgen.find_files_by_name({"curl", "curl.exe"}),
        EventNameFoundLibcurl = sbomgen.find_files_by_name({"curlver.h"}),
    }
end
```

 Lors du `discover()` renvoi d'une table contenant des chaînes de clés, chaque clé est traitée comme un nom d'événement distinct et sa valeur (une table des chemins de fichiers) est publiée dans cet événement. Les plugins de collection s'abonnent à des événements spécifiques `subscribe_to_event()` comme d'habitude. 

 Ceci est rétrocompatible : le renvoi d'une table séquentielle fonctionne `{"file1", "file2"}` toujours en mode événement unique. La détection est automatique : les tables avec n'importe quelle chaîne de clés sont multi-événements, les tables avec uniquement des clés entières (ou vides) sont des tables à événement unique. 

 Lors de l'utilisation de plusieurs événements, `get_event_name()` il n'est pas utilisé pour la publication (les noms des événements proviennent des clés de table renvoyées). Cependant, il est toujours appelé pendant le chargement du plugin pour détecter les collisions. Il doit donc renvoyer une valeur unique ou être omis pour utiliser la valeur par défaut. 

### Fonctions de découverte facultatives
<a name="sbomgen-plugin-developer-guide-optional-discovery-functions"></a>

 Tous ces éléments ont des valeurs par défaut saines dérivées du chemin du répertoire. Définissez-les uniquement si vous devez remplacer : 


| **Fonction** | **Par défaut** | **Annuler lorsque...** | 
| --- | --- | --- | 
| get\_scanner\_name() | {ecosystem}(par exemple,python-pip) | Vous souhaitez un nom de scanner personnalisé | 
| get\_scanner\_description() | "Lua discovery plugin: {ecosystem}" | Vous souhaitez une description personnalisée | 
| get\_scanner\_groups() | Dérivé du répertoire des catégories | Vous avez besoin de groupes non standard | 
| get\_event\_name() | Dérivé du chemin du répertoire | Vous avez besoin d'un routage d'événements personnalisé | 
| get\_localhost\_scan\_paths() | Aucune | Votre plugin a besoin de chemins spécifiques scannés lors localhost des scans | 

### Chemins d'analyse de l'hôte local
<a name="sbomgen-plugin-developer-guide-localhost-scan-paths"></a>

 Lorsque sbomgen exécute une `localhost` analyse, il parcourt les répertoires spécifiés par l'utilisateur ainsi que les chemins par défaut déclarés par les scanners. Par défaut, les plugins de découverte Lua ne fournissent aucun chemin, de sorte que les fichiers situés en dehors des répertoires spécifiés par l'utilisateur n'apparaîtront pas dans la liste des fichiers. 

 Définissez `get_localhost_scan_paths()` pour renvoyer les répertoires ou les chemins de fichiers que le localhost walker doit inclure : 

```
function get_localhost_scan_paths()
    return {
        "/usr/bin",
        "/usr/local/bin",
    }
end
```

 Les chemins renvoyés sont ajoutés à la liste de scan du marcheur uniquement pendant les `localhost` scans ; ils n'ont aucun effet sur `container` `directory` les `archive` scans. 

### Chemins d'analyse spécifiques à la plate-forme
<a name="sbomgen-plugin-developer-guide-platform-specific-scan-paths"></a>

 Lorsque les fichiers qui vous intéressent se trouvent à différents emplacements sous Windows, macOS et Linux, branchez `sbomgen.get_platform()` et renvoyez les chemins appropriés pour l'hôte : 

```
function get_localhost_scan_paths()
    local platform = sbomgen.get_platform()

    if platform == sbomgen.platform.WINDOWS then
        local drive = sbomgen.get_system_drive()
        return {
            drive .. "/Program Files/MyApp/myapp.exe",
            drive .. "/Program Files (x86)/MyApp/myapp.exe",
        }
    end

    if platform == sbomgen.platform.DARWIN then
        return {"/Applications/MyApp.app/Contents/MacOS/myapp"}
    end

    -- Linux
    return {
        "/usr/bin/myapp",
        "/usr/local/bin/myapp",
    }
end
```

 Sous Windows, utilisez-le `sbomgen.get_system_drive()` pour résoudre la lettre du lecteur système (par exemple,`"C:"`) plutôt que de la coder en dur. Pour les chemins dérivés de variables d'environnement telles que `LOCALAPPDATA` ou`PROGRAMFILES`, itérez `sbomgen.get_env_vars()` et recherchez la valeur par clé. Consultez le [Référence de l'API du plugin](sbomgen-plugin-api-reference.md) pour plus de détails. 

## Plug-ins de collection
<a name="sbomgen-plugin-developer-guide-collection-plugins"></a>

 Un plugin de collecte n'a besoin que de `collect()` cette fonction. Toutes les autres fonctions sont facultatives. 

 `collect(file_path)`est appelé une fois par fichier découvert par le plugin de découverte jumelé. Le schéma typique est le suivant : 
+ **Lisez** le contenu du fichier en utilisant `sbomgen.read_file()` (pour les petits fichiers chargés en mémoire) ou `sbomgen.open_file()` (pour les gros fichiers lus line-by-line).
+ **Analyse le contenu** : correspondance de chaînes pour les manifestes simples, `sbomgen.json_decode()` pour le JSON, `sbomgen.xml_decode()` pour le XML ou `sbomgen.search_binary()` pour les binaires compilés.
+ **Publiez** chaque package découvert en appelant `sbomgen.push_package()` avec les métadonnées du package.

```
-- REQUIRED: Called once per discovered file.
-- Parse the file and call sbomgen.push_package() for each package found.
function collect(file_path)
    local content, err = sbomgen.read_file(file_path)
    if err or not content then return end

    for line in content:gmatch("[^\r\n]+") do
        local name, version = line:match("^([%w%-%_%.]+)==(.+)$")
        if name and version then
            sbomgen.push_package({
                name = name,
                version = version,
                purl_type = "pypi",
                component_type = sbomgen.component_types.LIBRARY,
            })
        end
    end
end
```

 `collect()`ne renvoie aucune valeur. Chaque `push_package()` appel nécessite `name``purl_type`, et`component_type`. Consultez le [Référence de l'API du plugin](sbomgen-plugin-api-reference.md) pour tous les champs pris en charge. 

### Joindre des métadonnées aux composants
<a name="sbomgen-plugin-developer-guide-attaching-metadata-to-components"></a>

 **Sbomgen propose deux méthodes pour associer des métadonnées à un composant de package : les **qualificatifs PURL** et les propriétés CyclonedX.** Ils ont des objectifs différents, et le choix entre les deux a une incidence sur la manière dont Amazon Inspector identifie les vulnérabilités dans le SBOM qui en résulte. 


| **Mécanisme** | **Où il apparaît** | **Utiliser pour** | 
| --- | --- | --- | 
| qualifiers | Dans l'URL du package (par exemple,pkg:deb/debian/curl@7.88.1?arch=amd64) | Données faisant partie de l'identité du package | 
| properties | Dans le tableau du SBOM components[].properties | Métadonnées descriptives qui ne modifient pas la façon dont le package est identifié | 

 **Recommandation : préférez les propriétés CycloneDx (sous votre propre espace de noms) pour les métadonnées personnalisées.** Les propriétés ne modifient pas l'identité d'un composant, elles ne peuvent donc pas avoir d'impact sur l'identification des vulnérabilités par Amazon Inspector. Réservez les qualificatifs PURL dans les cas où le type PURL de votre écosystème les exige. 

#### Qualifications PURL
<a name="sbomgen-plugin-developer-guide-purl-qualifiers"></a>

 Certains qualificatifs PURL ont une signification sémantique pour Amazon Inspector et influencent l'identification des vulnérabilités. Par exemple, sur les `deb` composants, Inspector utilise des qualificatifs tels que `arch` et `distro` pour sélectionner le bon flux de vulnérabilités ; sur les `generic` composants pour les fichiers binaires compilés, des qualificatifs tels que `go_toolchain` ou pour `rust_toolchain` identifier la chaîne d'outils utilisée. En définissant un qualificatif qu'Inspector ne reconnaît pas ou en omettant un qualificatif attendu, des vulnérabilités peuvent être ignorées ou mal attribuées. 

 Voir [Qu'est-ce qu'une URL de package ?](https://docs.aws.amazon.com/inspector/latest/user/sbom-generator-purl-sbom.html) dans le guide de l'utilisateur d'Amazon Inspector pour connaître les conventions de qualification reconnues par Inspector par type de PURL. 

 Définissez les qualificatifs via le `qualifiers` tableau sur `sbomgen.push_package()` : 

```
sbomgen.push_package({
    name = "curl",
    version = "7.88.1",
    purl_type = "deb",
    namespace = "debian",
    component_type = sbomgen.component_types.LIBRARY,
    qualifiers = {
        arch = "amd64",
        distro = "debian-12",
    },
})
```

 Définissez des qualificatifs uniquement lorsqu'ils correspondent aux attentes de l'inspecteur concernant le type de PURL. Si vous devez enregistrer des métadonnées qui ne font pas partie de l'identité du package, utilisez plutôt les propriétés CyclonedX. 

#### Propriétés de CycloneDx
<a name="sbomgen-plugin-developer-guide-cyclonedx-properties"></a>

 Les propriétés CycloneDx sont des annotations clé-valeur qui apparaissent dans le tableau du SBOM. `components[].properties` Ils décrivent un composant sans affecter la façon dont il est identifié. Ils constituent donc le choix le plus sûr pour les métadonnées définies par le plugin. 

 **Les `amazon:inspector:*` espaces de noms sont réservés à Amazon Inspector.** En particulier : 
+ `amazon:inspector:sbom_generator:*`— réservé à Sbomgen et à ses scanners intégrés.
+ `amazon:inspector:sbom_scanner:*`— réservé à l'API Amazon Inspector Scan.

 Les auteurs de plugins ne doivent pas émettre de clés dans ces espaces de noms réservés. Le fait d'y écrire peut interférer avec le comportement de l'inspecteur et peut être remplacé. Pour obtenir la liste complète des clés réservées, consultez la section [Utilisation des espaces de noms CycloneDX avec Amazon Inspector](https://docs.aws.amazon.com/inspector/latest/user/cyclonedx-namespace.html). 

 Utilisez votre propre espace de noms (généralement l'identifiant de votre organisation ou de votre plugin) lors de la définition des propriétés : 

```
sbomgen.push_package({
    name = "requests",
    version = "2.28.1",
    purl_type = "pypi",
    component_type = sbomgen.component_types.LIBRARY,
    properties = {
        ["acme:python:manifest_path"] = file_path,
        ["acme:python:pinned"] = "true",
        ["acme:python:source"] = "requirements.txt",
    },
})
```

#### Principales règles de dénomination
<a name="sbomgen-plugin-developer-guide-key-naming-rules"></a>

 Les clés de propriété sont traitées par sbomgen comme suit : 
+ Une touche **contenant deux points** est utilisée mot pour mot dans le SBOM. Incluez toujours au moins deux points dans vos clés afin de contrôler l'espace de noms.
+ Une clé qui **ne contient pas de deux-points** est automatiquement préfixée par `amazon:inspector:sbom_generator:` : elle est placée dans l'espace de noms réservé de l'Inspector. Évitez cette forme pour les propriétés personnalisées.

```
properties = {
    ["acme:my_plugin:detected_via"] = "lockfile",  -- used as-is (recommended)
    detected_via                   = "lockfile",  -- becomes "amazon:inspector:sbom_generator:detected_via" (avoid)
}
```

 Les `sbomgen.properties.*` constantes existent de telle sorte que les scanners officiels émettent des clés cohérentes dans l'espace de noms réservé. Ce ne sont pas des points d'extension pour les plugins personnalisés. Utilisez plutôt votre propre espace de noms. 

#### Propriétés et qualificatifs des composants enfants
<a name="sbomgen-plugin-developer-guide-properties-and-qualifiers-on-child-components"></a>

 Des composants indépendants `children` sont imbriqués. Chaque enfant possède ses propres `qualifiers` tables ; `properties` les métadonnées définies sur le parent ne se propagent pas aux enfants. Définissez des valeurs de manière explicite pour chaque enfant qui en a besoin. 

### Fonctions de collecte optionnelles
<a name="sbomgen-plugin-developer-guide-optional-collection-functions"></a>


| **Fonction** | **Par défaut** | **Annuler lorsque...** | 
| --- | --- | --- | 
| get\_collector\_name() | {ecosystem}(par exemple,python-pip) | Vous souhaitez un nom de collectionneur personnalisé | 
| get\_collector\_description() | chaîne vide | Vous souhaitez une description | 
| subscribe\_to\_event() | Dérivé du chemin du répertoire | Vous avez besoin d'un routage d'événements personnalisé | 

## Exécution de vos plugins
<a name="sbomgen-plugin-developer-guide-running-your-plugins"></a>

 Pour que les plugins produisent des métadonnées de package, sbomgen doit recevoir un artefact à scanner contenant les fichiers cibles de votre plugin (par exemple, un répertoire contenant `requirements.txt` des fichiers manifestes de package ou des fichiers équivalents). `package.json` 

### Utilisation de base
<a name="sbomgen-plugin-developer-guide-basic-usage"></a>

```
inspector-sbomgen <artifact type> <arguments> --plugin-dir /path/to/plugins
```

 Exemple : 

```
inspector-sbomgen directory --path /target -o /tmp/sbom.json --plugin-dir /path/to/plugins
```

### Lorsque les scanners natifs sont désactivés (mode LUA uniquement)
<a name="sbomgen-plugin-developer-guide-with-native-scanners-disabled-lua-only-mode"></a>

```
inspector-sbomgen directory --path /target --plugin-dir /path/to/plugins --disable-native-scanners -o sbom.json
```

### Avec journalisation détaillée
<a name="sbomgen-plugin-developer-guide-with-verbose-logging"></a>

```
inspector-sbomgen directory --path /target --plugin-dir /path/to/plugins --verbose -o sbom.json
```

## Liste des scanners disponibles
<a name="sbomgen-plugin-developer-guide-listing-available-scanners"></a>

 `list-scanners`À utiliser pour voir tous les scanners disponibles pour sbomgen. Cela inclut les scanners natifs intégrés, tous les plugins Lua officiels fournis avec sbomgen et tous les plugins Lua personnalisés que vous avez fournis via : `--plugin-dir` 

```
inspector-sbomgen list-scanners --plugin-dir /path/to/plugins
```

```
┌─────────────────────┬────────┬───────────────────────────────┬─────────────────────────────┐
│    SCANNER NAME     │ SOURCE │            GROUPS             │         DESCRIPTION         │
├─────────────────────┼────────┼───────────────────────────────┼─────────────────────────────┤
│ curl                │ custom │ extra-ecosystems              │ Discovers curl version      │
│                     │        │ pkg-scanner                   │ header files (curlver.h)    │
├─────────────────────┼────────┼───────────────────────────────┼─────────────────────────────┤
│ python-requirements │ custom │ pkg-scanner                   │ Discovers requirements*.txt │
│                     │        │ programming-language-packages │ files for Python pip        │
│                     │        │                               │ packages                    │
└─────────────────────┴────────┴───────────────────────────────┴─────────────────────────────┘
```

 La colonne SOURCE indique d'où provient chaque scanner : 


| **Source** | **Signification** | 
| --- | --- | 
| native | Scanner intégré fourni avec sbomgen | 
| official | Plugins Lua fournis avec sbomgen | 
| custom | Plugin Lua fourni par l'utilisateur et chargé via --plugin-dir | 

 Running `list-scanners` without `--plugin-dir` still inclut à la fois les deux `native` et les `official` scanners, qui sont toujours disponibles. Le `--plugin-dir` drapeau ajoute vos `custom` scanners à la liste. 

 Pour répertorier uniquement les scanners Lua sans scanners natifs : 

```
inspector-sbomgen list-scanners --plugin-dir /path/to/plugins --disable-native-scanners
```

## Sélection du scanner
<a name="sbomgen-plugin-developer-guide-scanner-selection"></a>

 Les plugins Lua Discovery participent au même modèle de sélection de scanner que les scanners natifs intégrés. Par défaut, sbomgen exécute tous les scanners dont les groupes correspondent aux groupes de scanners par défaut pour le type d'artefact. Vous pouvez remplacer cela par trois indicateurs : 

### Exécutez uniquement des scanners spécifiques
<a name="sbomgen-plugin-developer-guide-run-only-specific-scanners"></a>

 `--scanners`À utiliser pour exécuter uniquement les scanners nommés. Tous les autres scanners sont exclus : 

```
inspector-sbomgen directory --path /target \
    --plugin-dir /path/to/plugins \
    --scanners python-requirements \
    -o sbom.json
```

 Cela ne fait fonctionner que le `python-requirements` scanner. Vous pouvez transmettre plusieurs noms de scanner séparés par des virgules ou transmettre un nom de groupe de scanners (par exemple,`programming-language-packages`) pour activer tous les scanners appartenant à ce groupe. 

### Exclure des scanners spécifiques
<a name="sbomgen-plugin-developer-guide-exclude-specific-scanners"></a>

 `--skip-scanners`À utiliser pour exclure les scanners nommés lors de l'exécution de tout le reste : 

```
inspector-sbomgen directory --path /target \
    --plugin-dir /path/to/plugins \
    --skip-scanners python-poetry \
    -o sbom.json
```

 Cela exécute tous les scanners par défaut, à l'exception de`python-poetry`. Par exemple`--scanners`, cet indicateur accepte également les noms de groupes, de sorte que le passage `--skip-scanners programming-language-packages` désactive tous les scanners de ce groupe. 

**Note**  
`--scanners`et s'`--skip-scanners`excluent mutuellement. Le fait de passer les deux produit une erreur.

### Ajouter des scanners provenant de groupes autres que ceux par défaut
<a name="sbomgen-plugin-developer-guide-add-scanners-from-non-default-groups"></a>

 Le jeu de scanner par défaut dépend du type d'artefact numérisé (voir la matrice [Comment les groupes affectent la sélection](#sbomgen-plugin-developer-guide-how-groups-affect-selection) ci-dessous). Un scanner dont les groupes ne font pas partie de la configuration par défaut pour le type d'artefact ne s'exécutera pas si vous ne l'activez pas. `--additional-scanners`À utiliser pour ajouter des scanners à l'ensemble par défaut sans le remplacer : 

```
inspector-sbomgen directory --path /target \
    --plugin-dir /path/to/plugins \
    --additional-scanners my-extra-scanner \
    -o sbom.json
```

 Cela exécute tous les scanners par défaut pour le type d'artefact, en plus`my-extra-scanner`. L'indicateur accepte une liste de noms de scanneurs ou de groupes séparés par des virgules, et s'empile avec l'ensemble par défaut au lieu de le remplacer. Permet `list-scanners` de vérifier à quels groupes appartient un scanner. 

### Comment les groupes affectent la sélection
<a name="sbomgen-plugin-developer-guide-how-groups-affect-selection"></a>

 La `get_scanner_groups()` fonction de votre plug-in de découverte détermine les groupes auxquels appartient le scanner. Le fonctionnement par défaut d'un scanner dépend à la fois de ses groupes et du type d'artefact numérisé. La matrice ci-dessous indique quels groupes sont inclus dans le jeu de scanners par défaut pour chaque type d'artefact : 


| **Groupe** | **`directory` / `archive`** | **`container`** | **`localhost`** | **`volume`** | **`binary`** | 
| --- | --- | --- | --- | --- | --- | 
| os | — | ✓ | ✓ | ✓ | — | 
| programming-language-packages | ✓ | ✓ | ✓ | ✓ | — | 
| binary | ✓ | ✓ | — | — | ✓ | 
| extra-ecosystems | — | ✓ | ✓ | ✓ | — | 
| dockerfile | ✓ | ✓ | — | — | — | 
| custom | ✓ | ✓ | ✓ | ✓ | ✓ | 
| certificate | — | — | — | — | — | 
| machine-learning | — | — | — | — | — | 
| pkg-scanner | — | — | — | — | — | 

 A ✓ signifie que tous les scanners de ce groupe s'exécutent par défaut pour ce type d'artefact. A `—` signifie que le groupe n'est pas dans l'ensemble par défaut, de sorte que ses scanners ne s'exécutent que s'ils sont explicitement sélectionnés via `--scanners` ou`--additional-scanners`. 

 Détails importants : 
+ **`custom`**est toujours dans l'ensemble par défaut : les plugins personnalisés chargés via reçoivent `--plugin-dir` automatiquement le `custom` groupe, de sorte qu'ils s'exécutent par défaut quel que soit le type d'artefact.
+ **`extra-ecosystems`**est par défaut pour `container``localhost`, et `volume` scanne, mais pas pour `directory``archive`, ou `binary` scanne. Pour ces types, vous devez passer `--additional-scanners` (par nom ou par `extra-ecosystems` groupe) pour les inclure.
+ **`pkg-scanner`**est informatif : il marque un scanner comme un collecteur de packages dans lequel il doit être affiché`list-scanners`, mais ne provoque pas à lui seul le fonctionnement du scanner. Associez-le à un groupe d'exécution (par exemple,`programming-language-packages`) dans`get_scanner_groups()`.

 Par exemple, un plugin qui renvoie s'`{sbomgen.groups.EXTRA_ECOSYSTEMS, sbomgen.groups.PACKAGE_COLLECTOR}`exécutera par défaut lors des scans de conteneurs, de localhost et de volumes, mais nécessitera `--additional-scanners` (ou`--scanners`) des scans de répertoires, d'archives et de fichiers binaires. 

## Règles de collision des plugins
<a name="sbomgen-plugin-developer-guide-plugin-collision-rules"></a>

 Sbomgen applique des métadonnées uniques à tous les plugins chargés afin d'empêcher les remplacements silencieux et de garantir l'intégrité du SBOM. Lorsqu'une collision est détectée, le dernier plugin est **ignoré** et un avertissement est enregistré. 

### Ce qui est vérifié
<a name="sbomgen-plugin-developer-guide-what-is-checked"></a>


| **Metadonnées** | **Scope (Portée)** | **En cas de collision** | 
| --- | --- | --- | 
| Nom de l'événement Discovery (get\_event\_name) | Tous les plugins de découverte | Deuxième plugin ignoré | 
| Nom du scanner (get\_scanner\_name) | Tous les plugins de découverte | Deuxième plugin ignoré | 
| Nom du collectionneur (get\_collector\_name) | Tous les plugins de collection | Deuxième plugin ignoré | 

### Ce qui est autorisé
<a name="sbomgen-plugin-developer-guide-what-is-allowed"></a>

 Plusieurs plugins de collecte **peuvent** s'abonner au même événement via`subscribe_to_event()`. C'est le modèle de ventilation prévu : un plugin de découverte peut alimenter plusieurs collecteurs qui font chacun des choses différentes (par exemple, l'un extrait des packages, un autre détecte des secrets). 

### Éviter les collisions
<a name="sbomgen-plugin-developer-guide-avoiding-collisions"></a>

 Si deux plug-ins utilisent le même nom de scanner, le même nom d'événement ou le même nom de collecteur, le deuxième module chargé est ignoré. Pour résoudre les collisions, renommez les métadonnées en conflit en définissant la fonction de remplacement appropriée dans votre plugin (`get_scanner_name()`,`get_event_name()`, ou`get_collector_name()`). 

### Exemple d'avertissement de collision
<a name="sbomgen-plugin-developer-guide-collision-warning-example"></a>

```
[custom:python-pip] SKIPPED: discovery event name "EventNameFoundPythonRequirements"
is already registered by [official:python-pip]. Each discovery plugin must have a
unique event name. Rename get_event_name() in your plugin to use a unique name.
```

 L'avertissement vous indique quel plugin a été ignoré, quel plugin est entré en collision, quel plugin possède déjà ce nom et quelle fonction modifier. 

## Débogage
<a name="sbomgen-plugin-developer-guide-debugging"></a>

### Journalisation de la console
<a name="sbomgen-plugin-developer-guide-console-logging"></a>

 Les plugins peuvent émettre des messages vers la sortie de console de sbomgen à l'aide des fonctions suivantes : 


| **Fonction** | **Niveau** | **Visible par défaut ?** | 
| --- | --- | --- | 
| sbomgen.log\_debug(message) | DEBUG | Non, nécessite --verbose | 
| sbomgen.log\_info(message) | INFO | Oui | 
| sbomgen.log\_warn(message) | WARN | Oui | 
| sbomgen.log\_error(message) | ERROR | Oui | 

 Toutes les sorties de journal d'un plugin sont automatiquement préfixées avec la source et le chemin du plugin (par exemple,`[custom:python-pip]`), de sorte que les messages des différents plugins sont faciles à distinguer. `log_info``log_warn`, et `log_error` toujours imprimer ; `log_debug` n'imprime que lorsque sbomgen est invoqué avec. `--verbose` 

```
function discover()
    sbomgen.log_info("starting discovery")
    local files = sbomgen.find_files_by_name({"requirements.txt"})
    sbomgen.log_debug(string.format("matched %d files", #files))
    if #files == 0 then
        sbomgen.log_warn("no requirements.txt files found")
    end
    return files
end
```

### Points d'arrêt
<a name="sbomgen-plugin-developer-guide-breakpoints"></a>

 `sbomgen.breakpoint()`À utiliser pour suspendre l'exécution du plugin et le bloquer jusqu'à ce que vous appuyiez sur Entrée. Cela agit comme un débogueur rudimentaire : combinez-le avec des instructions de journal pour inspecter l'état à des points spécifiques. 

```
function discover()
    local files = sbomgen.find_files_by_name({"requirements.txt"})

    sbomgen.log_info(string.format("about to inspect %d files", #files))
    sbomgen.breakpoint("before file inspection — press Enter to continue")

    local found = {}
    for _, f in ipairs(files) do
        if not f:match("[/\\]tests[/\\]") then
            table.insert(found, f)
        end
    end

    sbomgen.log_info(string.format("kept %d files after filtering", #found))
    sbomgen.breakpoint("after filtering — press Enter to continue")

    return found
end
```

 Le message du point d'arrêt est imprimé sur stderr. L'exécution est interrompue jusqu'à ce que vous appuyiez sur Entrée, ce qui vous laisse le temps de consulter les résultats du journal. 

### Problèmes courants
<a name="sbomgen-plugin-developer-guide-common-issues"></a>


| **Symptôme** | **Cause** | **Corriger** | 
| --- | --- | --- | 
| Plugin non chargé | init.lua manquant | Assurez-vous que le point d'entrée existe à la bonne profondeur du répertoire | 
| « fonction requise manquante » | Faute de frappe dans le nom de la fonction | Vérifiez queget\_scanner\_name,get\_scanner\_description,get\_scanner\_groups, discoverget\_event\_name,get\_localhost\_scan\_paths,get\_collector\_name,collect, subscribe\_to\_event sont définis | 
| Le plugin de collection n'a jamais été appelé | Incompatibilité du nom de l'événement | Vérifiez get\_event\_name() et subscribe\_to\_event() renvoyez la même chaîne | 
| Aucun package dans SBOM | push\_packagenon appelé ou champs obligatoires manquants | Assurez-vous que namepurl\_type, et component\_type sont définis dans chaque push\_package appel (y compris pour les enfants). Utilisez sbomgen.component\_types.\* des constantes. | 
| Erreur d'exécution dans le plugin | Erreur Lua lors de l'exécution | Vérifiez la sortie de sbomgen pour les messages d'avertissement contenant les détails de l'erreur | 
| « IGNORÉ : le nom de l'événement de découverte... est déjà enregistré » | Un autre plugin utilise le même nom d'événement | Renommer get\_event\_name() en une valeur unique | 
| « IGNORÉ : le nom du scanner... est déjà enregistré » | Un autre plugin utilise le même nom de scanner | Renommer get\_scanner\_name() en une valeur unique | 
| « IGNORÉ : le nom du collectionneur... est déjà enregistré » | Un autre plugin utilise le même nom de collecteur | Renommer get\_collector\_name() en une valeur unique | 

## Référence d’API
<a name="sbomgen-plugin-developer-guide-api-reference"></a>

 Le catalogue complet des fonctions est conservé dans un document d'accompagnement : 

 **→ [Référence de l'API du plugin](sbomgen-plugin-api-reference.md)** 

 La référence d'API couvre toutes les `sbomgen.*` fonctions (E/S de fichiers, utilitaires binaires, sortie de package, regex, analyse structurée, registre Windows, journalisation, débogage), l'`testing.*`API disponible dans les fichiers de test, toutes les constantes intégrées (,, `properties` `groups``component_types`,`platform`) et le cycle de vie global du plugin. 

## Gestion des erreurs
<a name="sbomgen-plugin-developer-guide-error-handling"></a>

 Les fonctions d'API qui peuvent échouer renvoient deux valeurs :`value, err`. Sur le succès, `err` c'est`nil`. En cas d'échec, la première valeur est `nil` et `err` est une chaîne d'erreur. 

```
local content, err = sbomgen.read_file(path)
if err then
    sbomgen.log_error("failed to read " .. path .. ": " .. err)
    return
end
-- content is safe to use here
```

 Si un plugin génère une erreur Lua non gérée, sbomgen enregistre un avertissement et passe au fichier ou au plugin suivant. Les autres plugins ne sont pas concernés. 

## Restrictions relatives au sandbox
<a name="sbomgen-plugin-developer-guide-sandbox-restrictions"></a>

 Les plugins s'exécutent dans une machine virtuelle Lua en sandbox avec un accès limité à la bibliothèque standard : 


| **d'outils** | **Disponible** | **Remarques** | 
| --- | --- | --- | 
| base | ✓ | dofile,loadfile, loadstring sont supprimés | 
| string | ✓ | Manipulation complète des chaînes | 
| table | ✓ | Manipulation complète du tableau | 
| math | ✓ | Bibliothèque mathématique complète | 
| package | ✓ | require()limité au répertoire des plugins | 
| io | ✗ | Utilisez plutôt sbomgen.\* I/O des fonctions | 
| os | ✗ | Bloqué pour des raisons de sécurité | 
| debug | ✗ | Bloqué pour empêcher l'introspection des machines virtuelles | 
| coroutine | ✗ | Non chargé | 

 L'accès direct au système de fichiers via `io.open` ou n'`os.execute`est pas disponible. Toutes les opérations sur les fichiers doivent passer par l'`sbomgen`API, ce qui garantit un comportement cohérent entre les types d'artefacts et empêche les plug-ins d'accéder à des fichiers extérieurs à l'artefact. 

 `require()`peut charger des modules uniquement à partir de l'arborescence de répertoires du plugin. La traversée du répertoire parent est telle que `require("../shared")` bloquée. 

## Partage de code entre plugins
<a name="sbomgen-plugin-developer-guide-sharing-code-between-plugins"></a>

 Vous pouvez utiliser `require()` pour charger des modules d'assistance depuis le répertoire de votre plugin : 

```
my-ecosystem/
├── init.lua
└── helpers.lua
```

```
-- helpers.lua
local M = {}
function M.parse_version(s)
    return string.match(s, "(%d+%.%d+%.%d+)")
end
return M
```

```
-- init.lua
local helpers = require("helpers")

function subscribe_to_event() return "MyEvent" end

function collect(file_path)
    local content, err = sbomgen.read_file(file_path)
    if err then return end
    local version = helpers.parse_version(content)
    -- ...
end
```

 Les sous-répertoires avec `init.lua` sont également pris en charge : 

```
my-ecosystem/
├── init.lua
└── parsers/
    └── init.lua
```

```
local parsers = require("parsers")
```

 `require()`est limité au répertoire de votre plugin. Vous ne pouvez pas charger de modules à partir d'autres plugins ou chemins système. Les bibliothèques Lua tierces (par exemple, from LuaRocks) ne sont pas prises en charge : seuls les modules d'assistance locaux situés dans le répertoire du plugin peuvent être chargés. 