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:
@@ -111,21 +111,27 @@ export default function TestDetailHeader({
|
||||
);
|
||||
}
|
||||
|
||||
// Red Team in red_executing -> Submit to Blue Team
|
||||
// Red Team in red_executing -> Submit to Blue Team (requires ≥1 red evidence)
|
||||
if (
|
||||
test.state === "red_executing" &&
|
||||
(role === "red_tech" || role === "red_lead" || role === "admin")
|
||||
) {
|
||||
const hasRedEvidence = (test.red_evidences?.length ?? 0) > 0;
|
||||
buttons.push(
|
||||
<button
|
||||
key="submit-red"
|
||||
onClick={onSubmitRed}
|
||||
disabled={isTransitioning}
|
||||
className="flex items-center gap-1.5 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{isTransitioning ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
|
||||
Submit to Blue Team
|
||||
</button>,
|
||||
<div key="submit-red" className="flex flex-col items-end gap-1">
|
||||
<button
|
||||
onClick={onSubmitRed}
|
||||
disabled={isTransitioning || !hasRedEvidence}
|
||||
title={!hasRedEvidence ? "Upload at least one Red Team evidence file before submitting" : undefined}
|
||||
className="flex items-center gap-1.5 rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isTransitioning ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
|
||||
Submit to Blue Team
|
||||
</button>
|
||||
{!hasRedEvidence && (
|
||||
<span className="text-[10px] text-orange-400">⚠ Upload evidence first</span>
|
||||
)}
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -149,16 +155,23 @@ export default function TestDetailHeader({
|
||||
</button>,
|
||||
);
|
||||
} else {
|
||||
// Submit for Review requires ≥1 blue evidence
|
||||
const hasBlueEvidence = (test.blue_evidences?.length ?? 0) > 0;
|
||||
buttons.push(
|
||||
<button
|
||||
key="submit-blue"
|
||||
onClick={onSubmitBlue}
|
||||
disabled={isTransitioning}
|
||||
className="flex items-center gap-1.5 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-500 transition-colors disabled:opacity-50"
|
||||
>
|
||||
{isTransitioning ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
|
||||
Submit for Review
|
||||
</button>,
|
||||
<div key="submit-blue" className="flex flex-col items-end gap-1">
|
||||
<button
|
||||
onClick={onSubmitBlue}
|
||||
disabled={isTransitioning || !hasBlueEvidence}
|
||||
title={!hasBlueEvidence ? "Upload at least one Blue Team evidence file before submitting" : undefined}
|
||||
className="flex items-center gap-1.5 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isTransitioning ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
|
||||
Submit for Review
|
||||
</button>
|
||||
{!hasBlueEvidence && (
|
||||
<span className="text-[10px] text-orange-400">⚠ Upload evidence first</span>
|
||||
)}
|
||||
</div>,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user