Ce document explique comment créer un New plugin Threat Exchange et tirer le meilleur parti de votre écosystème de menaces en exploitant les fonctionnalités offertes par le module Threat Exchange. Pour créer un New guide du développeur, utilisez ce modèle.
Conditions préalables
Pour créer un plugin New, il vous faut
- Expérience en programmation Python 3.x (niveau intermédiaire).
- Accès à la plateforme Netskope Cloud Exchange.
- Accès à l'API ou au SDK Python du produit ou de la solution pour lequel vous devez écrire le plugin.
- Un compte avec une autorisation minimale pour le produit.
Module Threat Exchange
La plateforme Cloud Exchange (CE) et son module Threat Exchange sont dotés d'un riche ensemble de caractéristiques et de fonctionnalités qui permettent un haut degré de personnalisation. Nous vous recommandons donc de vous familiariser avec les différents aspects de la plateforme énumérés ci-dessous.
Note
Ce module permet de partager les données de Netskope avec des tiers et vice-versa.
Concepts et terminologie de Netskope
- Le moteur central : Le moteur central de l'EC gère les plugins tiers et leurs méthodes de cycle de vie, ainsi que les points d'extrémité de l'API pour interagir avec la plateforme afin d'effectuer diverses tâches.
- Module : Les zones de code fonctionnel qui invoquent des plugins spécifiques aux modules pour accomplir différents flux de travail. Threat Exchange est l'un des modules de Cloud Exchange.
- Plugin : Les plugins sont des paquets Python dotés d'une logique permettant d'extraire et d'envoyer des informations IoC sur les menaces vers/depuis des systèmes Threat Intel tiers, qui seront ensuite stockées dans Threat Exchange.
- Configurations de plugin : Les configurations de plugin sont les objets de classe de plugin configurés avec les paramètres requis et planifiés par le moteur central de Cloud Exchange pour tirer et pousser les informations IoC de Threat.
- Indicateurs (Threat IoCs) : les indicateurs sont des hachages de logiciels malveillants et des objets d'URL de sites malveillants collectés à partir de diverses plateformes Threat Intel et stockés dans la base de données Cloud Exchange.
Lignes directrices pour le développement
- Utilisez la structure du répertoire du paquet pour tout le code Python.
- Assurez-vous que toutes les bibliothèques tierces fournies avec le plugin ont fait l'objet d'une vérification des vulnérabilités connues.
- Assurez-vous de suivre les conventions standard du code Python : PEP 8 – Guide de style pour le code Python.
- Exécutez et vérifiez que le contrôle lint de flake8 passe avec le contrôle docstring activé. De même, la longueur maximale d'une ligne doit être de 80.
- Convertissez les valeurs d'horodatage au format lisible par l'homme (de l'époque à l'objet DateTime). Assurez-vous que l'heure affichée sur l'interface utilisateur correspond au fuseau horaire local.
- Si possible, ajoutez une valeur par défaut lors de l'ajout d'un paramètre de configuration dans le plugin.
- Pour les scripts/intégrations écrits en Python, veillez à créer des tests unitaires. Pour plus d'informations, consultez la rubrique Tests unitaires.
- L'architecture du plugin permet de stocker des états ; toutefois, évitez de stocker des objets volumineux pour la gestion des états.
- Vérifiez que votre code python ne présente pas de vulnérabilités.
- L'icône du plugin doit avoir une taille inférieure à 10 Ko. Veillez à utiliser le logo de l'entreprise (et non celui du produit) sur un fond transparent. La taille recommandée pour le logo est de 300 x 50 ou un format similaire.
- Utilisez le point de contrôle fourni par le noyau Threat Exchange plutôt que d'en mettre un en place vous-même.
- Suivez la structure du répertoire des plugins.
- Si la description du plugin contient un lien, il doit s'agir d'un lien hypertexte redirigeant vers la page de documentation.
- Les messages du logger et les messages Toast ne doivent pas contenir les valeurs des champs de type API Token et Password.
- La pagination doit toujours être prise en compte lors du développement d'une fonctionnalité dans un plugin.
- Veillez à ajouter un mécanisme de relance pour le code de statut 429.
- Veillez à mettre en correspondance les différents champs reçus lors des appels d'API avec le modèle de données de l'indicateur afin de tirer le meilleur parti du système. Les champs tels que la réputation, la première vue et les commentaires permettent à l'utilisateur du SOC de mieux comprendre les données dans les champs d'indicateurs lors de l'analyse des données.
- Veillez à cartographier le champ de commentaire qui donne plus de contexte à l'analyste SOC. Le champ commentaire peut inclure le nom du fichier (dans le cas de Hash).
- Utilisez le point de contrôle fourni par le noyau de Cloud Exchange plutôt que d'en mettre un en place par vous-même.
- Vérifiez toujours si le plugin supporte le mécanisme de push ou non et définissez la variable push_supported en conséquence dans le fichier manifest.json.
- Utilisez une validation appropriée pour les paramètres transmis à la méthode validate et fournissez le texte d'aide approprié pour tous les paramètres.
- Utilisez l'objet notifier pour émettre une notification en cas d'échec ou de situation critique (comme la limitation du taux ou le dépassement de la taille de la charge utile) afin d'informer l'utilisateur de l'état du plugin.
- Veillez à mettre en place un mécanisme de journalisation approprié avec l'objet logger transmis par la plateforme Cloud Exchange. Veillez à ce que la journalisation soit suffisante pour aider l'équipe d'exploitation à résoudre les problèmes. Assurez-vous que les données sensibles ne sont pas enregistrées ou divulguées dans la notification.
- Fournissez le texte d'aide approprié (infobulle) pour tous les paramètres. Si possible, veillez à expliquer la signification du paramètre dans l'infobulle.
- Il devrait y avoir un espace réservé pour les paramètres de configuration de type texte.
- Veillez à donner un nom et une description significatifs aux paramètres de configuration du plugin.
- Veillez à fournir un type de configuration approprié (texte, nombre, mot de passe, choix, multi-choix) aux paramètres de configuration.
- Veillez à utiliser la configuration du proxy et l'indicateur de validation du certificat SSL transmis par la plateforme CE lors de toute requête sortante (API/SDK).
- Veillez à collecter la valeur d'un paramètre non obligatoire à l'aide de la fonction .get() et fournir une valeur par défaut lors de l'utilisation de .get() méthode.
- Assurez-vous que le nom du répertoire du plugin (par exemple sample_plugin) correspond à celui du fichier manifest.json. champ id.
- L’Agent utilisateur doit être ajouté aux en-têtes lors de tout appel API. Format pour l’agent utilisateur :
netskope-ce-<ce_version>-<module>-<plugin_name>-<plugin_version>.Note
La version du plugin doit être récupérée dynamiquement et pour récupérer la chaîne Netskope-ce-<version>, utilisez la méthode définie par le noyau.
- Les champs Tokens API et Password ne doivent pas utiliser strip().
- Les messages du journal doivent commencer par<module> <app name> « <nom de l’application > ; Plugin [configuration_name] : ".
Exemple : « Plugin URE Crowdstrike [Nom de la configuration CrowdStrike] : <log_message> ». [Ceci est une suggestion, vous pouvez omettre le nom de la configuration]. (logger.info(“<module> <plugin_name> Plugin : <message>”))
- Lors de la consignation d'un journal d'erreurs, vous devez, si possible, ajouter la trace d'exécution de l'exception.
Utilisation :self.logger.error(error, details=traceback.format_exc()). - The Toast message should not contain the “<app_name> <module> Plugin:” in the message.
- Assurez-vous d'attraper les exceptions et les codes d'état appropriés pendant et après les appels à l'API.
- Le fichier CHANGELOG.md doit être mis à jour avec les balises appropriées telles que Added, Changed et Fixed ainsi qu'un message convivial approprié. Assurez-vous que le nom du fichier correspond exactement à CHANGELOG.md.
Écrire un plugin
Cette section explique le processus d'écriture d'un plugin à partir de zéro
Téléchargez le plugin d’exemple depuis le dépôt public Github NetskopeOSS.
Mise en place du développement
Python
Threat Exchange utilise Python3 (v3.7 et plus). Veillez à installer python3 dans votre environnement de développement. Pytest est utilisé pour exécuter des tests unitaires.
Bibliothèques Python incluses
Les bibliothèques Python suivantes sont incluses dans la plateforme Netskope Threat Exchange.
| Nom de la bibliothèque | Version |
|---|---|
| aiofiles | 22.1.0 |
| amqp | 5.1.1 |
| anyio | 3.6.2 |
| asgiref | 3.6.0 |
| attrs | 22.2.0 |
| azure-core | 1.26.2 |
| azure-storage-blob | 12.14.1 |
| bcrypt | 4.0.1 |
| boto3 | 1.26.51 |
| botocore | 1.29.51 |
| billiard | 3.6.4.0 |
| celery | 5.2.7 |
| cabby | 0.1.23 |
| cachetools | 5.2.1 |
| celerybeat-mongo | 0.2.0 |
| certifi | 2022.12.7 |
| cffi | 1.13.2 |
| chardet | 5.1.0 |
| charset-normalizer | 3.0.1 |
| click | 8.1.3 |
| click-didyoumean | 0.3.0 |
| click-plugins | 1.1.1 |
| click-repl | 0.2.0 |
| colorama | 0.4.6 |
| colorlog | 6.7.0 |
| cryptography | 39.0.0 |
| cybox | 2.1.0.21 |
| defusedxml | 0.7.1 |
| dnspython | 2.3.0 |
| docker | 6.0.1 |
| fastapi | 0.89.1 |
| furl | 2.1.3 |
| google-api-core | 2.11.0 |
| google-auth | 2.16.0 |
| google-cloud-core | 2.3.2 |
| google-cloud-pubsub | 2.13.12 |
| google-cloud-pubsublite | 1.6.0 |
| google-cloud-storage | 2.7.0 |
| google-crc32c | 1.5.0 |
| google-resumable-media | 2.4.0 |
| googleapis-common-protos | 1.58.0 |
| grpc-google-iam-v1 | 0.12.6 |
| grpcio | 1.51.1 |
| grpcio-status | 1.51.1 |
| gunicorn | 20.1.0 |
| h11 | 0.14.0 |
| idna | 3.4 |
| importlib-metadata | 6.0.0 |
| isodate | 0.6.1 |
| jmespath | 1.0.1 |
| jsonpath | 0.8 |
| jsonschema | 4.17.3 |
| kombu | 5.2.4 |
| libcst | 0.3.21 |
| libtaxii | 1.1.119 |
| lxml | 4.9.2 |
| mongoengine | 0.25.0 |
| mongoquery | 1.4.2 |
| more-itertools | 9.0.0 |
| MarkupSafe | 2.1.2 |
| memory-profiler | 0.61.0 |
| mixbox | 1.0.5 |
| msrest | 0.7.1 |
| multidict | 6.0.4 |
| mypy-extensions | 0.4.3 |
| netskopesdk | 0.0.25 |
| numpy | 1.23.5 |
| oauthlib | 3.2.2 |
| onelogin | 3.1.0 |
| ordered-set | 4.1.0 |
| orderedmultidict | 1.0.1 |
| overrides | 6.5.0 |
| pandas | 1.5.0 |
| packaging | 23.0 |
| passlib | 1.7.4 |
| pycparser | 2.21 |
| prompt-toolkit | 3.0.36 |
| proto-plus | 1.22.2 |
| protobuf | 4.21.12 |
| psutil | 5.9.4 |
| pydantic | 1.10.4 |
| pyasn1 | 0.4.8 |
| pyasn1-modules | 0.2.8 |
| PyJWT | 2.6.0 |
| pymongo | 4.3.4 |
| pyparsing | 3.0.9 |
| python-dateutil | 2.8.2 |
| pyrsistent | 0.15.6 |
| python-multipart | 0.0.5 |
| python3-saml | 1.15.0 |
| pytz | 2022.7.1 |
| PyYAML | 6.0 |
| requests | 2.28.2 |
| requests-oauthlib | 1.3.1 4.9 |
| rsa | 4.9 |
| six | 1.16.0 |
| starlette | 0.22.0 |
| sniffio | 1.3.0 |
| s3transfer | 0.6.0 |
| stix | 1.2.0.11 |
| taxii2-client | 2.3.0 |
| typing-inspect | 0.8.0 |
| typing-utils | 0.1.0 |
| typing_extensions | 4.4.0 |
| urllib3 | 1.26.14 |
| uvicorn | 0.20.0 |
| vine | 5.0.0 |
| wcwidth | 0.2.6 |
| weakrefmethod | 1.0.3 |
| websocket-client | 1.4.2 |
| Werkzeug | 2.2.2 |
| xmlsec | 1.3.11 |
| zipp | 3.11.0 |
| requests-mock | 1.7.0 |
Inclure des bibliothèques de plugins personnalisés
Netskope conseille de regrouper toutes les bibliothèques python tierces dont votre plugin aura besoin avec le paquetage du plugin lui-même. Pour réaliser ce regroupement, utilisez le programme d'installation pip ; il fournit un commutateur qui prend un répertoire en entrée. S'il est fourni, pip installera les paquets dans ce répertoire.
For example, the command shown below will install the cowsay package into the directory lib.
> pip install cowsay --target ./lib
Pour la documentation officielle à ce sujet, consultez https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-t.
Lors de l'importation de modules à partir du dossier lib ci-dessus, nous devons utiliser l'importation relative au lieu de l'importation absolue, comme indiqué ci-dessous :
rom .lib import cowsay
IDE
Les IDE recommandés sont PyCharm ou Visual Studio Code.
Structure du répertoire des plugins
Cette section décrit la structure typique des répertoires pour le plugin Threat Exchange.
/sample_plugin/ ├──__init__.py ├──CHANGELOG.md ├──icon.png ├──main.py ├──manifest.json
Exemple de contenu de plugin
- README.md : Le fichier README contient la documentation pour le cas d'utilisation de l'intégration du plugin.
- __init__.py : Chaque paquet de plugins est considéré comme un module python par le code de Cloud Exchange. Assurez-vous que chaque paquet de plugins contient le fichier vide "__init__.py" fichier.
- CHANGELOG.md : Ce fichier contient les détails de la mise à jour du plugin et doit être mis à jour avec les balises appropriées telles que Added, Changed, Fixed (Ajouté, Modifié, Corrigé) ainsi qu'un message convivial approprié.
- icon.png : Logo de l'icône du plugin, qui sera visible dans le chiclet du plugin et dans les cartes de configuration de l'interface utilisateur. Le logo doit avoir un fond transparent et une taille recommandée de 300*50 pixels ou un rapport d'aspect similaire.
- main.py : Ce fichier python contient la classe Plugin contenant l'implémentation concrète des méthodes pull, push et validate.
- manifest.json : Fichier manifeste pour le paquet de plugins contenant des informations sur tous les paramètres configurables et leurs types de données. Ce fichier contient également plus d'informations sur l'intégration du plugin.
Les fichiers listés ici sont obligatoires pour toute intégration de plugin, mais vous pouvez ajouter d'autres fichiers en fonction des exigences spécifiques de l'intégration.
Note: Assurez-vous que le nom du répertoire du plugin (par exemple sample_plugin) correspond à celui du fichier manifest.json. champ id.
CHANGELOG.md
C'est un fichier qui contient les détails de la mise à jour du plugin et qui doit être mis à jour avec les balises appropriées comme Added, Changed, Fixed (ajouté, modifié, corrigé) ainsi qu'un message convivial approprié.
- Ajouté : utilisez-le lorsque les fonctionnalités de New sont ajoutées.
- Corrigé : Utilisez-le lorsqu'un bogue/une erreur est corrigé(e).
- Changed : Utilisez-le lorsqu'il y a un changement dans l'implémentation existante du plugin.
Sample Changelog.md
# 1.0.1 ## Fixed - Fixed pagination when there are more than 10k Logs # 1.0.0 ## Added - Initial release.
Manifest.json
Il s'agit d'un fichier JSON qui stocke les méta-informations relatives au plugin, qui sont ensuite lues par le module Threat Exchange pour rendre le plugin dans l'interface utilisateur, ainsi que pour permettre au module Threat Exchange d'en savoir plus sur le plugin, y compris les paramètres de configuration requis, l'identifiant du plugin, le nom du plugin, etc.
- Chaque plugin doit contenir ce fichier avec les informations nécessaires pour que Threat Exchange puisse instancier l'objet Plugin correctement.
- Les paramètres courants du fichier manifest.json sont les suivants
- name : (string) Nom du plugin. (Obligatoire)
- id : (string) Id du paquet de plugins. Assurez-vous qu'il est unique pour tous les plugins installés dans le Cloud Exchange. L'ID doit correspondre au nom du répertoire du paquet de plugins. (Obligatoire)
- version : (string) Version du plugin. Utilisation d'un MAJOR.MINOR.PATCH (ex. 1.0.1) est encouragé, mais il n'y a pas de restrictions. (Obligatoire)
- description : (string) Description du plugin. Fournissez une description détaillée qui mentionne les capacités et les instructions d'utilisation du plugin, (ex. Ce plugin fonctionne avec le produit foo et extrait les hachages md5 et sha256 ainsi que le malURL vers Threat Exchange et les transmet au produit foo). Cette description apparaît sur la carte de configuration du plugin. (Obligatoire)
- push_supported : (booléen) Ce drapeau indique si le plugin supporte ou non la méthode push. S'il est défini sur false, les champs liés au partage ne seront pas affichés dans l'interface utilisateur. (optionnel, valeur par défaut : true)
- patch_supported : (booléen) Ce drapeau indique si le produit intégré prend en charge la déclaration incrémentielle des indicateurs. Certains produits (par exemple Les fonctionnalités de Netskope utilisant RESTAPIv1) s'attendent à ce que tous les indicateurs soient signalés à chaque fois. Dans ce cas, "patch_supported" doit être défini comme "False". ServiceNow permet également de partager les indicateurs un par un et conserve les indicateurs précédemment partagés. Dans ce cas, patch_supported devait être défini comme "True". (Obligatoire)
- configuration : (array) Array of JSON objects that contains information about all the parameters required by the plugin - their name, type, id, etc. Les paramètres communs des objets JSON imbriqués sont expliqués ci-dessous.
- label : Nom du paramètre. Ceci sera affiché sur la page de configuration du plugin. (Obligatoire)
- key : Clé unique du paramètre, qui sera utilisée comme clé dans l'objet dict python où la configuration du plugin est utilisée. (Obligatoire)
- type : Type de valeur du paramètre. Les valeurs autorisées sont "texte", "mot de passe", "nombre", "choix" et "multichoix". (Obligatoire) Pour plus de détails, reportez-vous aux types de paramètres de la configuration du plugin ci-dessous.
- default : La valeur par défaut de ce paramètre. Cette valeur apparaîtra dans la page de configuration du plugin sur l'interface utilisateur de Threat Exchange. Les types de données pris en charge sont "texte", "nombre" et "liste" (pour le type multichoix). (Obligatoire)
- obligatoire : Booléen qui indique si ce paramètre est obligatoire ou non. Si un paramètre est obligatoire, Threat Exchange UI ne vous laissera pas passer une valeur vide pour le paramètre. Les valeurs autorisées sont "true" et "false". (Obligatoire)
- description : Description du paramètre au niveau du texte d'aide qui peut donner plus de détails sur le paramètre et la valeur attendue. Cette chaîne apparaîtra dans la page de configuration du plugin en tant que texte d'aide. (Obligatoire)
- choix : Une liste d'objets JSON contenant la clé et la valeur comme clés JSON. Ce paramètre n'est pris en charge que par le "type" : "choix et multichoix".
Plugin Configuration Parameter Types
Assurez-vous que tous les paramètres de configuration du plugin sont listés dans la section de configuration de manifest.json pour le plugin.
Password Parameter
Utilisez ce paramètre pour stocker les secrets/mots de passe pour l'authentification avec les points d'extrémité de l'API. Les paramètres dont le mot de passe est un type auront une zone de texte de mot de passe dans la page de configuration du plugin et seront obscurcis et cryptés par la plateforme.
Exemple de JSON
"configuration": [
{
"label": "Api token",
"key": "api_token",
"type": "password"
},
]
Vue de la configuration du plugin :
![]() |
Text Parameter
Utilisez ce paramètre pour stocker des informations sous forme de chaîne, telles que base-url, nom d'utilisateur, etc. Ce paramètre aura une entrée de texte normale sur la page de configuration du plugin.
Exemple de JSON
"configuration": [
{
"label": "Tenant Name",
"key": "tenant_name",
"type": "text"
},
]
Vue de la configuration du plugin :
![]() |
Number Parameter
Utilisez ce paramètre pour stocker des valeurs numériques ou flottantes. Ce paramètre aura un champ de saisie numérique sur la page de configuration du plugin.
Exemple de JSON
"configuration": [
{
"label": "Maximum File hash list size in MB.",
"key": "max_size",
"type": "number"
},
]
Vue de la configuration du plugin :
![]() |
Choice Parameter
Use this parameter for storing any enumeration parameter values. This parameter will have a dropdown on the plugin configuration page.
Exemple de JSON
"configuration": [
{
"label": "Type of Threat data to pull",
"key": "ioc_type",
"type": "choice",
"choices": [
{
"key": "Both",
"value": ["malware", “malsite”]
},
{
"key": "Malware",
"value": "malware"
},
{
"key": "Malsite",
"value": "malsite"
}
]
},
]
Vue de la configuration du plugin :
![]() |
Après avoir sélectionné l'entrée.
![]() |
Multichoice Parameter
Utilisez ce paramètre pour stocker des valeurs à choix multiples. Ce paramètre aura une liste déroulante sur la page de configuration du plugin avec la possibilité de sélectionner plusieurs valeurs.
Exemple de JSON
"configuration": [
{
"label": "Severity",
"key": "severity",
"type": "multichoice",
"choices": [
{
"key": "Unknown",
"value": "unknown"
},
{
"key": "Low",
"value": "low"
},
{
"key": "Medium",
"value": "medium"
},
{
"key": "High",
"value": "high"
},
{
"key": "Critical",
"value": "critical"
}
],
"default": [
"critical",
"high",
"medium",
"low",
"unknown"
],
"mandatory": false,
"description": "Only indicators with matching severity will be saved."
}
]
Vue de la configuration du plugin :
![]() |
Toggle Parameter
Ce paramètre stocke une valeur booléenne ; la bascule activée est vraie et la bascule désactivée est fausse.
- Activer la vérification SSL : Cette variable doit être utilisée lors de tout appel API dans le plugin.
- Utiliser le proxy du système ('proxy') : Utilise le proxy système configuré dans les paramètres (par défaut) : Faux)
Vue de la configuration du plugin :
![]() |
Note
Ce paramètre est fourni par le Core, et il n'est pas autorisé à être ajouté à partir du fichier manifest.json des plugins.
main.py
Ce fichier python contient l'implémentation de base du plugin.
Importations standard
from netskope.integrations.cte.plugin_base import PluginBase, ValidationResult, PushResult from netskope.integrations.cte.models import Indicator, IndicatorType from netskope.integrations.cte.models.business_rule import Action, ActionWithoutParams
Variables de PluginBase
PluginBase donne accès à des variables qui peuvent être utilisées pendant le cycle de vie du plugin.
Méthodes. Voici la liste des variables.
| Nom de la variable | Usage | Description |
|---|---|---|
| self.logger | self.logger.error(“Message”)
self.logger.warn("Message") self.logger.info(“Message”) | Poignée du logger fournie par le noyau. Utilisez cet objet pour enregistrer les événements importants. Les journaux seront visibles dans les journaux d'audit de Cloud Exchange. Reportez-vous à la documentation sur la journalisation. |
| self.configuration | self.configuration.get(<nom-clé-attribut>)<attribute-key-name> | Représentation JSON de l'objet de configuration de l'instance de plugin. Utilisez-le pour accéder aux attributs de configuration tels que les informations d'authentification, les détails du serveur, etc. Utilisez le nom de la clé de l'attribut mentionné dans manifest.json. |
| self.last_run_at | Si self.last_run_at :
self.last_run_at.timestamp() Utilisez ce format pour convertir la dernière durée d'exécution en format d'époque. | Fournit l'horodatage de la dernière exécution réussie de la méthode d'extraction du plugin. Le noyau de Cloud Exchange maintient l'heure du point de contrôle après chaque exécution réussie de pull(). Pour la première exécution, la valeur sera None. Le type de données de l'objet est datetime. |
| self.storage | Cloud Exchange fournit au plugin un mécanisme pour maintenir l'état. Utilisez cet objet pour conserver tout état qui serait nécessaire lors d'appels ultérieurs. Le type de données de cet objet est python dict. | |
| self.notifier | self.notifier.info(“message”)
self.notifier.warn(“message”) self.notifier.error(“message”) | Cet objet fournit la gestion du notificateur du noyau Cloud Exchange. Utilisez cet objet pour envoyer une notification à la plateforme. Les notifications seront visibles sur l'interface utilisateur de Threat Exchange. Veillez à ce que le message contienne des informations résumées pour que l'utilisateur puisse les lire et prendre les mesures nécessaires.
Par exemple, un notificateur utilisé dans le plugin Netskope si la méthode push() dépasse la limite de 8MB du produit. |
| self.proxy | requests.get(url=url, proxies=self.proxy) | Gestion des paramètres proxy du système s'ils sont configurés, sinon {}. |
| self.ssl_validation | requests.get(url=url, verify=self.ssl_validation) | Valeur booléenne qui indique si la validation ssl est appliquée pour les appels à l'API REST. |
Classe de plugin
- La classe Plugin doit être héritée de la classe PluginBase. La classe PluginBase est définie dans Netskope.integrations.cte.plugin_base.
- Assurez-vous que la classe Plugin fournit une implémentation pour les méthodes "pull", "push" et "validate".
- La classe du plugin contiendra tous les paramètres nécessaires pour établir la connexion et l'authentification avec l'API tierce.
- Les constantes telles que PLUGIN_NAME, LIMIT, etc. doivent être déclarées.
"""Sample plugin implementation. This is a sample implementation of base PluginBase class. Which explains the concrete implemetation of the base class. """ from netskope.integrations.cte.plugin_base import PluginBase, ValidationResult, PushResult from netskope.integrations.cte.models import Indicator, IndicatorType from typing import List from datetime import datetime import requests PLUGIN_NAME = "<module> <plugin_name> Plugin class SamplePlugin(PluginBase): """SamplePlugin class having concrete implementation for pulling and pushing threat information. This class is responsible for implementing pull, push and validate methods with proper return types, so that it's lifecycle execution can be scheduled by the CTE core engine. """
Def Pull()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode met en œuvre la logique permettant d'extraire les IoC de la menace (Malware & Malsites) des points d'extrémité de l'API. Cette méthode est invoquée périodiquement.
- Assurez-vous qu'il est testable à l'unité.
- Utilisez le point de contrôle transmis par la plateforme Cloud Exchange en invoquant self.last_run_at Il renvoie l'objet Python datetime.datetime contenant l'heure à laquelle cette méthode a été exécutée avec succès pour la dernière fois.
- Utilisez la configuration du proxy transmise par la plateforme Cloud Exchange en invoquant self.proxy. Il renvoie l'objet dict python qui peut être utilisé directement avec le module de requêtes.
- Tous les paramètres de configuration pour l'authentification de l'API sont transmis en tant que python dict les reçoit en invoquant self.configuration.
- Tous les journaux sont enregistrés par l'objet self.logger avec le niveau de journal approprié (info, warn, error). Cet objet enregistre les journaux dans MongoDB et est accessible via des appels API.
- Use self.ssl_validation bool to enable/disable validation of the SSL server certificate.
- Renvoie la liste des objets Indicator (voir ci-dessous) qui contiennent les données reçues du point de terminaison de l'API.
- En cas d'échec, une erreur ou une exception de type approprié est soulevée et accompagnée d'un message adéquat.
def pull(self):
"""Pull the Threat information from the 3rd part Threat Intel systems.
Implement the logic of pulling Threat data from 3rd party apis and return the list of objects netskope.integrations.cte.models.Indicators on successful pull otherwise raises an exception.
Returns:
List[netskope.integrations.cte.models.Indicators]: List of indicator objects received from the 3rd-party Threat Intel Systems.
"""
# Load all the configured plugin parameters as python dict object.
# Use the key name provided in the manifest.json file for the configuration parameters to
# get the value of that particular parameter.
config = self.configuration
# get proxy settings dict, just the way requests module requires.
proxy_dict = self.proxy
# get the ssl_validation bool for enabling/disabling validation of SSL server certificates.
ssl_validation = self.ssl_validation
start_time = self.last_run_at # datetime.datetime object.
# How to use proxy dict and ssl_validation flag.
resp = requests.get("www.example.com", proxies=proxy_dict, verify=ssl_validation) # noqa: F841
# Get the logger object for logging purpose. This logger object logs all the logs to mongodb
# under the cte database logs collection. Log timestamp is automatically recorded by the logger library.
# Supported logging levels are info, warn and error.
logger = self.logger
logger.info(f"{PLUGIN_NAME}: Starting Pulling data for sample plugin.")
indicator_list = self.pull_data_from_3rd_party_api(config, logger)
logger.info(f"{PLUGIN_NAME}:logger.info("{PLUGIN_NAME}: Finished pulling data")
return indicator_list
Def Push()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode met en œuvre la logique permettant d'envoyer les informations IoC sur les menaces partagées par la plateforme Cloud Exchange aux points d'extrémité de l'API du produit.
- Elle reçoit tous les paramètres que la méthode Pull reçoit, ainsi que la liste des objets indicateurs de la plateforme Cloud Exchange en tant qu'argument de la méthode, qui doivent être partagés avec le produit d'intégration.
- Cette méthode sera invoquée lorsque la plateforme Cloud Exchange recevra un indicateur New d'une source et que le partage des indicateurs est configuré avec la configuration actuelle du plugin.
- Si l'API prend en charge la méthode PATCH pour partager les indicateurs, cette méthode ne recevra qu'un seul objet indicateur dans la liste. Dans le cas contraire, elle recevra tous les objets indicateurs renvoyés après l'application des filtres de partage sur tous les indicateurs de la base de données de la plateforme Threat Exchange.
- Veillez à gérer le cas où la taille maximale de la charge utile prise en charge par le point de terminaison de l'API est dépassée. Il peut y avoir plusieurs façons de traiter ce cas :
- Si le point de terminaison de l'API prend en charge plusieurs demandes avec une taille de charge utile fixe, envoyez les données par morceaux.
- Si le point de terminaison de l'API ne prend pas en charge les demandes multiples (c'est-à-dire nous pouvons le pousser en un seul appel API), soit le plugin peut ignorer les indicateurs restants et envoyer une notification à l'utilisateur pour qu'il ajuste les filtres de partage, soit il peut échouer avec l'erreur de dépassement de la taille de la charge utile.
- Retournez l'objet PushResult (Faites référence à la classe PushResult avec un indicateur de succès indiquant si l'opération Push a réussi ou non).
- Traitez toutes les exceptions avec la connexion et le code de réponse HTTP.
def push(self, indicators: List[Indicator]):
"""Push the Indicator list to the 3rd party Threat Intel systems.
Implement the logic of spliting the indicators list according to their type and push the data
to the 3rd party APIs. This method will be invoked while sharing the Threat information with 3rd party.
Args:
indicators (List[netskope.integrations.cte.models.Indicators]): List of Indicator objects to be pushed.
Returns:
netskope.integrations.cte.plugin_base.PushResult: PushResult object with success flag and Push result message.
"""
# Load all the configured plugin parameters as python dict object.
# Use the key name provided in the manifest.json file for the configuration parameters to
# get the value of that particular parameter.
config = self.configuration
# get proxy settings dict, just the way requests module requires.
proxy_dict = self.proxy
# get the ssl_validation bool for enabling/disabling validation of SSL server certificates.
ssl_validation = self.ssl_validation
# How to use proxy dict and ssl_validation flag.
resp = requests.get("www.example.com", proxies=proxy_dict, verify=ssl_validation) # noqa: F841
# Get the logger object for logging purpose. This logger object logs all the logs to mongodb
# under the cte database logs collection. Log timestamp is automatically recorded by the logger library.
# Supported logging levels are info, warn and error.
logger = self.logger
logger.info(f"{PLUGIN_NAME}: Starting Pulling data for sample plugin.")
push_result = self.push_data_to_3rd_party_api(config, logger, indicators)
logger.info("f"{PLUGIN_NAME}: Finished Pushing data for sample plugin.")
return push_result
Def Validate()
Il s'agit d'une méthode abstraite de la classe PluginBase.
-
- Cette méthode valide la configuration du plugin et les paramètres d'authentification transmis lors de la création d'une configuration de plugin.
- Cette méthode n'est appelée que lorsqu'une configuration New est créée ou mise à jour.
- Validez que tous les paramètres obligatoires sont transmis avec le type de données approprié.
<li">Validez les paramètres d’authentification et le point d’accès API pour garantir une exécution fluide du cycle de vie du plugin.
- Renvoie l'objet ValidationResult (voir la classe ValidationResult) avec un indicateur de succès signalant la réussite ou l'échec de la validation et le message de validation contenant la raison de l'échec de la validation.
def validate(self, data):
"""Validate the Plugin configuration parameters.
Validation for all the parameters mentioned in the manifest.json for the existence and
data type. Method returns the netskope.integrations.cte.plugin_base.ValidationResult object with success = True in the case
of successful validation and success = False and a error message in the case of failure.
Args:
data (dict): Dict object having all the Plugin configuration parameters.
Returns:
netskope.integrations.cte.plugin_base.ValidateResult: ValidateResult object with success flag and message.
"""
self.logger.info(f"{PLUGIN_NAME}: Executing validate method for Sample plugin")
if (
"secret_field_id1" not in data
or not data["secret_field_id1"]
or type(data["secret_field_id1"]) != str
):
self.logger.error(
f"{PLUGIN_NAME}: Validation error occurred Error: Secret Field1 is required with type string."
)
return ValidationResult(
success=False, message="Invalid Secret Field 1 provided.",
)
else:
return ValidationResult(
success=True, message="Validation Successful for Sample plugin"
)
Def get_actions()
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode doit renvoyer une liste de toutes les actions prises en charge (affichées en tant que cibles dans l'interface utilisateur) si le plugin prend en charge le partage d'indicateurs (c'est à dire manifest a push_supported=true) sinon il devrait renvoyer une liste vide.
- Ajoutez toutes les actions prises en charge dans la classe ActionWithoutParams et renvoyez une liste d'objets de la classe ActionWithoutParams.
- Si le plugin prend en charge le partage des indicateurs, cette méthode doit renvoyer au moins une action.
Si le manifeste contient push_supported=false :
def get_actions(self): """Get available actions. Returns: List[ActionWithoutParams]: List of ActionWithoutParams objects that are supported by the plugin. """ return []
Si le manifeste contient push_supported=true :
def get_actions(self): """Get available actions. Returns: List[ActionWithoutParams]: List of ActionWithoutParams objects that are supported by the plugin. """ return [ ActionWithoutParams(label=”Share Indicators”, value=”share”) ActionWithoutParams(label=”Add to Group”, value=”add”) ]
Def get_action_fields() :
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode doit renvoyer la liste des champs à afficher dans l'interface utilisateur lorsqu'une cible est sélectionnée dans la liste déroulante.
- Cette méthode doit être appelée après que l'utilisateur a sélectionné l'une des actions.
- Si l'action sélectionnée nécessite des paramètres, elle renvoie une liste de dictionnaires (où chaque dictionnaire est une entrée configurable), sinon elle renvoie une liste vide.
- Allez sur Manifest.json pour voir comment les champs sont définis.
Si le manifeste contient push_supported=false :
def get_action_fields(self, action: Action): """Get fields required for an action. Args: action (Action): Action object which is selected as Target. Return: List[Dict]: List of configurable fields based on selected action. """ return []
Si le manifeste contient push_supported=true :
def get_action_fields(self, action: Action):
"""Get fields required for an action.
Args:
action (Action): Action object which is selected as Target.
Return:
List[Dict]: List of configurable fields based on selected action.
"""
if action.value == “add”:
return [
{
“label”: “Group Name”,
“key”: “group_name”,
“type”: “text”,
“default”: “”,
“mandatory”: True,
“description”: “Name of group.”
}
]
else:
return []
Déf validate_action() :
Il s'agit d'une méthode abstraite de la classe PluginBase.
- Cette méthode valide l'action et ses paramètres.
- Cette méthode ne sera appelée que lorsque la configuration de partage New est créée ou que la configuration de partage existante est mise à jour.
- Validez que tous les paramètres obligatoires sont transmis avec le type de données approprié.
- Renvoie l'objet ValidationResult (voir la classe ValidationResult) avec un indicateur de succès signalant la réussite ou l'échec de la validation et le message de validation contenant la raison de l'échec de la validation.
- Si le plugin n'est pas pris en charge par push, il renvoie un objet ValidationResult avec un drapeau de réussite, sinon il vérifie les validations.
Si le manifeste contient push_supported=false :
def validate_action(self, action: Action): """Validate Action Parameters. Args: action (Action): Action object having all the configurable parameters. Return: netskope.integrations.cte.plugin_base.ValidateResult: ValidateResult object with success flag and message. """ return ValidationResult(success=True, message=”Validation successful.”)
Si le manifeste contient push_supported=true :
def validate_action(self, action: Action):
"""Validate Action Parameters.
Args:
action (Action): Action object having all the configurable parameters.
Return:
netskope.integrations.cte.plugin_base.ValidateResult: ValidateResult object with success flag and message.
"""
if action.value not in [“share”, “add”]:
return ValidationResult(
success=False, message=”Unsupported action provided.”
)
if action.value == “add”:
if action.parameters.get(“group_name”) is None:
return ValidationResult(
success=False, message=”Group Name should not be empty.”
)
return ValidationResult(
success=True, message=”Validation successful.”
)
Modèles de données
Cette section énumère les modèles de données et leurs propriétés.
IndicatorType Modèle
- Cette classe fournit le modèle de données Python pour un objet IndicatorType.
- Ce modèle comporte 3 champs : URL, SHA256, MD5 de type chaîne.
- Vous interagirez avec le modèle dans la méthode "push" en envoyant une liste d'indicateurs à une tierce partie.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| URL | string | Il peut être utilisé pour les URL |
| SHA256 | string | Il peut être utilisé pour les hachages de fichiers de type sha256. |
| MD5 | string | Il peut être utilisé pour les hachages de fichiers de type md5. |
from netskope.integrations.cte.models import ( Indicator,
IndicatorType,
SeverityType,
)
Indicator(
value=behavior_info.get("ioc_value"),
type=IndicatorType.SHA256,
comments=behavior_info.get("ioc_description", ""),
firstSeen=datetime.datetime.strptime(
behavior_info.get("timestamp"),
"%Y-%m-%dT%H:%M:%SZ",
),
lastSeen=datetime.datetime.strptime(
behavior_info.get("timestamp"),
"%Y-%m-%dT%H:%M:%SZ",
),
severity=self.get_severity_from_int(behavior_info.get("severity", 0)),
)
Modèle de type de gravité
- Cette classe fournit le modèle de données Python pour un objet SeverityType.
- Ce modèle comporte 5 champs : INCONNU, FAIBLE, MOYEN, FORT, CRITIQUE de type chaîne de caractères.
- Vous interagirez avec le modèle dans la méthode pull en renvoyant une liste d'indicateurs.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| UNKNOWN | string | Il peut être utilisé pour une gravité inconnue |
| LOW | string | Il peut être utilisé pour les cas de faible gravité |
| MEDIUM | string | Il peut être utilisé pour les cas de gravité moyenne |
| HIGH | string | Il peut être utilisé pour les cas de gravité élevée |
| CRITICAL | string | Il peut être utilisé pour les cas de gravité critique |
from netskope.integrations.cte.models import SeverityType if type(severity) is not int or severity == 0: return SeverityType.UNKNOWN if 10 <= severity <= 39: return SeverityType.LOW if 40 <= severity <= 69: return SeverityType.MEDIUM if 70 <= severity <= 89: return SeverityType.HIGH if 90 <= severity <= 100: return SeverityType.CRITICAL return SeverityType.UNKNOWN
Modèle ActionWithoutParams
- Cette classe fournit le modèle de données Python pour un objet ActionWithoutParams.
- Ce modèle comporte deux champs : l'étiquette et la valeur, de type chaîne de caractères.
- Vous interagirez avec le modèle dans la méthode get_actions en renvoyant une liste d'actions disponibles.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| label | string | Étiquette affichée sur l'interface utilisateur |
| value | string | Valeur du champ |
from netskope.integrations.cte.models.business_rule import ActionWithoutParams ActionWithoutParams( label="Add to Suspicious Object List", value="suspicious_object", )
- Cette classe fournit le modèle de données Python pour un objet Indicateur.
- La méthode Pull renvoie la liste des objets de la classe Indicator avec les informations reçues des appels API.
- Les valeurs prises en charge pour le champ type sont IndicatorType.MD5, IndicatorType.SHA256 et IndicatorType.URL. Les types MD5 et SHA256 sont utilisés pour représenter les indicateurs de logiciels malveillants et le type URL est utilisé pour représenter les indicateurs de sites malveillants.
- La valeur du champ "réputation" doit être comprise entre 1 et 10. La valeur par défaut des champs de saisie est 5, si elle n'est pas fournie. S'il est fourni (dans cet intervalle), le CTE l'acceptera et l'affichera.
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| value | string | Valeur de l'indicateur. Il peut s'agir de la valeur de hachage MD5/SHA256 dans le cas des indicateurs de logiciels malveillants, et du nom de domaine/de l'adresse URL dans le cas des indicateurs de sites malveillants. |
| type | Enum (IndicatorType) | Il peut s'agir de IndicatorType.MD5 ou IndicatorType.SHA256 dans le cas des indicateurs de logiciels malveillants, ou de IndicatorType.URL dans le cas des indicateurs de sites malveillants. |
| test | bool | Indique s'il s'agit d'un indicateur de test ou non.
Default – False |
| reputation | int | Score de réputation de l'indicateur.
Default – 5 |
| expiresAt | datetime.datetime | Délai après lequel l'indicateur sera marqué comme inactif par Cloud Exchange. |
| firstSeen | datetime.datetime | objet datetime.datetime indiquant la date à laquelle l'indicateur a été découvert pour la première fois.
Défaut - Heure actuelle du système au moment de la création de l'objet indicateur. |
| lastSeen | datetime.datetime | objet datetime.datetime indiquant quand l'indicateur a été découvert pour la dernière fois.
Défaut - Heure actuelle du système au moment de la création de l'objet indicateur. |
| commentaires | string | Chaîne de commentaires qui donne plus d'informations sur l'indicateur. |
| sévérité | Enum (Type de gravité) | Gravité de l'indicateur. Les valeurs possibles sont les suivantes :
SeverityType.LOW SeverityType.MEDIUM SeverityType.HIGH SeverityType.CRITICAL SeverityType.UNKNOWN |
| extendedInformation | string | Un lien menant à une source externe pour des informations plus détaillées concernant l'indicateur. La valeur de ce champ sera rendue sous forme d'URL cliquable dans l'interface utilisateur. Le schéma de l'URL doit être soit HTTP, soit HTTPS. |
from netskope.integrations.cte.models import Indicator, IndicatorType
Indicator(
value="md5hash", # md5 hash value of the indicator.
type=IndicatorType.MD5, # Type of indicator.
test=True, # Indicates whether it's test indicator or not. Defaults to False.
reputation=7, # Reputation score of Indicator. Defaults to 5.
# Time after which Indicator will be marked as inactive.
expiresAt=datetime.datetime(2022, 12, 23, 15, 22, 52, 667126),
# Time when the Indicator was discovered first time. Defaults to current time.
firstSeen=datetime.datetime(2017, 1, 11, 15, 22, 52, 667126),
# Time when the Indicator was discovered last time. Defaults to current time.
lastSeen=datetime.datetime(2019, 12, 23, 15, 22, 52, 667126),
# Comment which gives more information about the indicator.
comments="Indicator explanation",
),
Classe PushResult
- Cette classe contient le résultat de l'opération de poussée des indicateurs vers le point de terminaison de l'API produit.
- L'indicateur de réussite indique le résultat de l'opération de poussée et l'indicateur de message doit contenir un message d'erreur approprié en cas d'échec. (En cas de succès, un simple message de succès avec l'indicateur de succès True doit être renvoyé).
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| success | bool | indique le résultat de l'opération de poussée, qu'elle ait réussi ou échoué. |
| message | string | Le champ message indique l'erreur en cas d'échec. En cas de succès, il peut s'agir d'un simple message de réussite. |
from netskope.integrations.cte.plugin_base import PushResult
PushResult(
success=True,
message=" Successfully pushed data to 3rd party."
)
Classe ValidationResult
- Cette classe contient le résultat du processus de validation des paramètres de configuration du plugin transmis à l'objet Plugin lors de la création d'une configuration New pour le plugin.
- Assurez-vous que tous les paramètres transmis à la méthode validate sont validés par rapport au type de données et à la valeur.
- La méthode Validate renvoie l'objet de cette classe avec un drapeau de réussite indiquant le résultat de l'opération de validation et le champ message contient le message d'erreur approprié en cas d'échec de la validation. (En cas de succès, un simple message de succès avec l'indicateur de succès True doit être renvoyé).
Propriétés du modèle de données
| Nom | Type | Description |
|---|---|---|
| success | bool | indique le résultat de l'opération de validation, qu'elle ait réussi ou échoué. |
| message | string | Le champ message indique l'erreur en cas d'échec. En cas de succès, il peut s'agir d'un simple message de réussite. |
from netskope.integrations.cte.plugin_base import ValidationResult
ValidationResult(
success=True,
message="Validation Successfull for Sample plugin"
)
Enregistrement
Cloud Exchange fournit un objet logger pour la journalisation.
- Évitez les instructions d'impression dans le code.
- Cet objet est enregistré dans la base de données centrale Cloud Exchange avec le champ d'horodatage. Les niveaux de journalisation pris en charge sont
info,warneterror. - Assurez-vous que le secret d'authentification de l'API ou toute autre information sensible n'est pas exposé dans les messages du journal.
- Veillez à mettre en œuvre un mécanisme de journalisation approprié avec l'objet logger transmis par la plate-forme CE.
- Assurez-vous que la journalisation est suffisante pour aider l'équipe d'exploitation à résoudre les problèmes.
- Assurez-vous que les données sensibles ne sont pas enregistrées ou divulguées dans la notification ou les journaux.
self.logger.error(
f"{PLUGIN_NAME}: Error log-message goes here."
)
self.logger.warn(
f"{PLUGIN_NAME}: Warning log-message goes here."
)
self.logger.info(
f"{PLUGIN_NAME}: Info log-message goes here."
)
Notifications
Cloud Exchange fournit un handle de l'objet de notification, qui peut être utilisé pour générer des notifications sur l'interface utilisateur de Cloud Exchange.
- Cet objet est transmis de Cloud Exchange à l'objet plugin. Chaque intégration de plugin peut utiliser cet objet en cas d'échec, qui doit être notifié immédiatement à l'utilisateur. L'horodatage de la notification est géré par Cloud Exchange.
- Cet objet affichera une notification dans l'interface utilisateur, avec un code couleur indiquant la gravité de la panne. Les niveaux de gravité des notifications pris en charge sont
info,warn, eterror. - Assurez-vous que le secret d'authentification de l'API ou toute autre information sensible n'est pas exposé dans les messages de notification.
- Utilisez un objet notificateur pour déclencher une notification en cas d'échec ou de situation critique (comme la limitation du débit ou le dépassement de la taille de la charge utile) afin d'informer l'utilisateur de l'état du plugin.
self.notifier.info(
f"{PLUGIN_NAME}: Info notification-message goes here."
)
self.notifier.error(
f"{PLUGIN_NAME}: Error notification-message goes here."
)
self.notifier.warn(
f"{PLUGIN_NAME}: Warning notification-message goes here."
)
Tagging
Threat Exchange fournit une classe utilitaire pour gérer les fonctionnalités liées au balisage à partir des méthodes push/pull/validate du plugin. Vous trouverez ci-dessous quelques exemples de son utilisation.
Créez une étiquette New
from netskope.integrations.cte.models import TagIn from netskope.integrations.cte.utils import TagUtils utils = TagUtils() utils.create_tag(Tag(name="Tag Name", color="#FF0000"))
Rechercher si une étiquette avec un nom donné existe déjà
utils = TagUtils()
if utils.exists("Tag Name"):
pass # tag already exists
Enlever une étiquette de certains indicateurs
utils = TagUtils()
utils.on_indicators({
"source": "Test"
}).remove("Tag Name")
Cette opération supprime la balise Tag Name de tous les indicateurs dont la source est "Test". Le premier et unique argument de "on_indicators" est un objet "dict". Il doit s'agir d'une requête Mongo valide.
Ajouter une étiquette à certains indicateurs
utils = TagUtils()
utils.on_indicators({
"source": "Test"
}).add("Tag Name")
Testing
Linting
Dans le cadre du processus de construction, nous exécutons quelques linters pour détecter les erreurs de programmation courantes, les erreurs stylistiques et les éventuels problèmes de sécurité.
Flake8
Il s'agit d'un linter de base. Il peut être exécuté sans que toutes les dépendances soient disponibles et il détectera les erreurs les plus courantes. Nous utilisons également ce linter pour appliquer le style de formatage standard python pep8. En de rares occasions, vous pouvez être amené à désactiver une erreur/un avertissement renvoyé(e) par ce lecteur. Pour ce faire, ajoutez un commentaire en ligne de ce type sur la ligne où vous souhaitez désactiver l'erreur :
# # noqa: <error-id>
Par exemple :
example = lambda: 'example' # example = lambda: 'example' # noqa: E731
Lorsque vous ajoutez un commentaire en ligne, indiquez toujours le code d'erreur pour lequel vous désactivez la fonction. Ainsi, si d'autres erreurs apparaissent sur la même ligne, elles seront signalées.
Voir : https://flake8.pycqa.org/en/latest/user/violations.html#in-line-ignoring-errors
La vérification des chaînes de documentation à la manière de PEP8 est également activée avec le linter flake8. Veillez donc à ce que chaque fonction/module soit accompagné d'une docstring appropriée.
Tests unitaires
Assurer des tests unitaires pour tester de petites unités de code de manière isolée et déterministe. Veillez à ce que les tests unitaires évitent de communiquer avec des API externes et à ce qu'ils utilisent la technique du "mocking". Assurez-vous que les tests unitaires garantissent une couverture du code supérieure à 70%.
Configuration de l'environnement
Pour travailler avec les tests unitaires, le script d’intégration ou d’automatisation doit être développé en suivant la structure du répertoire des plugins. Nous utilisons PIP pour installer toutes les dépendances des modules Python nécessaires à l’exécution de la configuration. Avant de lancer les tests, assurez-vous d’installer toutes les dépendances nécessaires mentionnées dans les requirements.txt du référentiel central Cloud Exchange.
Écrire vos tests unitaires
Assurez-vous que les tests unitaires sont écrits dans un fichier Python séparé nommé : <your_plugin_name>_test.py. Dans le fichier de test unitaire, chaque fonction de test unitaire doit porter le nom : test_.<your test case> Plus d’informations sur la rédaction de tests unitaires et leur format sont disponibles sur PyTest Docs.
Mocking
Utilisez pytest-mock pour la simulation. pytest-mock est activé par défaut et installé dans l'environnement de base mentionné ci-dessus. Pour utiliser un objet mocker, il suffit de le passer en paramètre à votre fonction de test. Le simulateur peut alors être utilisé pour simuler à la fois l'objet de classe du plugin et les API externes.
Exemple :
def test_netskope_pull_success(mocker):
mocker.patch("cte.plugins.netskope.main.NetskopePlugin.pull")
pull_return_result = [
Indicator(value="ind1", type=IndicatorType.MD5),
Indicator(value="ind2", type=IndicatorType.SHA256),
Indicator(value="ind3", type=IndicatorType.URL),
]
NetskopePlugin.pull.return_value = pull_return_result
ns = NetskopePlugin(None, None, None, logger)
actual_pull = ns.pull()
assert pull_return_result == actual_pull
Pour simuler la réponse du module de demande pour les appels API (le plugin requests_mock Pytest est installé avec toutes les dépendances) :
def test_fetch_threat_data_malware(requests_mock):
endpoint_url = "https://example-api.com"
mock_response_json = {
'status': 'success',
'data': [
{
'local_md5': 'ind1',
},
{
'local_md5': 'ind2',
},
{
'local_md5': 'ind3',
},
]
}
requests_mock.get(endpoint_url, json=mock_response_json)
config_dict = {
"api_token": "abc",
"tenant_name": "partners",
"file_list": "test",
"url_list": "sample",
"threat_data_type": "URL",
"is_pull_required": "Yes",
"max_file_hash_cap": 8,
"max_url_list_cap": 8,
}
ns = NetskopePlugin(config_dict, None, None, logger)
actual_ind_list = ns.fetch_threat_data(
endpoint_url,
config_dict['api_token'],
datetime.datetime.now(),
time.time(),
"malware"
)
indicator_list = [
Indicator(value="ind1", type=IndicatorType.MD5),
Indicator(value="ind2", type=IndicatorType.MD5),
Indicator(value="ind3", type=IndicatorType.MD5),
]
assert len(actual_ind_list) == len(indicator_list)
for i in range(len(actual_ind_list)):
assert actual_ind_list[i].value == indicator_list[i].value
Exécutez vos tests unitaires
$ PYTHONPATH=. pytest
Déployer le plugin sur Cloud Exchange
Paqueter le plugin
Cloud Exchange s'attend à ce que le plugin développé soit au format zip ou tar.gz.
Exécutez cette commande pour compresser le paquet :
zip -r sample_plugin.zip sample_plugin
Exécutez cette commande pour générer le paquet tar.gz :
tar -zcvf sample_plugin.tar.gz sample_plugin
Télécharger le plugin
Utilisez le fichier zip ou tar.gz pour déployer le plugin.
- Dans Cloud Exchange, accédez à Setting > Plugins.

- Cliquez sur Add New Plugin.

- Cliquez sur Browse.
- Select le fichier zip ou tar.gz.

- Cliquez sur Upload.
Note
Ce plugin n'est pris en charge que pour le module Threat Exchange.
Add a Repository
Pour déployer votre plugin sur la plateforme Cloud Exchange, vous pouvez ajouter un dépôt pour stocker votre plugin.
- Dans Cloud Exchange, accédez à Setting > Plugin Repository.

- Cliquez sur Configure New Repository.

- Saisissez un nom de référentiel, une URL de référentiel, un nom d'utilisateur et un jeton d'accès personnel.
- Cliquez sur Save.

- Allez sur Settings > Plugins.
- Select le nom du référentiel dans la liste déroulante Référentiel.









