fix(jira): store execution times as real UTC, fix RT date fields, label reopens
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled

- execution_start_time/execution_end_time/detection_time/containment_time
  were captured from a datetime-local input with no local->UTC conversion,
  then stored/displayed as if already UTC — off by the browser's offset.
  Frontend now converts properly in both directions; backend schemas
  defensively normalize any tz-aware input to naive UTC as well.
- push_rt_submitted was pushing datetime.utcnow() (whenever the submit
  button was clicked) into Jira's RT Start/End Date fields instead of the
  operator-entered execution window. Now pushes the *first* round's
  execution start (recovered from round_history across reopens) and the
  *current* round's execution end. Removed push_rt_started, which only
  ever pushed a meaningless click-timestamp.
- Reopening a test now adds a "reopened" Jira label (read-modify-write so
  existing labels aren't clobbered), on top of the existing round-archived
  comment and status push.
This commit is contained in:
kitos
2026-07-13 14:57:42 +02:00
parent b48de743b6
commit 4221d2858b
5 changed files with 208 additions and 45 deletions
+20 -2
View File
@@ -4,15 +4,29 @@
import uuid
# Import datetime from datetime
from datetime import datetime
from datetime import datetime, timezone
from pydantic import BaseModel, ConfigDict, model_validator
from pydantic import BaseModel, ConfigDict, field_validator, model_validator
# Import DataClassification from app.domain.enums
from app.domain.enums import AttackSuccessResult, ContainmentResult, DataClassification
from app.models.enums import TestResult, TestState
from app.schemas.evidence import EvidenceOut
def _to_naive_utc(v: datetime | None) -> datetime | None:
"""Normalize an incoming datetime to naive UTC.
Every timestamp column in this app is naive-UTC (set via
``datetime.utcnow()`` server-side). Clients are expected to send a
proper UTC ISO string (with a ``Z``/offset), but if one slips through
tz-aware, convert it rather than let it get silently mis-stored as if
its clock digits were already UTC.
"""
if v is not None and v.tzinfo is not None:
return v.astimezone(timezone.utc).replace(tzinfo=None)
return v
# ── Create ──────────────────────────────────────────────────────────
@@ -85,6 +99,8 @@ class TestRedUpdate(BaseModel):
execution_start_time: datetime | None = None
execution_end_time: datetime | None = None
_normalize_datetimes = field_validator("execution_start_time", "execution_end_time")(_to_naive_utc)
# ── Blue Team update ───────────────────────────────────────────────
@@ -100,6 +116,8 @@ class TestBlueUpdate(BaseModel):
# Assign blue_summary = None
blue_summary: str | None = None
_normalize_datetimes = field_validator("detection_time", "containment_time")(_to_naive_utc)
# ── Round history (archived on reopen) ─────────────────────────────