|
================================================================================
|
|
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.
|
|
================================================================================
|