|
===================================================================
|
|
QA #47 — Infrastructure Redmine : recherche par clé (champ custom),
|
|
création + anti-doublons/régression
|
|
Epic parent : #24 | Branche : feat/47-redmine-security-adapter
|
|
PR #27 -> dev | Backend uniquement (api/)
|
|
SHA testé : bf0d87d (origin/feat/47-redmine-security-adapter)
|
|
Date : 2026-06-11 | Agent : QA manuel (#25)
|
|
NOTE : aucun secret/clé API n'est inclus dans cette preuve.
|
|
===================================================================
|
|
|
|
ENVIRONNEMENT
|
|
python : api/.venv (FastAPI épinglé)
|
|
cmd : PYTHONPATH=src .venv/bin/python -m pytest -q tests/test_redmine_scan_adapter.py
|
|
|
|
-------------------------------------------------------------------
|
|
SMOKE TEST 1/3 — Tests de contrat respx (9 tests, hors réseau)
|
|
-------------------------------------------------------------------
|
|
......... [100%]
|
|
9 passed in 0.46s
|
|
|
|
-------------------------------------------------------------------
|
|
SMOKE TEST 1/3 — détail (verbose, noms de scénarios)
|
|
-------------------------------------------------------------------
|
|
tests/test_redmine_scan_adapter.py::test_adapter_is_a_scan_ticket_port PASSED [ 11%]
|
|
tests/test_redmine_scan_adapter.py::test_find_by_key_open_ticket_via_custom_field PASSED [ 22%]
|
|
tests/test_redmine_scan_adapter.py::test_find_by_key_no_match_returns_none PASSED [ 33%]
|
|
tests/test_redmine_scan_adapter.py::test_find_by_key_only_closed_ticket_is_regression PASSED [ 44%]
|
|
tests/test_redmine_scan_adapter.py::test_find_by_key_fallback_matches_on_description PASSED [ 55%]
|
|
tests/test_redmine_scan_adapter.py::test_create_ticket_files_security_ticket PASSED [ 66%]
|
|
tests/test_redmine_scan_adapter.py::test_create_ticket_without_field_embeds_key_in_body PASSED [ 77%]
|
|
tests/test_redmine_scan_adapter.py::test_reopen_ticket_resets_status_and_notes PASSED [ 88%]
|
|
tests/test_redmine_scan_adapter.py::test_note_still_open_adds_note_only PASSED [100%]
|
|
|
|
-------------------------------------------------------------------
|
|
SMOKE TEST 2/3 — Câblage import / use-case
|
|
-------------------------------------------------------------------
|
|
OK : RedmineScanTicketAdapter implémente ScanTicketPort (port défini en #46)
|
|
OK : build_redmine_scan_ticket_adapter + SECURITY_TAG importables
|
|
OK : RedmineField.SECURITY_KEY = 12
|
|
OK : SECURITY_TAG = [Sécurité]
|
|
|
|
-------------------------------------------------------------------
|
|
SMOKE TEST 3/3 — Qualité statique (module concerné)
|
|
-------------------------------------------------------------------
|
|
$ ruff check scan_adapter.py + test_redmine_scan_adapter.py
|
|
All checks passed!
|
|
$ mypy scan_adapter.py
|
|
Success: no issues found in 1 source file
|
|
|
|
===================================================================
|
|
MAPPING CRITÈRES D'ACCEPTATION -> RÉSULTAT
|
|
===================================================================
|
|
AC1 Recherche par clé via champ custom 'security_key' (id 12),
|
|
avec repli titre/description documenté ............... OK
|
|
- test_find_by_key_open_ticket_via_custom_field
|
|
- test_find_by_key_fallback_matches_on_description
|
|
- docstring scan_adapter.py : repli documenté (lignes 21-26)
|
|
AC2 Anti-doublon : aucun ticket si un ticket OUVERT porte
|
|
déjà la clé (resolved=False) ......................... OK
|
|
- test_find_by_key_open_ticket_via_custom_field
|
|
- requête pass 1 scoping status_id=open vérifié
|
|
AC3 Régression : nouveau ticket si seuls des tickets
|
|
FERMÉS portent la clé (resolved=True) ................ OK
|
|
- test_find_by_key_only_closed_ticket_is_regression
|
|
AC4 Création conforme : tag [Sécurité], statut Submitted,
|
|
clé persistée dans security_key ...................... OK
|
|
- test_create_ticket_files_security_ticket
|
|
- test_create_ticket_without_field_embeds_key_in_body
|
|
AC5 Tests respx verts ; chemin RUN_REDMINE_LIVE présent ;
|
|
ruff + mypy passent .................................. OK
|
|
- 9/9 respx verts ; ruff+mypy clean ; gate dev :
|
|
423 passed / 2 skipped (live gated) x2
|
|
|
|
NOTE AC1 (provisioning) : le champ custom security_key (id 12)
|
|
n'est pas encore provisionné sur le Redmine live ; l'adaptateur
|
|
retombe alors sur le repli titre/description (clé embarquée dans
|
|
le corps à la création). Comportement vérifié par
|
|
test_find_by_key_fallback_matches_on_description et
|
|
test_create_ticket_without_field_embeds_key_in_body.
|
|
|
|
VERDICT : PASS — tous les critères OK.
|
|
===================================================================
|