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
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:
@@ -44,9 +44,28 @@ import { createTemplate } from "../api/test-templates";
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────
|
||||
|
||||
// The backend always stores/returns naive UTC datetimes (no "Z", no
|
||||
// offset). <input type="datetime-local"> shows/edits wall-clock time in
|
||||
// the browser's own timezone, so both directions need an explicit
|
||||
// UTC <-> local conversion — treating the raw digits as interchangeable
|
||||
// silently shifts every value by the browser's UTC offset.
|
||||
function isoToDatetimeLocal(iso: string | null): string {
|
||||
if (!iso) return "";
|
||||
return iso.replace("Z", "").replace(/\.\d+$/, "").slice(0, 16);
|
||||
const utcStr = iso.endsWith("Z") || iso.includes("+") ? iso : iso + "Z";
|
||||
const d = new Date(utcStr);
|
||||
if (isNaN(d.getTime())) return "";
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
}
|
||||
|
||||
function datetimeLocalToIso(local: string): string | undefined {
|
||||
if (!local) return undefined;
|
||||
// New Date() on a plain "YYYY-MM-DDTHH:mm" string (no zone designator)
|
||||
// parses it as local time per the ECMA-262 date string spec — exactly
|
||||
// the wall-clock time the user picked.
|
||||
const d = new Date(local);
|
||||
if (isNaN(d.getTime())) return undefined;
|
||||
return d.toISOString();
|
||||
}
|
||||
|
||||
// ── Page Component ─────────────────────────────────────────────────
|
||||
@@ -205,8 +224,8 @@ export default function TestDetailPage() {
|
||||
tool_used: redDraft.tool_used || undefined,
|
||||
attack_success: redDraft.attack_success || undefined,
|
||||
red_summary: redDraft.red_summary || undefined,
|
||||
execution_start_time: redDraft.execution_start_time || undefined,
|
||||
execution_end_time: redDraft.execution_end_time || undefined,
|
||||
execution_start_time: datetimeLocalToIso(redDraft.execution_start_time),
|
||||
execution_end_time: datetimeLocalToIso(redDraft.execution_end_time),
|
||||
}),
|
||||
onSuccess: () => {
|
||||
invalidateAll();
|
||||
@@ -220,8 +239,8 @@ export default function TestDetailPage() {
|
||||
updateTestBlue(testId!, {
|
||||
detection_result: (blueDraft.detection_result as TestResult) || undefined,
|
||||
containment_result: (blueDraft.containment_result as ContainmentResult) || undefined,
|
||||
detection_time: blueDraft.detection_time || undefined,
|
||||
containment_time: blueDraft.containment_time || undefined,
|
||||
detection_time: datetimeLocalToIso(blueDraft.detection_time),
|
||||
containment_time: datetimeLocalToIso(blueDraft.containment_time),
|
||||
blue_summary: blueDraft.blue_summary || undefined,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
|
||||
Reference in New Issue
Block a user