Maison > Article > développement back-end > Sécuriser les secrets de test avec pytest-mask-secrets
Garder la sécurité et la confidentialité des données sensibles est une priorité absolue dans le développement de logiciels. Les journaux d’applications, l’un des vecteurs de fuite les plus courants, sont soigneusement gardés pour éviter la présence de secrets. Les mêmes préoccupations et risques s’appliquent également aux journaux de tests, qui peuvent révéler des mots de passe ou des jetons d’accès. Les outils exécutant des flux de travail CI fournissent généralement des mécanismes permettant de masquer les données sensibles dans les journaux avec peu ou pas d'effort. Bien que cela soit très pratique, efficace et facile à utiliser, dans certaines situations, cela peut ne pas suffire.
Par exemple, GitHub Actions fait un bon travail en matière de gestion des secrets. Tout secret défini dans le flux de travail est automatiquement masqué de la sortie capturée, ce qui fonctionne à merveille. Cependant, comme tout système CI, il a ses limites. Si le rapport de sortie emprunte un chemin différent (par exemple, s'il est enregistré dans un fichier, si Junit est généré ou envoyé à un magasin de journaux distant), GitHub Actions n'a pas la possibilité d'inspecter le contenu et de masquer les secrets.
De plus, les tests ne s'exécuteront pas toujours dans le cadre d'un flux de travail CI, et même dans ce cas, les secrets devront peut-être être cachés. Imaginez que vous exécutez des tests localement et partagez un journal pour discuter d'un problème. Sans vous en rendre compte, vous incluez une URL avec votre jeton d'accès.
Par conséquent, disposer d'un mécanisme permettant de gérer les données sensibles dans les journaux de test est essentiel à tous les niveaux. La meilleure approche consiste à implémenter cela directement au niveau du test ou dans le cadre de test lui-même. Cela garantit que les secrets ne sont pas divulgués à partir de la source principale, empêchant ainsi leur transmission à travers le système.
Maintenir le masquage des secrets directement dans les tests peut être relativement coûteux et sujet aux erreurs, et ressemble souvent à une bataille perdue d'avance. Par exemple, imaginez que vous deviez concevoir une URL avec un jeton comme paramètre. Cette URL doit être rendue différemment pour être utilisée dans une requête par rapport à sa présence dans le journal.
En revanche, l'interception de la génération du rapport dans le cadre de test offre une opportunité idéale de s'accrocher au processus et de modifier les enregistrements pour éliminer les données sensibles. Cette approche est transparente pour les tests, ne nécessite aucune modification du code de test et fonctionne exactement comme la fonctionnalité de masquage des secrets dans les workflows CI : exécutez-la simplement et oubliez la gestion des secrets. Il automatise le processus, garantissant que les données sensibles sont protégées sans ajouter de complexité supplémentaire à la configuration du test.
C'est exactement ce que fait pytest-mask-secrets, évidemment lorsque pytest est utilisé pour l'exécution de tests. Parmi ses nombreuses fonctionnalités, pytest propose un système de plugins riche et flexible. À cette fin, il vous permet de vous connecter au processus juste avant la génération d'un journal, à un moment où toutes les données ont déjà été collectées. Cela facilite la recherche et la suppression des valeurs sensibles des enregistrements avant leur sortie.
Pour illustrer comment cela fonctionne, un exemple simple sera le plus efficace. Vous trouverez ci-dessous un test trivial qui ne représente peut-être pas un scénario de test réel, mais sert à démontrer assez bien les secrets du masque pytest.
import logging import os def test_password_length(): password = os.environ["PASSWORD"] logging.info("Tested password: %s", password) assert len(password) > 18
Dans cet exemple, il y a une assertion qui a le potentiel d'échouer (et elle échouera), ainsi qu'un message de journal qui inclut un secret. Oui, cela peut sembler idiot d'inclure un secret dans le journal, mais envisagez un scénario dans lequel vous avez une URL avec un jeton comme paramètre et où la journalisation de débogage détaillée est activée. Dans de tels cas, les bibliothèques telles que les requêtes pourraient par inadvertance enregistrer le secret de cette manière.
Maintenant, place aux tests. Tout d'abord, définissez le secret nécessaire à des fins de test :
(venv) $ export PASSWORD="TOP-SECRET"
Ensuite, lancez le test :
(venv) $ pytest --log-level=info test.py ============================= test session starts ============================== platform linux -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0 rootdir: /tmp/tmp.AvZtz7nHZS collected 1 item test.py F [100%] =================================== FAILURES =================================== _____________________________ test_password_length _____________________________ def test_password_length(): password = os.environ["PASSWORD"] logging.info("Tested password: %s", password) > assert len(password) > 18 E AssertionError: assert 10 > 18 E + where 10 = len('TOP-SECRET') test.py:8: AssertionError ------------------------------ Captured log call ------------------------------- INFO root:test.py:7 Tested password: TOP-SECRET =========================== short test summary info ============================ FAILED test.py::test_password_length - AssertionError: assert 10 > 18 ============================== 1 failed in 0.03s ===============================
Par défaut, la valeur secrète apparaît deux fois dans la sortie : une fois dans le message de journal capturé et de nouveau dans l'assertion ayant échoué.
Mais que se passe-t-il si pytest-mask-secrets est installé ?
(venv) $ pip install pytest-mask-secrets
Et configuré en conséquence. Il doit connaître la liste des variables d'environnement qui contiennent les secrets. Cela se fait en définissant la variable MASK_SECRETS :
(venv) $ export MASK_SECRETS=PASSWORD
Maintenant, relancez le test :
(venv) $ pytest --log-level=info test.py ============================= test session starts ============================== platform linux -- Python 3.12.4, pytest-8.3.2, pluggy-1.5.0 rootdir: /tmp/tmp.AvZtz7nHZS plugins: mask-secrets-1.2.0 collected 1 item test.py F [100%] =================================== FAILURES =================================== _____________________________ test_password_length _____________________________ def test_password_length(): password = os.environ["PASSWORD"] logging.info("Tested password: %s", password) > assert len(password) > 18 E AssertionError: assert 10 > 18 E + where 10 = len('*****') test.py:8: AssertionError ------------------------------ Captured log call ------------------------------- INFO root:test.py:7 Tested password: ***** =========================== short test summary info ============================ FAILED test.py::test_password_length - AssertionError: assert 10 > 18 ============================== 1 failed in 0.02s ===============================
Désormais, au lieu de la valeur secrète, des astérisques apparaissent partout où le secret aurait été imprimé. Le travail est terminé et le rapport de test est désormais exempt de données sensibles.
D'après l'exemple, il peut sembler que pytest-mask-secrets ne fait pas grand-chose de plus que ce que GitHub Actions fait déjà par défaut, ce qui rend l'effort redondant. Cependant, comme mentionné précédemment, les outils d'exécution de flux de travail CI masquent uniquement les secrets dans la sortie capturée, laissant les fichiers JUnit et autres rapports inchangés. Sans pytest-mask-secrets, des données sensibles pourraient toujours être exposées dans ces fichiers : cela s'applique à tout rapport généré par pytest. D'un autre côté, pytest-mask-secrets ne masque pas la sortie directe lorsque l'option log_cli est utilisée, les fonctionnalités de masquage des workflows CI sont donc toujours utiles. Il est souvent préférable d’utiliser les deux outils conjointement pour assurer la protection des données sensibles.
Ça y est. Merci d'avoir pris le temps de lire cet article. J'espère que cela a fourni des informations précieuses sur l'utilisation de pytest-mask-secrets pour améliorer la sécurité de votre processus de test.
Bon test !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!