Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problème
La CI échouait avant qu'un seul test ne s'exécute : 7 erreurs de collecte,
Interrupted: 7 errors during collection, exit code 2.Le
ERROR: Coverage failure: total of 17 is less than fail-under=38du même log est une conséquence, pas une seconde panne : aucun test n'ayant tourné, la couverture mesurée était celle des seuls modules importés. Aucun ajustement de seuil n'est nécessaire.Cause racine
services/component_sbom.pycréaitSBOM_DIR(/repos/sbomspar défaut) au niveau module.routers/upload.pyimporte ce module etrouters/__init__.pyimporteupload: le moindreimport routers.*tentait donc unmkdirsur/repos, non inscriptible pour l'utilisateur non-root d'un runner GitHub.Six autres modules avaient le même motif (
manifest,audit,indexer,pending_promotions,cve_enrichment,routers/upload). Ils ne cassaient pas encore parce que chaque fichier de test redéclare individuellementMANIFEST_DIR,AUDIT_DIR, etc. viaos.environ.setdefaulten tête de module.SBOM_DIRétait simplement plus récent que ces déclarations. La panne était donc structurelle : tout nouveauX_DIRajouté au graphe d'import cassait la CI de la même façon.Correctif
Convention appliquée à l'ensemble des modules concernés : importer un module ne doit jamais toucher au filesystem. Les répertoires sont créés à la première écriture, dans la fonction qui écrit.
services/component_sbom.pysave_component_sbom()services/manifest.pysave_manifest()services/audit.pylog()services/indexer.py_save_index()services/pending_promotions.pycreate_pending()services/cve_enrichment.py_save_json()(déjà présent, mkdir d'import redondant)routers/upload.py_ensure_upload_dirs(), appelé par les deux handlers POSTL'alternative envisagée (centraliser les variables d'environnement dans
tests/conftest.py) a été écartée : 29 des 37 fichiers de test utilisent leur_TMPlocal au-delà des appelssetdefault, queconftestrendrait silencieusement inopérants. Le correctif côté modules ne touche aucun test existant.Garde-fou
tests/test_no_import_side_effects.py(nouveau) :astdeservices/,routers/,auth/,db/: échoue si unmkdir/makedirs/touch/write_text/write_bytesréapparaît au niveau module. Descend dans lesfor/if/tryde premier niveau (le casrouters/upload.py) mais jamais dans un corps de fonction. N'importe aucun module inspecté, ce qui serait précisément l'effet de bord testé ;mkdirdifféré, ils lèventFileNotFoundError. Ils couvrent notamment les deux cas sansmkdirdédié,_save_json()(unique point d'écriture du module) etupdate_pending()(sort enNoneavant l'écriture si le fichier n'existe pas, donc ne peut jamais être le premier writer).Impact production
Aucun changement de comportement. Les répertoires sont créés au premier usage au lieu du démarrage. Vérifié :
Path.glob/rglob/.exists(), qui renvoient vide sur un répertoire absent (pas deos.listdir, qui lèverait) ;StaticFilessur ces chemins (un montage échouerait au démarrage sur répertoire absent) ;pool/,dists/,conf/,db/par bind mount docker-compose, créés par Docker indépendamment du backend.Vérification
Exécuté dans un conteneur
python:3.10-slim, utilisateur non-root (--user 1000:1000), reproduisant les conditions du runner. En root le bug ne se reproduit pas :/reposest créable.Required test coverage of 38% reached. Total coverage: 50.19%;import routerset les 6 modules touchés avec zéro variable d'environnement sur un/non inscriptible : OK,/reposjamais créé ;ruff check .: All checks passed.