feat(tests): require evidence upload before phase transitions
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled

Backend:
- submit_red_evidence: raises InvalidOperationError if no Red Team
  evidence file has been uploaded for the test
- submit_blue_evidence: raises InvalidOperationError if no Blue Team
  evidence file has been uploaded

Frontend:
- 'Submit to Blue Team' button: disabled + '⚠ Upload evidence first'
  hint when test.red_evidences is empty
- 'Submit for Review' button: same for test.blue_evidences
- Native tooltip on disabled buttons explains the requirement
- Buttons re-enable automatically after the first file is uploaded

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
kitos
2026-06-02 14:27:15 +02:00
parent 2b41b191bd
commit b4a264f2bd
2 changed files with 58 additions and 20 deletions

View File

@@ -20,7 +20,8 @@ from sqlalchemy.orm import Session
from app.config import settings
from app.domain.exceptions import InvalidOperationError, InvalidTransitionError
from app.domain.test_entity import TestEntity
from app.models.enums import TestState
from app.models.enums import TestState, TeamSide
from app.models.evidence import Evidence
from app.models.test import Test
from app.models.user import User
from app.services.audit_service import log_action
@@ -146,9 +147,21 @@ def submit_red_evidence(db: Session, test: Test, user: User) -> Test:
"""Move from ``red_executing`` → ``blue_evaluating``.
Called by **red_tech** once they have finished documenting the attack.
Requires at least one Red Team evidence file to be uploaded.
Stops the Red Team timer and creates an automatic worklog.
Starts the Blue Team timer by recording ``blue_started_at``.
"""
# Evidence is mandatory before submitting
red_evidence_count = (
db.query(Evidence)
.filter(Evidence.test_id == test.id, Evidence.team == TeamSide.red)
.count()
)
if red_evidence_count == 0:
raise InvalidOperationError(
"Cannot submit to Blue Team: at least one Red Team evidence file must be uploaded first."
)
now = datetime.utcnow()
# Auto-resume if paused
@@ -224,10 +237,22 @@ def submit_blue_evidence(db: Session, test: Test, user: User) -> Test:
"""Move from ``blue_evaluating`` → ``in_review``.
Called by **blue_tech** once they have finished documenting detection.
Requires at least one Blue Team evidence file to be uploaded.
Stops the Blue Team timer and creates an automatic worklog.
Uses blue_work_started_at as the phase start for Tempo if available,
otherwise falls back to blue_started_at (queue-entry timestamp).
"""
# Evidence is mandatory before submitting
blue_evidence_count = (
db.query(Evidence)
.filter(Evidence.test_id == test.id, Evidence.team == TeamSide.blue)
.count()
)
if blue_evidence_count == 0:
raise InvalidOperationError(
"Cannot submit for review: at least one Blue Team evidence file must be uploaded first."
)
now = datetime.utcnow()
# Auto-resume if paused