feat(backend): enforce campaign scheduling, add reviewer queue filter, tactic order, duplicate-test counts

- start_execution now blocks a test from starting before its campaign's
  start_date, closing a gap where the field was persisted but never
  enforced
- GET /tests gains a reviewer_id "my reviews" filter for the red_review/
  blue_review lead-gate stage, distinct from pending_validation_side
  (which only ever covered the later in_review stage and ignored
  assignment entirely)
- get_coverage_by_tactic now returns all 14 MITRE tactics in canonical
  kill-chain order instead of an alphabetical, partial list — the
  regular Dashboard and Executive Dashboard both consume this endpoint
  and previously disagreed on order/completeness
- test-template listing now includes existing_test_count per technique
  so the catalog can warn before creating a likely-duplicate test
This commit is contained in:
kitos
2026-07-08 08:46:09 +02:00
parent 21c6febd22
commit 1c8fa436ab
12 changed files with 333 additions and 3 deletions
@@ -16,6 +16,8 @@ from app.domain.errors import EntityNotFoundError
# Import TestTemplate from app.models.test_template
from app.models.test_template import TestTemplate
from app.models.technique import Technique
from app.models.test import Test
# Import escape_like from app.utils
from app.utils import escape_like
@@ -91,6 +93,21 @@ def list_templates(
# Chain .all() call
.all()
)
# Attach existing_test_count per template — lets the catalog warn before
# creating a likely-duplicate test for a technique that already has one.
if templates:
mitre_ids = {t.mitre_technique_id for t in templates}
counts = dict(
db.query(Technique.mitre_id, func.count(Test.id))
.join(Test, Test.technique_id == Technique.id)
.filter(Technique.mitre_id.in_(mitre_ids))
.group_by(Technique.mitre_id)
.all()
)
for t in templates:
t.existing_test_count = counts.get(t.mitre_technique_id, 0)
# Return templates
return templates