Test Lifecycle
Every test in Aegis follows a structured state machine from creation to final validation. This page documents every state, transition, actor, and field update rule.
State Diagram
┌─────────┐
│ draft │◄──────────────────────────┐
└────┬────┘ │
│ POST /start-execution │
│ (red_tech, red_lead, admin) │ POST /reopen
▼ │ (leads, admin)
┌─────────────────┐ │
│ red_executing │ │
└────────┬────────┘ │
│ POST /submit-red │
│ (red_tech, red_lead, admin) │
▼ │
┌─────────────────────┐ │
│ blue_evaluating │ │
└────────┬────────────┘ │
│ POST /submit-blue │
│ (blue_tech, blue_lead, admin) │
▼ │
┌───────────┐ │
│ in_review │ │
└─────┬─────┘ │
│ Both validate (approved) │
│ │
┌──────────┴──────────┐ │
│ Either rejects │ │
▼ ▼ │
┌──────────┐ ┌───────────┐ │
│ rejected │─────────┤ validated │ │
└──────────┘ └───────────┘ │
│ │
└───────────────────────────────────────────┘
States Reference
draft
- Description: Initial state. Test has been defined but not yet executed.
- Who creates: red_lead, blue_lead, admin (POST /api/v1/tests)
- Who can edit general fields: red_lead, blue_lead, admin (PATCH /api/v1/tests/{id})
- Available actions:
- Edit test metadata (title, description, technique_id, objective, target_environment, etc.)
- Add to campaigns
- Attach red evidence (even before execution, for pre-work files)
- Cannot do: upload blue evidence, start timer
Create payload example:
{
"title": "T1059.001 PowerShell cradle download",
"technique_id": "T1059.001",
"objective": "Verify AMSI bypass detection",
"target_environment": "Windows 10 workstation",
"severity": "high",
"campaign_id": "optional-uuid"
}
red_executing
- Description: Red team is actively executing the attack.
- Trigger: POST /api/v1/tests/{id}/start-execution
- Who can trigger: red_tech, red_lead, admin
- Timer starts automatically when entering this state.
- Who updates red fields: red_tech, red_lead, admin (PATCH /api/v1/tests/{id}/red)
Red fields (PATCH /tests/{id}/red):
{
"tool_used": "Cobalt Strike 4.8",
"command_executed": "powershell -nop -w hidden -enc ...",
"output_observed": "Beacon established on 10.0.0.5",
"red_notes": "Used staged payload to bypass AV",
"attacker_ip": "10.10.10.100",
"target_ip": "10.0.0.5",
"start_time": "2024-03-15T10:00:00Z",
"end_time": "2024-03-15T10:15:00Z"
}
Evidence upload (team=red):
POST /api/v1/tests/{id}/evidence
Content-Type: multipart/form-data
file=<binary>
team=red
description=PowerShell execution screenshot
blue_evaluating
- Description: Blue team is evaluating what they detected (or didn't).
- Trigger: POST /api/v1/tests/{id}/submit-red
- Who can trigger: red_tech, red_lead, admin
- Who updates blue fields: blue_tech, blue_lead, admin (PATCH /api/v1/tests/{id}/blue)
Blue fields (PATCH /tests/{id}/blue):
{
"detection_result": "detected",
"detection_notes": "Windows Defender ATP alert fired: Suspicious PowerShell",
"alert_fired": true,
"alert_name": "ASR rule: Block Office apps from creating child processes",
"response_action": "Endpoint isolated automatically",
"time_to_detect_seconds": 47,
"blue_notes": "AMSI telemetry captured full script content"
}
detection_result values:
detected— blue team observed the attack in timenot_detected— attack was not detectedpartial— partial detection (some indicators observed but not full alert)
Evidence upload (team=blue):
POST /api/v1/tests/{id}/evidence
Content-Type: multipart/form-data
file=<binary>
team=blue
description=SIEM alert screenshot
in_review
- Description: Both leads must independently validate their side.
- Trigger: POST /api/v1/tests/{id}/submit-blue
- Who can trigger: blue_tech, blue_lead, admin
- No field updates allowed while in review.
- Evidence is locked — no new evidence uploads.
Red validation (red_lead, admin):
POST /api/v1/tests/{id}/validate-red
{"red_validation_status": "approved", "red_validation_notes": "Execution was clean"}
Blue validation (blue_lead, admin):
POST /api/v1/tests/{id}/validate-blue
{"blue_validation_status": "approved", "blue_validation_notes": "Detection confirmed"}
Both validations can be approved or rejected.
validated
- Description: Both leads approved. Test is complete and results are official.
- Trigger: Both red_validation_status and blue_validation_status =
approved - Effects:
- Technique coverage status is recalculated
- Webhook events fired (if configured):
test.validated - Score may be updated
- Snapshot data refreshed
- After validation: Leads and admin can still edit the
remediationfields:PATCH /api/v1/tests/{id}/remediation { "remediation_status": "in_progress", "remediation_notes": "SIEM rule deployed to block this technique", "remediation_owner": "blue-lead-user-uuid" }
rejected
- Description: At least one lead rejected their side.
- Trigger: Either validate-red or validate-blue returns
rejected - Recovery: POST /api/v1/tests/{id}/reopen (leads, admin) sends back to
draft
Evidence Rules Summary
| State | Red evidence | Blue evidence |
|---|---|---|
| draft | Upload allowed | Not allowed |
| red_executing | Upload allowed | Not allowed |
| blue_evaluating | Not allowed | Upload allowed |
| in_review | Locked | Locked |
| validated | Locked | Locked |
| rejected | Locked | Locked |
Timer
The test timer measures elapsed execution time.
| Action | Endpoint | Allowed roles |
|---|---|---|
| Pause timer | POST /tests/{id}/pause-timer | All except viewer |
| Resume timer | POST /tests/{id}/resume-timer | All except viewer |
The timer automatically starts when entering red_executing.
Timeline and Audit Trail
Every state change is recorded in the timeline:
GET /api/v1/tests/{id}/timeline
Response includes entries for:
- State transitions (from_state, to_state, actor, timestamp)
- Validation actions (approved/rejected, actor, timestamp)
- Evidence uploads (team, filename, actor, timestamp)
- Timer pauses/resumes
- Worklog entries
Retest Chain
When a test is a retest of a previous (failed) test, it is linked via retest_of:
{"retest_of": "previous-test-uuid"}
Navigate the full chain:
GET /api/v1/tests/{id}/retest-chain
Returns an ordered list of all tests in the chain, oldest first.