feat(tests): add Blue detect_procedure field mapped from template suggestion
Blue Team gets a detect_procedure field on Test (what they actually did to detect the attack), Blue's counterpart to Red's procedure_text. It's seeded from a new detect_suggested_procedure field on TestTemplate at test-creation time, so a junior who later reuses the same template starts with prior guidance instead of a blank field. Also adds the procedure_suggestions review table and Test.source_template_id, laying the groundwork for suggesting template improvements from filled-in procedure fields (reviewed and approved by a lead, never auto-written). detect_procedure is archived (not cleared) on Blue reopen, matching blue_summary, and now appears in the Jira round-archived and blue_review comments alongside the existing detection/containment fields.
This commit is contained in:
@@ -486,6 +486,7 @@ def _build_state_comment(
|
||||
f"Blue Team has submitted evidence for Round {test.blue_round_number or 1} and the "
|
||||
"test is awaiting Blue Lead review before cross-validation.",
|
||||
"",
|
||||
f"*Detect Procedure:* {test.detect_procedure or 'N/A'}",
|
||||
f"*Detection Result:* {_enum_value(test.detection_result) or 'N/A'}",
|
||||
f"*Containment Result:* {_enum_value(test.containment_result) or 'N/A'}",
|
||||
]
|
||||
@@ -1129,6 +1130,7 @@ def push_round_archived(db: Session, test, actor, *, round_data) -> None:
|
||||
lines.append(f"*Attack success:* {round_data.attack_success.value if round_data.attack_success else '-'}")
|
||||
lines.append(f"*Summary:* {round_data.red_summary or '-'}")
|
||||
else:
|
||||
lines.append(f"*Detect procedure:* {round_data.detect_procedure or '_none recorded_'}")
|
||||
lines.append(f"*Detection result:* {round_data.detection_result.value if round_data.detection_result else '-'}")
|
||||
lines.append(f"*Containment result:* {round_data.containment_result.value if round_data.containment_result else '-'}")
|
||||
lines.append(f"*Summary:* {round_data.blue_summary or '-'}")
|
||||
|
||||
@@ -364,9 +364,11 @@ def create_test_from_template(
|
||||
platform=platform_override if platform_override is not None else template.platform,
|
||||
procedure_text=procedure_text_override if procedure_text_override is not None else template.attack_procedure,
|
||||
tool_used=tool_used_override if tool_used_override is not None else template.tool_suggested,
|
||||
detect_procedure=template.detect_suggested_procedure,
|
||||
remediation_steps=template.suggested_remediation,
|
||||
# Keyword argument: created_by
|
||||
created_by=creator_id,
|
||||
source_template_id=template.id,
|
||||
# Keyword argument: state
|
||||
state=TestState.draft,
|
||||
created_at=datetime.utcnow(), # explicit — DB column has no server default
|
||||
|
||||
@@ -623,7 +623,7 @@ def reopen_blue_review(db: Session, test: Test, user: User, notes: str) -> Test:
|
||||
paused_seconds=test.blue_paused_seconds or 0,
|
||||
detection_result=test.detection_result, containment_result=test.containment_result,
|
||||
detection_time=test.detection_time, containment_time=test.containment_time,
|
||||
blue_summary=test.blue_summary,
|
||||
blue_summary=test.blue_summary, detect_procedure=test.detect_procedure,
|
||||
review_notes=notes.strip(), reviewed_by=user.id,
|
||||
)
|
||||
db.add(archived_round)
|
||||
|
||||
Reference in New Issue
Block a user