Commit Graph

160 Commits

Author SHA1 Message Date
kitos 4e1f35c250 feat(tests): on-hold button with reason modal, Jira comment + On Hold transition
Aegis CI / lint-and-test (push) Waiting to run
Snyk Security Scan / Python vulnerabilities (backend) (push) Waiting to run
Snyk Security Scan / npm vulnerabilities (frontend) (push) Waiting to run
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Waiting to run
2026-06-19 09:53:05 +02:00
kitos 6147f15238 feat(tests): operator assignment — two queues for techs, assign endpoint for leads
Aegis CI / lint-and-test (push) Waiting to run
Snyk Security Scan / Python vulnerabilities (backend) (push) Waiting to run
Snyk Security Scan / npm vulnerabilities (frontend) (push) Waiting to run
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Waiting to run
2026-06-19 09:07:39 +02:00
kitos a58f9fd357 feat(techniques): add external_references storage and display MITRE sources with links
Aegis CI / lint-and-test (push) Waiting to run
Snyk Security Scan / Python vulnerabilities (backend) (push) Waiting to run
Snyk Security Scan / npm vulnerabilities (frontend) (push) Waiting to run
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Waiting to run
2026-06-18 16:26:11 +02:00
kitos 263823f290 refactor(settings): move Jira connection test from admin Jira tab to Profile tab
Aegis CI / lint-and-test (push) Waiting to run
Snyk Security Scan / Python vulnerabilities (backend) (push) Waiting to run
Snyk Security Scan / npm vulnerabilities (frontend) (push) Waiting to run
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Waiting to run
2026-06-18 15:38:49 +02:00
kitos af5b6e1cff fix(docker): pin nginx to 1.31.1-alpine3.23-slim to fix libxml2 High CVE-2026-6732
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
2026-06-12 13:29:58 +02:00
kitos dcd4bebc92 fix(security): resolve Snyk Code findings — Tar Slip, Path Traversal, Open Redirect, XSS
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
Tar Slip (CWE-22) — 3 import services:
  threat_actor, lolbas, caldera: add path validation before extractall()
  to prevent malicious zip members with ../ escaping the target directory.
  (sigma, elastic, atomic already had this protection)

Path Traversal (CWE-23) — professional_reports.py:
  Add _assert_safe_report_path() check on all 5 report endpoints to
  verify the generated filepath stays within REPORT_OUTPUT_DIR.

Open Redirect (CWE-601) — sso.py:
  Validate IdP redirect URL scheme (must be http/https) before
  issuing RedirectResponse, blocking javascript: and data: redirects.

DOM XSS (CWE-79) — 4 frontend pages:
  Create src/utils/url.ts with safeUrl() that rejects non-http/https
  protocols; apply to actor.mitre_url, ref.url, intel.url.
  Sanitize framework name to alphanumeric-only before DOM insertion.
  Restrict evidence MIME types to an explicit safe allowlist (png/jpg/gif/webp).

Hardcoded credentials (CWE-798):
  verify_gaps.py, create_wiki.py: replace literal passwords with
  environment variable reads (AEGIS_ADMIN_PASSWORD, GITEA_PASSWORD).
2026-06-12 13:15:36 +02:00
kitos 392ce162dc chore(docker): use npm ci instead of npm install in frontend Dockerfile
Aegis CI / lint-and-test (push) Has been cancelled
npm ci installs exact versions from package-lock.json with no implicit
resolution, making builds fully reproducible and guaranteed to use the
audited safe dependency versions.
2026-06-12 12:10:09 +02:00
kitos 5e8b5ee33c fix(deps): update frontend lockfile to resolve 39 Dependabot security alerts
Aegis CI / lint-and-test (push) Has been cancelled
npm audit fix updated 15 packages resolving all 39 vulnerabilities:
- axios: prototype pollution, SSRF, credential leak, ReDoS gadgets
- vite: server.fs.deny bypass, path traversal (dev-only)
- react-router: XSS, DoS, open redirect
- rollup: arbitrary file write (dev-only)
- lodash: code injection, prototype pollution
- picomatch: ReDoS, method injection (dev-only)
- follow-redirects: auth header leak
- postcss: XSS (dev-only)
2026-06-12 09:50:31 +00:00
kitos 0001b33594 refactor(ui): move SSO, Export/Import, System Info from SystemPage to Settings
SystemPage now only shows operational content: MITRE Sync, Intel Scan,
ATT&CK Evaluations, Scheduled Jobs, and Template Management.

Settings gets two new admin-only tabs:
- "SSO / Azure AD": full SAML 2.0 wizard (5-step setup for Azure AD)
- "System": System Status + Version Info + Configuration Export/Import
2026-06-08 15:01:22 +02:00
kitos a7725ba519 feat(sso): Azure AD / Entra ID SAML 2.0 integration
- sso_service: fix process_callback for Azure AD claim URIs (email, role)
  - Default role_attr to full Azure role claim URI
  - Fallback email resolution via Azure email claim URI + NameID
  - Username defaults to full email (prevents collision with local accounts)
  - User lookup also tries email field for existing local accounts
  - Logs warning when unknown role received from IdP

- frontend/api/sso.ts: new API module with getSsoStatus, getSsoConfig, updateSsoConfig

- LoginPage: redesigned for SSO-first flow
  - Shows Azure SSO button as primary when SSO enabled+configured
  - Local login collapsed under "Emergency admin access" section
  - Falls back to normal local login form when SSO is disabled

- SystemPage: new SsoConfigSection component (guided 5-step wizard)
  - Step 1: Copy SP Entity ID and ACS URL for IT team + metadata XML download
  - Step 2: Azure App Roles reference table (6 roles with exact values)
  - Step 3: Tenant ID field auto-fills idp_entity_id and idp_sso_url
  - Step 4: X.509 certificate paste field
  - Step 5: Attribute mapping pre-filled with Azure AD claim URIs
  - Enable/disable toggle + save
2026-06-08 13:48:36 +02:00
kitos e2861a08bc feat(evaluations): enrich eval tests with attack path, criteria and data sources
- Capture Step.Description (HTML stripped), step name/number, substep ref,
  criteria, and data sources from MITRE ATT&CK Evaluations API
- _aggregate_by_technique() now accumulates ALL occurrences per technique
  (multiple substep refs, criteria, step contexts) instead of keeping only
  the best-scoring one
- New helper functions _build_procedure_text(), _build_description(),
  _build_red_summary() generate rich narratives from accumulated occurrences
- New re_enrich_evaluation_round() service function + POST endpoint
  /system/attck-evaluations/re-enrich to update already-imported tests
  without changing detection results or validation state
- Frontend: Re-enrich button per imported round + result banner in SystemPage
2026-06-08 11:42:08 +02:00
kitos 467afc334d fix(evaluations): optional chaining on evalPendingData to fix TS18048 2026-06-05 16:56:29 +02:00
kitos b630cd3210 feat(evaluations): bulk approve evaluation tests with 4-step confirmation modal
Backend:
- POST /system/attck-evaluations/bulk-approve: finds all [EVAL R*] tests in
  in_review state, approves blue side, transitions to validated, recalculates
  technique statuses, audit logs each test
- GET /system/attck-evaluations/pending-count: returns count of pending eval tests

Frontend:
- BulkApproveModal: 4 mandatory checkboxes before confirm button enables
  (lab env / not org detection / metrics impact / spot-check recommendation)
- Bulk Approve button in header badge showing pending count
- Green result banner showing approved tests + techniques recalculated
- Invalidates techniques, metrics and review-queue queries on success
2026-06-05 16:53:00 +02:00
kitos 51d86e5436 fix(evaluations): correct fallback rounds + friendlier error messages
- Fallback names now use hyphens matching live API (carbanak-fin7, wizard-spider-sandworm)
- Add APT3 (R1) and Enterprise 2025/er7 (R7) to fallback - verified from live API
- Remove OilRig (R6) from fallback - CrowdStrike did not participate in Round 6
- Orange fallback banner only shows when NO rounds are available at all
- Soft gray note when rounds are loaded but API had transient error
- Check-new and import errors: detect 502/Cloudflare messages and show user-friendly text
  instead of raw Cloudflare HTML error messages
2026-06-05 16:24:06 +02:00
kitos 8515b8de17 fix(evaluations): bypass Cloudflare 403 with browser headers + hardcoded fallback rounds
- Add browser User-Agent and Referer headers to all evals.mitre.org requests
- fetch_rounds_with_status() returns api_reachable flag + rounds list
- Fallback to 5 known public CrowdStrike rounds (APT29/R2 through OilRig/R6)
  when live API is blocked, so UI always shows something actionable
- Router returns {rounds, api_reachable, api_error} instead of plain array
- Frontend shows orange warning banner when using fallback data
- Remove 502 HTTPException - rounds are always returned (live or fallback)
2026-06-05 16:10:27 +02:00
kitos b037500b7c feat(evaluations): ATT&CK Evaluations importer for CrowdStrike Falcon [FASE-6.1]
- Migration b048: evaluation_imports table (adversary, round, status, tests_created)
- EvaluationImport SQLAlchemy model
- attck_evaluations_service: fetch rounds from evals.mitre.org API, import per-technique
  detection results (Technique/Tactic/Telemetry -> detected/partially/not_detected)
- All imported tests land in in_review state with lab-environment disclaimer
- Idempotency guard prevents duplicate round imports
- 4 new endpoints: list rounds, import specific, import latest, check-new
- Weekly APScheduler cron (Mon 06:00) auto-checks and imports new rounds
- SystemPage UI: rounds table, import buttons, check-new, result feedback
- Disclaimer callout reminding admins these are lab results not org coverage
2026-06-05 15:57:03 +02:00
kitos 6f835c8501 feat(techniques): move legend to top with descriptions and review_required
Replaces the minimal bottom legend with a full coverage legend panel
placed above the filters. Each status shows a cell mock matching the
exact colors used in the matrix, a color-coded label, and a short
description of what it means. Includes review_required with its
orange alert-triangle badge. Removes the old minimal bottom legend.
2026-06-05 13:23:44 +02:00
kitos 46ade20d14 feat(rt-import): add Image to Base64 converter utility
New drag-and-drop section at the bottom of the Import RT page so operators
can convert screenshots to base64 without leaving the page. Includes
thumbnail preview, copy-base64 and copy-JSON-snippet buttons with
2s feedback, per-image delete and clear-all.
2026-06-05 13:08:55 +02:00
kitos 5f54396cb6 feat(rt-import): require base64 evidence images per technique
Each technique in the RT import JSON now requires at least one evidence
image (PNG/JPG/GIF/WebP/BMP, max 10 MB decoded) embedded as base64.

Backend:
- RTEvidenceEntry model: filename, data (base64), caption (optional)
- RTTechniqueEntry.evidence is now required
- Pre-validation raises 422 if any technique is missing evidence
- After test creation, images are decoded and stored in MinIO as
  Evidence records (team=red) linked to the test

Frontend:
- RTEvidenceEntry type added to api/tests.ts
- parseJson() validates evidence presence and structure per technique
- Preview table shows base64 thumbnails (up to 3 + overflow count)
- Format reference updated: evidence fields moved to Required section
- Import result shows total evidence images attached
2026-06-05 12:57:22 +02:00
kitos f4289249b8 refactor(system): rename Threat Intel Scan to Security Feed Monitor
The previous name implied data from a dedicated threat intelligence team.
The feature actually monitors public RSS feeds and security blogs for
ATT&CK technique mentions, so Security Feed Monitor is more accurate.
Updated description and all references across SystemPage and ReviewQueuePage.
2026-06-05 10:23:59 +02:00
kitos 6ab61c8ace refactor(dashboard): replace security posture claims with programme-scoped language
Overall Security Score renamed to Overall Programme Score. Descriptions across
Executive Dashboard and Dashboard page now clarify scores reflect Red/Blue Team
exercise maturity and coverage breadth, not the organisation real-world security
state, to avoid overstating what ATT&CK simulation tests can guarantee.
2026-06-05 09:33:41 +02:00
kitos 564eb406aa fix(campaigns): fix start_date modal — interceptor was losing structured detail
client.ts: when FastAPI detail is an object, extract .message for the error
string and preserve the full detail on enhancedError.detail so consumers
can inspect structured error payloads (e.g. 409 start_date_in_future).

CampaignDetailPage: use enhancedErr.status (not response.status) and
enhancedErr.detail (not response.data.detail) to detect 409 and show
the confirmation modal instead of the toast.
2026-06-04 16:22:17 +02:00
kitos bf3add9b09 fix(campaigns): correct Axios error parsing in activateMutation
FastAPI wraps error bodies as {detail: string | object}, not at the
top level. Was reading data.message instead of data.detail.message,
causing [object Object] in the toast for all non-409 errors.

Now correctly extracts:
- 409 with object detail -> start_date warning modal
- Other errors with string detail -> readable toast message
- Other errors with object detail -> detail.message in toast
2026-06-04 15:57:54 +02:00
kitos 840e1ac0bb feat(threat-actors): Generate Campaign button on actor detail page
Adds a Generate Campaign button (purple, visible to leads/admin) in the
threat actor header. Opens a modal with:
- Actor name shown as context
- Start date picker (required — validated: must be today or future)
- Warning message showing when tests will be queued
- Error display for API failures
- On success: redirects to the new campaign detail page

Start date is mandatory here (unlike the CampaignsPage flow where it
is optional) to enforce scheduling discipline when generating from actors.
2026-06-04 15:45:55 +02:00
kitos b5f924abe0 fix(ts): explicit useMutation generic types for activateMutation
useMutation<Campaign, unknown, boolean> to fix TS2322/TS1345/TS2345 errors
caused by inferred void variables type.
2026-06-04 15:26:12 +02:00
kitos 6b1f5d690a fix(campaigns): start_date modal + hide future-campaign tests from queue
Backend: activate endpoint returns 409 with structured warning when
start_date is in the future; accepts force=true to bypass.
test_crud_service: always excludes tests from draft campaigns with future
start_date so they do not appear in the team queue prematurely.

Frontend: catches 409 on activate and shows amber confirmation modal
with Keep scheduled / Activate now anyway options.
2026-06-04 14:05:58 +02:00
kitos 27c67a5f76 feat(campaigns): start_date for threat-actor-generated campaigns
Backend:
- campaign_service.generate_campaign_from_threat_actor: accept optional
  start_date kwarg and set it on the Campaign model
- campaigns router: new GenerateFromActorPayload schema, /from-threat-actor
  endpoint now accepts optional body with start_date

Frontend:
- generateCampaignFromThreatActor API: accept optional options param
- Generate Campaign modal: date picker + warning message, same UX as the
  manual create form
2026-06-04 13:37:40 +02:00
kitos f605b52d89 fix(security): remediate CVE-2026-42043 — upgrade axios ^1.14.0
- package.json: bump axios constraint from ^1.13.5 to ^1.14.0
- Dockerfile build stage: npm ci -> npm install so the semver range
  in package.json is honoured at build time (npm ci uses the lockfile
  exactly, bypassing the updated constraint)
2026-06-04 13:17:45 +02:00
kitos af864ed735 fix(security): upgrade axios to >=1.14.0 — CVE-2026-42043 (CVSS 10)
Bumps minimum Axios version from 1.13.5 to 1.14.0 to remediate
CVE-2026-42043 identified by VMT / Wiz (asset: AegisTest).
2026-06-04 10:16:41 +02:00
kitos 92e8ff7aff feat(campaigns): campaign start date — scheduled activation, Jira start_date
DB: migration b047 adds start_date (DateTime nullable) + index to campaigns.

Backend:
- Campaign model: start_date field
- CampaignCreate/Update schemas: accept start_date (ISO string)
- CRUD service: persist + serialize start_date in both serializers
- Activation endpoint: blocks manual activation if start_date is in the future
  (campaign will auto-activate via scheduler)
- Scheduler: new hourly job _run_scheduled_campaign_activation — finds draft
  campaigns with start_date <= now, activates them, creates Jira tickets,
  notifies red_tech team
- Jira: campaign + test tickets now include JIRA_START_DATE_FIELD (configurable,
  default customfield_10015). Campaign uses start_date if set, else created_at.
  Tests inherit campaign start_date.
- config.py: JIRA_START_DATE_FIELD setting

Frontend:
- Campaign type: start_date field on Campaign + CampaignSummary
- CampaignCreatePayload: start_date optional field
- Create form: date picker with min=today, warning message explaining behavior
- Campaign detail header: start_date badge showing days remaining or started date
2026-06-03 16:57:06 +02:00
kitos 9fb84fa65c refactor(campaigns): move CampaignTimingPanel next to Progress panel
Progress and Timing now share a 2-column grid at the top of the detail page.
Removed CampaignTimingPanel from the bottom Jira section.
2026-06-03 16:42:45 +02:00
kitos cafd7db94b feat(compliance): add mapping confidence warnings for DORA, ISO 27001, ISO 42001
Amber banner for DORA and ISO 27001:2022 — community-based mapping, no official CTID source.
Orange banner for ISO 42001:2023 — experimental, MITRE ATT&CK has no AI-specific techniques yet.
Each notice explains the mapping source, limitations, and what executives should consider
before using the data in formal audits or regulatory submissions.
2026-06-03 16:37:25 +02:00
kitos 80991b2f59 feat(compliance): executive descriptions and mapping rationale for all 5 frameworks
Backend: expose description in control status response, add rich business-language
descriptions to all curated controls (ISO 27001, ISO 42001, CIS v8, DORA) explaining
requirements and ATT&CK mapping rationale. ISO 42001 includes infrastructure-mapping note.

Frontend: description field in type, info panel in ControlsTable expanded rows,
framework info banner with description and official standard link in CompliancePage.
2026-06-03 16:28:16 +02:00
kitos 200ef88d67 feat(compliance): add ISO/IEC 27001:2022 and ISO/IEC 42001:2023 frameworks
ISO 27001:2022: 37 Annex A controls across 4 themes (Organizational,
People, Physical, Technological) mapped to MITRE ATT&CK techniques.

ISO 42001:2023: 25 Annex A controls for AI Management Systems mapped to
relevant ATT&CK techniques covering AI supply chain, data pipeline
integrity, model serving security, and third-party AI risk.

Backend: import functions, _import_curated_framework() shared helper,
and POST /compliance/import/iso-27001 + iso-42001 endpoints.
Frontend: API client functions + import buttons in CompliancePage.
2026-06-03 15:50:54 +02:00
kitos fd39658f5d feat(disputed): symmetric UX for both leads in disputed state
Lead who approved: Request Discussion button becomes Discussion Requested after sending.
Lead who rejected: new Change to Approved button to resolve conflict after offline discussion.
Both leads retain vote-change buttons. discussionSent state flag tracks send status.
2026-06-03 14:09:52 +02:00
kitos 3b552dbe4e fix(disputed): add admin role + contact info in discussion modal
- request-discussion endpoint: add 'admin' to allowed roles
- Return rejector_email and rejector_role in the response
- Modal success state shows contact card with username, role, email link
  so the approving lead can immediately reach out to the rejecting lead
2026-06-03 13:02:57 +02:00
kitos 2ecb950770 feat(disputed): Confirm My Validation button + discussion request modal
Backend: POST /tests/{id}/request-discussion
  - Only callable by the lead whose vote is 'approved' in a disputed test
  - Sends notification to the rejecting lead: 'Lead X confirms their
    approval and wants to discuss your rejection'
  - Logs the action in audit trail

Frontend:
- 'Confirm My Validation' button (amber outline) alongside 'Change to Rejected'
- Opens a modal showing:
    * Explanation: both leads must agree to finalise
    * Other lead's rejection reason/notes
    * What happens next (stays disputed, notification sent, either can change)
- 'Send Discussion Request' → calls the new endpoint → shows success state:
    'Lead username has been notified...'
- Instruction to reach out via team channels to resolve offline

Flow summary for disputed tests:
  Approving lead sees 2 options:
    a) 'Confirm My Validation' → modal → send request → other lead notified
    b) 'Change to Rejected' → validation modal → both agree to reject → rejected
2026-06-03 12:48:08 +02:00
kitos 6c343bd7a1 fix(ts): add disputed to all Record<TestState> maps to satisfy TypeScript 2026-06-03 12:23:53 +02:00
kitos 643e65fbe5 feat(tests): disputed state + fix timestamps on reopen
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
2026-06-03 12:21:47 +02:00
kitos de0db3cec8 feat(tests): reopen rejected test keeps all content + rejection notes
Backend (reopen_test):
- Preserve red/blue validation NOTES — teams see exactly what to fix
  without losing the rejection context. Previously both notes were cleared.
- Preserve all content fields: procedure_text, tool_used, red_summary,
  attack_success, blue_summary, detection_result (already the case).
- Preserve evidences (separate table, unaffected — already the case).
- Still clear: validation statuses + who/when validated (fresh re-validation
  required). Phase timing reset so the new execution starts clean.

Frontend:
- Button label: 'Reopen Test' → 'Continue Test' (more accurate intent)
- Dialog title: 'Reopen Test' → 'Continue Test'
- Dialog message: replaces alarming 'workflow will be restarted / clear all'
  with accurate description of what is preserved vs reset
- Toast: explains what to do next
2026-06-03 11:31:37 +02:00
kitos cd2fe5aad6 fix(TestsPage): move lastActivityDate outside component to fix TDZ error
useMemo executes its factory immediately on first render. lastActivityDate
was defined with const after the useMemo call inside the component, causing
a temporal dead zone: 'Cannot access v before initialization'.

Fix: move the function to module scope (before the component), where it
is fully initialized before any hook runs.
2026-06-03 11:26:00 +02:00
kitos a1415a379f fix(tests): replace updated_at (doesn't exist) with real timestamps
TestsPage 'Updated' column: compute lastActivityDate() from the most
recent available timestamp — blue_validated_at > red_validated_at >
blue_work_started_at > blue_started_at > red_started_at > created_at.
Also fixes the sort-by-updated_at case.

ValidatedTestsPage 'Validated' column: use blue_validated_at (when Blue
Lead approved) falling back to red_validated_at. Fixes both the display
and the default sort-by-validated.
2026-06-03 11:22:28 +02:00
kitos 611689f3ce fix(tests): use blue_started_at for Waiting column (updated_at doesn't exist)
updated_at column does not exist in the tests table — it was always
undefined, so formatElapsed() always returned '—'.

Replace with blue_started_at (set when Red Team submits to Blue Team),
which correctly shows how long a test has been waiting for Blue Team
evaluation. Also fixed the waiting_time sort to use the same field.
2026-06-03 11:15:00 +02:00
kitos 7d7d351ca8 feat(evidence): paste screenshot directly from clipboard (Ctrl+V)
- Global document paste listener captures image/* items from clipboard
- Auto-generates filename: screenshot-YYYY-MM-DDTHH-MM-SS.png
- Brief cyan pulse animation confirms the paste was detected
- Shows image preview before uploading (max-h 192px, object-contain)
- Drop zone hint now says 'Drag & drop, browse, or Ctrl+V to paste'
- Works with any source: OS screenshot (PrintScreen/Cmd+Shift+4),
  browser Inspect screenshots, any image copied to clipboard
2026-06-03 11:06:22 +02:00
kitos 33e6a1a3f4 fix(tooltip): clarify Blue Team Avg Time excludes queue wait time 2026-06-03 11:01:50 +02:00
kitos 399628e20a fix(metrics): prevent 0.0 falsy bug for sub-hour timing values
Root cause: avg times were ~2-3 minutes (< 1h). round(0.033, 1) = 0.0
which is falsy in JS, so the frontend showed N/A instead of the value.

Fix (backend): _safe_stats() and team metrics now convert to minutes
when avg < 1 hour, adding a 'unit' field ('min' or 'hrs').

Fix (frontend): use != null instead of truthy check for avg_completion_hours,
MTTD, MTTR — correctly shows 0.0 and uses the unit field to show 'min' or 'hrs'.
2026-06-03 10:59:58 +02:00
kitos 0531e7e73e fix(metrics): use direct timestamp fields instead of audit log lookups
MTTD: was querying AuditLog for action names that don't match actual
logged actions. Now uses red_started_at → blue_started_at directly
(both stored on the Test record). Net of red_paused_seconds.

MTTR: was searching for remediation_status=completed (no data). Redefined
as total pipeline time: red_started_at → blue_validated_at net of all
paused time. Only counts fully validated tests.

Red avg time: was using red_validated_at - created_at (created_at NULL
for many tests). Now uses blue_started_at - red_started_at net paused.

Blue avg time: was using blue_validated_at - red_validated_at (wrong
phase boundary). Now uses blue_work_started_at (or blue_started_at
fallback) → blue_validated_at net of blue_paused_seconds.
2026-06-03 10:40:05 +02:00
kitos a1c67419e7 feat(exec-dashboard): move Red/Blue team stats above Top Threat Actors 2026-06-03 10:33:01 +02:00
kitos e5e1779208 feat(exec-dashboard): vertical bars for Coverage by Tactic in MITRE order
- Convert horizontal bar chart to vertical bars (columns)
- Sort all 14 MITRE ATT&CK tactics in official order:
  Reconnaissance → Resource Development → Initial Access → Execution →
  Persistence → Privilege Escalation → Defense Evasion → Credential Access →
  Discovery → Lateral Movement → Collection → C2 → Exfiltration → Impact
- Show ALL tactics (not a subset)
- Labels rotated -45° to fit all names
- Bars have rounded top corners; horizontal gridlines only
2026-06-03 10:13:09 +02:00
kitos f3c07fdaf1 fix(types): add conversion_rate fields to ValidationThroughput interface 2026-06-03 10:07:49 +02:00