================================================================================ PREUVE QA — Ticket #42 « Endpoint Aggregator /api/projects/{key}/soups » Epic parent #28 | Repo: omdev/aggregator | Branche: feat/42-soups-endpoint PR aggregator#4 -> dev | Date: 2026-06-11 Agent: QA manuel (#25). Aucun secret n'est inclus dans cette preuve. ================================================================================ PERIMETRE - Smoke test du read-plane aggregator : adaptateur Dependency-Track (DTrack) + endpoint GET /api/projects/{key}/soups + flag healthz `dtrack`. - Gate aggregator (CLAUDE.md) : `python -m pytest -q` et `ruff check .` verts (mypy NON inclus dans le gate aggregator). -------------------------------------------------------------------------------- 1) SUITE COMPLETE PYTEST -------------------------------------------------------------------------------- $ .venv/bin/python -m pytest -q ........................................................................ [ 90%] ........ [100%] 80 passed in 0.39s => 80 passed (conforme au run dev "80 passed x2"). -------------------------------------------------------------------------------- 2) RUFF -------------------------------------------------------------------------------- $ .venv/bin/python -m ruff check . All checks passed! (exit 0) => ruff clean. -------------------------------------------------------------------------------- 3) TESTS SOUPs / DTRACK (ciblés) -------------------------------------------------------------------------------- $ .venv/bin/python -m pytest -v -k "soup or dtrack" tests/test_api.py::test_dtrack_enabled_default_off PASSED tests/test_api.py::test_dtrack_poll_dormant_without_config PASSED tests/test_api.py::test_dtrack_risk_level_worst_first PASSED tests/test_api.py::test_dtrack_shape_masks_suppressions_and_builds_envelope PASSED tests/test_api.py::test_dtrack_shape_top10_cap PASSED tests/test_api.py::test_soups_endpoint_unknown_key_is_empty_200 PASSED tests/test_api.py::test_soups_endpoint_dormant_dtrack_empty_200 PASSED tests/test_api.py::test_soups_endpoint_returns_populated_slice PASSED tests/test_api.py::test_soups_poll_shapes_and_stores PASSED => 9 passed, 71 deselected. -------------------------------------------------------------------------------- 4) SMOKE RUNTIME (TestClient FastAPI, env sans creds DTrack) -------------------------------------------------------------------------------- - Import adaptateur app.adapters.dtrack : OK - Cache TTL : 21600 s == 6 h : True - settings.dtrack_enabled (defaut, sans creds) : False (client DTrack dormant) - GET /healthz -> 200 ; upstreams.dtrack : False (flag dormant cable) - GET /api/projects/__no_such_key__/soups -> 200 * tous les champs requis presents : True {key, risk_level, total_vulnerabilities, by_severity, components, top_3_critical, suppressions, generated_at} * key estampillee : True ("__no_such_key__") * enveloppe vide : risk_level="clean", total_vulnerabilities=0, by_severity all-zero, components=[], top_3_critical=[], suppressions=0 => Degradation en 200 enveloppe vide schema-valide (jamais 404/500). OK -------------------------------------------------------------------------------- 5) MASQUAGE DES SUPPRESSIONS (_shape direct) -------------------------------------------------------------------------------- Entree: metrics suppressed=5 ; finding critique SUPPRIME (CVE-SUPP) sur libbar. Resultat: - suppressions : 5 (compte seul expose) - top_3_critical ids : ['CVE-A'] -> CVE-SUPP ABSENT : True - composant libbar : vulnerabilities=1, critical=0 -> finding supprime exclu : True => Faux positifs / relances jamais comptes dans totals/by_severity/components/top_3. Seul un compteur opaque `suppressions` est expose. OK -------------------------------------------------------------------------------- 6) GATING DES CREDENTIALS (app/config.py) -------------------------------------------------------------------------------- dtrack_enabled := bool(dtrack_url AND dtrack_api_key) => Le client DTrack reste dormant tant que DTRACK_URL + DTRACK_API_KEY non definis. (Valeurs de secrets NON imprimees.) -------------------------------------------------------------------------------- 7) DOCUMENTATION DU SCHEMA (docs/SBOM.md) -------------------------------------------------------------------------------- - Endpoint, schema de reponse complet, contrat d'enveloppe vide documentes. - Cache 6h documente (section "6h cache"). - Masquage des suppressions documente (section "Suppressions are MASKED"). - Note : la tendance 30 jours provient de l'export Prometheus (comme Security Ops), PAS de cet endpoint -> conforme a la spec, ce n'est pas une lacune. ================================================================================ MATRICE DES CRITERES D'ACCEPTATION ================================================================================ AC1 GET /soups renvoie {key, risk_level, total_vulnerabilities, by_severity, components(top-10), top_3_critical, suppressions, generated_at} ........ OK AC2 Donnees mises en cache, rafraichissement 6h (TTL=21600s) ............... OK AC3 Faux positifs/relances (suppressions) jamais dans la reponse (masquage totals/by_severity/components/top_3 ; compte seul expose) .... OK AC4 Aggregator seule source ; client DTrack dormant sans creds ; degradation 200 enveloppe vide (jamais 404/500) ...................... OK AC5 Schema de reponse documente (aggregator/docs/SBOM.md) ................. OK NOTE Tendance 30j via export Prometheus (docs/SBOM.md) — per-spec, pas une lacune. VERDICT : PASS — tous les criteres OK. Le ticket reste en QA. ================================================================================