1. New 'disputed' state — one lead approved, the other rejected:
- Both approved → validated (unchanged)
- Both rejected → rejected (unchanged)
- One approves + one rejects → disputed (new)
- DB: ALTER TYPE teststate ADD VALUE 'disputed'
- Notification sent to the approving lead explaining the conflict
with the rejection notes
2. Disputed UI in TestDetailHeader:
- Amber banner showing conflict + rejection reason from notes
- 'Change Vote to Rejected' button for the lead who approved
- Validation indicators shown for disputed state too
3. Fix timestamps on reopen (rejected → draft):
- Keep red_started_at, blue_started_at etc. as historical record
- Only clear paused_at defensively
- Timestamps naturally update when test is re-executed
4. disputed badge (amber) added to all badge color maps
1. Jira status → In Progress on Start Execution
- push_test_event calls set_issue_status("In Progress") when
new_state == "red_executing" (non-fatal, separate try/except)
2. Jira assignee set on Start Execution
- assign_issue() called with actor.jira_account_id when operator
clicks Start (non-fatal)
3. Standalone tests parent ticket (OFS-20798)
- New jira.parent_ticket_standalone config key
- get_jira_parent_ticket_standalone() falls back to parent_ticket
- auto_create_test_issue uses standalone parent for non-campaign tests
- Exposed in /system/jira-config GET+PATCH and SettingsPage UI
4. Tests table: Created + Updated columns
- Add Created column (created_at), fix Updated to show updated_at
- Both use UTC-aware date parsing (append Z if no tz suffix)
- updated_at added to Test TypeScript interface
5. Sortable columns in tests table
- All 7 columns sortable: Name, Technique, State, Current Team,
Platform, Created, Updated
- Click to sort asc, click again to reverse; ChevronUp/Down indicator
- Default sort: Created desc (newest first)
Previously blue_started_at was set when the RED team submitted evidence
(= queue open time), so Tempo was getting total queue wait time instead
of actual work time.
Changes:
- DB: add blue_work_started_at column (migration b045), set when a blue
tech explicitly picks up the test (mirrors red_started_at for red team)
- Workflow: new start_blue_work() function + POST /tests/{id}/start-blue-work
endpoint (blue_tech / blue_lead roles). Cannot be called twice.
- submit_blue_evidence: uses blue_work_started_at (when available) as the
phase start for the Tempo worklog, falls back to blue_started_at
- reopen_test: clears blue_work_started_at alongside other timing fields
- Tempo: both red_team_execution and blue_team_evaluation now synced;
correct work_date and description per activity type
- Frontend: "Start Evaluation" button shown in blue_evaluating state when
blue_work_started_at is null; live timer shows from pick-up time
What each timestamp tracks:
blue_started_at = queue entry (SLA / internal tracking)
blue_work_started_at = pick-up by blue tech (Tempo start)
- Add must_change_password field to User model with migration b023
- Add POST /auth/change-password endpoint with password policy validation
- Add require_password_changed dependency to block requests until password is changed
- Add ChangePasswordModal with live password policy checklist (forced on first login)
- Show password policy in CreateUserModal and EditUserModal
- Fix backend permissions: tests, campaigns, templates, reports, evidence, worklogs
- red_tech/blue_tech: execute only, cannot create tests/campaigns/templates
- red_lead/blue_lead: create/edit tests/campaigns/templates, generate reports, no system access
- viewer: read-only everywhere, can generate reports
- Fix frontend role checks across TestDetailPage, TestDetailHeader, TeamTabs, TestsPage, CampaignsPage, CampaignDetailPage, Sidebar
Pause/Resume timer:
- Add paused_at, red_paused_seconds, blue_paused_seconds fields to Test model
- Add pause_timer/resume_timer workflow functions with accumulated pause tracking
- Auto-resume on phase submit; subtract paused time from worklog duration
- Add POST /tests/{id}/pause-timer and resume-timer endpoints
- Update LiveTimer component with pause/resume button and paused visual state
- Wire pause/resume mutations through TestDetailPage and TestDetailHeader
Professional Reporting Engine - Fase 2:
- Add ReportEngine service with Jinja2 HTML rendering, WeasyPrint PDF, and docxtpl DOCX
- Add corporate CSS stylesheet with cover page, data tables, stats grid, findings
- Create purple_campaign, coverage_report, and executive_summary HTML templates
- Add report_generation_service collecting domain data for each report type
- Add professional_reports router: GET /reports/generate/purple-campaign/{id}, coverage-summary, executive-summary
- Add analytics router with flat JSON endpoints for PowerBI: /coverage, /tests, /trends, /operators
- Add advanced_metrics router: /coverage-by-tactic, /never-tested, /avg-validation-time, /detection-rate-trend
- Add weasyprint and docxtpl to requirements.txt
- Add REPORT_TEMPLATES_DIR, REPORT_OUTPUT_DIR, COMPANY_NAME, COMPANY_LOGO_PATH to config
- Add red_started_at/blue_started_at timing fields to Test model with Alembic migration
- Modify workflow transitions to auto-create integrity-hashed worklogs: Start Execution records red_started_at, Submit to Blue Team stops Red timer and creates worklog then starts Blue timer, Submit for Review stops Blue timer and creates worklog
- Auto-sync worklogs to Tempo when test has a Jira link
- Add LiveTimer component showing real-time elapsed counter during active phases
- Clear timing fields on test reopen
- Fix campaign test management: replace broken navigate-to-tests flow with AddTestToCampaignModal that lets users search and add existing tests directly from the campaign detail page
Full Jira/Tempo pipeline: link Aegis entities to Jira issues, auto-sync
status hourly, log time internally with integrity hashing, and optionally
push worklogs to Tempo.
- 1.1 JiraLink model + Worklog model: Alembic migration b020 with indexes,
enums (jiralinkentitytype, jirasyncdirection), and integrity_hash column
- 1.2 Jira service: atlassian-python-api wrapper with lazy singleton client,
search/create/sync operations, feature-flagged via JIRA_ENABLED
- 1.3 Jira router: CRUD endpoints for /jira/links, /jira/search,
/jira/create-issue with audit logging and entity-to-issue auto-creation
- 1.4 Tempo service: worklog push via tempo-api-python-client, auto-log from
test completions when TEMPO_ENABLED, graceful fallback on failure
- 1.5 Worklog service + router: immutable internal time records with SHA-256
integrity hash, CRUD at /worklogs, /worklogs/{id}/verify endpoint
- 1.6 Frontend: JiraLinkPanel component (search, link, sync, unlink) and
WorklogTimeline component (timeline view, manual log form) integrated into
TestDetailPage sidebar, CampaignDetailPage grid, TechniqueDetailPage
- 1.7 Jira sync job: APScheduler hourly job syncs all links from Jira,
registered in background scheduler alongside existing jobs
T-113: Rewrite models.ts with v2 types - TestState now includes red_executing/blue_evaluating, add TeamSide, ValidationStatus, TestTemplate, TestTemplateSummary, TestTimelineEntry types, RED_EDITABLE_STATES/BLUE_EDITABLE_STATES constants, and dual validation fields on Test interface. Remove old validated_by/validated_at references from TestDetailPage and techniques API.
T-114: Rewrite tests.ts API client with 16 functions covering full Red/Blue workflow (createTestFromTemplate, updateTestRed/Blue, startExecution, submitRed/Blue, validateAsRedLead/BlueLead, reopenTest, getTestTimeline). Rewrite evidence.ts with team parameter on upload/list and new deleteEvidence. Create test-templates.ts with getTemplates, getTemplateById, getTemplatesByTechnique, createTemplate, importAtomicTests.