feat(tests): require evidence upload before phase transitions
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user