Project

General

Profile

Actions

Feature #46

closed
RA

Feature #24: Implémenter un hook pour la création automatique de tickets Redmine depuis les scans Trivy et Semgrep

Domaine & application : SecurityFinding, normalisation Trivy/Semgrep, clé de dédup et format de ticket

Feature #46: Domaine & application : SecurityFinding, normalisation Trivy/Semgrep, clé de dédup et format de ticket

Added by Redmine Admin about 2 months ago. Updated about 2 months ago.

Status:
Shipped
Priority:
Normal
Assignee:
-
Start date:
06/11/2026
Due date:
% Done:

0%

Estimated time:
spec_ref:

Spec = la description + critères d'acceptation de ce ticket (issu de la décomposition de #24, validée PO). Unité hexagonale domaine+application : SecurityFinding, normaliseurs Trivy/Semgrep, clé de dédup, format ticket, use case CreateTicketsFromScan via port abstrait. Aucune dépendance. Prêt pour backend-dev.

build_status:
build_number:
ci_run_url:
scan_status:
scan_report_url:
deploy_status:
preprod_url:
deployed_at:
branch:
feat/46-security-finding-domain
pr_url:
https://github.com/omdev-tech/PipeLiner-Client/pull/23
security_key:
severity:
paused:

Description

Couches domain + application de `api/` : modèle de domaine commun `SecurityFinding` + logique métier indépendante de Redmine et du transport HTTP. Normaliseurs purs `from_trivy(report)` / `from_semgrep(report)` → liste de `SecurityFinding`. Calcul de la clé de dédup : Trivy `CVE-{id}` ou `{paquet}@{version}_CVE-{id}` ; Semgrep `{fichier}:{ligne}_{rule-id}`. Formatage du ticket (titre + description complète : sévérité, extrait code, lien CVE, recommandations). Cas d'usage `CreateTicketsFromScan` orchestrant normalisation → décision dédup vs régression via un **port abstrait** (pas d'impl Redmine ici). TDD.

## Critères d'acceptation
- `SecurityFinding` + normaliseurs couvrent les 2 formats de rapport.
- Clé de dédup correcte (Trivy `CVE-{id}`/`{paquet}@{version}_CVE-{id}` ; Semgrep `{fichier}:{ligne}_{rule-id}`).
- Format de ticket conforme aux exemples (titre + description complète).
- `CreateTicketsFromScan` décide dédup vs régression via un port abstrait.
- Tests unitaires verts (normalisation, clé, format) ; `ruff check .` + `mypy src` passent.

Estimation : M. Dépendances : aucune.


Files

qa-46-preuve-technique.txt (3.78 KB) qa-46-preuve-technique.txt Redmine Admin, 06/11/2026 06:50 PM

RA Updated by Redmine Admin about 2 months ago Actions #1

  • Status changed from Submitted to Spec
  • spec_ref updated (diff)

Passage en **Spec** + `spec_ref` rempli ⇒ prêt pour le dev (cible : `backend-dev`, en worktree isolé).

RA Updated by Redmine Admin about 2 months ago Actions #2

  • Status changed from Spec to In development

RA Updated by Redmine Admin about 2 months ago Actions #3

  • Status changed from In development to QA
  • branch set to feat/46-security-finding-domain
  • pr_url set to https://github.com/omdev-tech/PipeLiner-Client/pull/23

Couches **domaine + application** livrées (TDD) sur la branche `feat/46-security-finding-domain`.

- `domain/security/value_objects.py` : `SecurityFinding` (frozen) + enums `SecuritySource`/`Severity` ; clé de dédup, titre et description de ticket portés par le VO.
- Dédup : Trivy `{paquet}@{version}_CVE-{id}` (repli `CVE-{id}`) ; Semgrep `{fichier}:{ligne}_{rule-id}`.
- Titre : `[Sécurité] Dépendance vulnérable : (CVE-2021-23337)` / `[Sécurité] Vulnérabilité de code : fichier:ligne (rule-id)`.
- Description complète : sévérité, source, emplacement/paquet, extrait de code, lien CVE, recommandations.
- `domain/security/normalizers.py` : `from_trivy` / `from_semgrep` purs et totaux (rapport vide/malformé → `[]`).
- `domain/security/ports.py` : port **abstrait** `ScanTicketPort` (Protocol) + `ExistingTicket`. Pas d'adaptateur Redmine ici (c'est #47).
- `application/create_tickets_from_scan.py` : `CreateTicketsFromScan` orchestre normalisation → décision **création / dédup / régression** via le port, avec dédup intra-scan.

Gate vert (depuis `api/`) : `pytest` 398 passed / 1 skipped (lancé 2× sur un Postgres pgvector éphémère, idempotence OK), `ruff check .` OK, `mypy src` OK (strict).

PR (vers `dev`) : https://github.com/omdev-tech/PipeLiner-Client/pull/23

NB : correction au passage d'une assertion obsolète de `test_tasks_api` laissée par le commit du statut Design (33554b6) — l'ordre canonique compte désormais 9 étapes (Design=15 entre Spec et In development).

Passage en QA.

RA Updated by Redmine Admin about 2 months ago Actions #5

**QA — Smoke test : PASS** (ticket back-end uniquement, couches domain + application de `api/` ; pas d'HTTP/UI -> preuve = build/import + suites unitaires, pas de capture navigateur).

Branche / commit : `feat/46-security-finding-domain` @ `138e26e` (PR #23 -> `dev`).

**Résultats par critère d'acceptation**
- AC1 — `SecurityFinding` + normaliseurs couvrent les 2 formats : **OK**. `from_trivy`/`from_semgrep` importent et tournent sur des payloads Trivy (`Results[*].Vulnerabilities[*]`) et Semgrep (`results[*]`).
- AC2 — Clé de dédup : **OK**. Trivy `_CVE-2021-23337` (paquet+version) et `CVE-2020-8203` (version inconnue -> CVE seul) ; Semgrep `api/src/app/exec.py:42_python.lang.security.dangerous-exec`. Conforme au format documenté (`{paquet}@{version}_CVE-{id}` / `CVE-{id}` ; `{fichier}:{ligne}_{rule-id}`).
- AC3 — Format de ticket : **OK**. Titre `[Sécurité] Dépendance vulnérable : (CVE-2021-23337)` / `[Sécurité] Vulnérabilité de code : …` ; description complète (sévérité, source, emplacement/paquet, extrait de code, lien CVE, recommandations ; sections vides omises).
- AC4 — `CreateTicketsFromScan` décide dédup vs régression via un port abstrait : **OK**. `ScanTicketPort` est un `Protocol` `runtime_checkable` ; le use case ne dépend que de l'interface. Scénario exercé via un port en mémoire : nouveau -> `created`, ticket résolu resurfacé -> `regression` (reopen), ticket déjà ouvert -> `deduped` (note). Dédup intra-scan d'une même clé également vérifiée.
- AC5 — Tests verts + qualité statique : **OK**. 26 tests sécurité ciblés verts ; suite back-end complète **398 passed, 1 skipped** (Postgres éphémère `pgvector/pgvector:pg16` + `alembic upgrade head`) ; `ruff check .` OK ; `mypy src` OK (114 fichiers).

**Pièce jointe** : `qa-46-preuve-technique.txt` (log technique complet, filtré de tout secret — payloads synthétiques, port en mémoire ; aucun `.env`/clé/token).

**Verdict : PASS.** Le ticket reste en **QA** (la promotion preprod est du ressort d'un autre agent).

RA Updated by Redmine Admin about 2 months ago Actions #6

  • Status changed from QA to Shipped

Shipped to production (with #40, same promotion). Backend security domain (SecurityFinding + Trivy/Semgrep normalizers + CreateTicketsFromScan via abstract port).
- QA PASS (api suite 398 passed ×2 on ephemeral Postgres, ruff/mypy clean, all 5 AC) — proof attached.
- PR #23 merged to dev; dev build #53 SUCCESS @ 9b5108a; dev→preprod→master all fast-forward; master build #63 SUCCESS → prod deployed.
- Note: domain/application layer only — wired into a live endpoint by sibling tickets #47 (infrastructure) + #48 (presentation), so no behavioural change in prod yet (safe dead-path until those land).

Actions

Also available in: PDF Atom