Commit Graph

134 Commits

Author SHA1 Message Date
kitos
f8418bc7ea feat(campaigns): start_date for threat-actor-generated campaigns
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:37:40 +02:00
kitos
498536f3f1 fix(security): remediate CVE-2026-42043 — upgrade axios ^1.14.0
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- 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)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 13:17:45 +02:00
kitos
bea5a8e781 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).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04 10:16:41 +02:00
kitos
c62dafbc1f feat(campaigns): campaign start date — scheduled activation, Jira start_date
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 16:57:06 +02:00
kitos
3db9809be5 refactor(campaigns): move CampaignTimingPanel next to Progress panel
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Progress and Timing now share a 2-column grid at the top of the detail page.
Removed CampaignTimingPanel from the bottom Jira section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 16:42:45 +02:00
kitos
7c6aaeda30 feat(compliance): add mapping confidence warnings for DORA, ISO 27001, ISO 42001
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 16:37:25 +02:00
kitos
1dcff4ad20 feat(compliance): executive descriptions and mapping rationale for all 5 frameworks
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 16:28:16 +02:00
kitos
0b82d96bcc feat(compliance): add ISO/IEC 27001:2022 and ISO/IEC 42001:2023 frameworks
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 15:50:54 +02:00
kitos
460faf9935 feat(disputed): symmetric UX for both leads in disputed state
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 14:09:52 +02:00
kitos
02ff89401c fix(disputed): add admin role + contact info in discussion modal
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- 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
4e20bfa835 feat(disputed): Confirm My Validation button + discussion request modal
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
9f86c205be fix(ts): add disputed to all Record<TestState> maps to satisfy TypeScript
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-06-03 12:23:53 +02:00
kitos
61e6037e97 feat(tests): disputed state + fix timestamps on reopen
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 12:21:47 +02:00
kitos
2de95a3082 feat(tests): reopen rejected test keeps all content + rejection notes
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
74ca8dc53a fix(TestsPage): move lastActivityDate outside component to fix TDZ error
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
ad5cd26363 fix(tests): replace updated_at (doesn't exist) with real timestamps
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
fc3b413a83 fix(tests): use blue_started_at for Waiting column (updated_at doesn't exist)
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
9f1c4c28c9 feat(evidence): paste screenshot directly from clipboard (Ctrl+V)
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- 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
ea8c48755f fix(tooltip): clarify Blue Team Avg Time excludes queue wait time
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-06-03 11:01:50 +02:00
kitos
5684484fdf fix(metrics): prevent 0.0 falsy bug for sub-hour timing values
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
06e8effaa4 fix(metrics): use direct timestamp fields instead of audit log lookups
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
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
56d49f6de7 feat(exec-dashboard): move Red/Blue team stats above Top Threat Actors
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-06-03 10:33:01 +02:00
kitos
688e843e03 feat(exec-dashboard): vertical bars for Coverage by Tactic in MITRE order
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- 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
e03a222ab0 fix(types): add conversion_rate fields to ValidationThroughput interface
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-06-03 10:07:49 +02:00
kitos
f53500bcb5 fix(exec-dashboard): replace time-dependent throughput with Pipeline Conversion %
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
'Validation Throughput (tests/week)' was time-dependent — director wanted
an activity-based metric instead.

New metric: Pipeline Conversion Rate
  formula: validated / (validated + rejected + in_review) × 100
  unit: %  (no time reference)
  meaning: 'of all tests that have entered validation, X% succeeded'
  trend: declining if in_review backlog > validated count,
         improving if conversion ≥ 80%, stable otherwise

Backend: calculate_validation_throughput() rewritten — same API key
(tests_per_week) kept for compatibility, new conversion_rate field added.
Frontend: label → 'Pipeline Conversion', unit → '%', tooltip updated.
2026-06-03 10:06:30 +02:00
kitos
9e36b683fa feat(exec-dashboard): split threat actors into exposure vs detection strength
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Replace single list with two-column layout:
- LEFT '⚠ Highest Exposure': top 5 actors by uncovered technique count,
  red border, text explaining 'these attacks would go unnoticed today'
- RIGHT ' Strongest Detection': top 5 actors by coverage %, green border,
  text explaining 'Blue Team would likely detect an intrusion from these'

Shows both the risks (where to focus testing) and the strengths
(what's already well protected) to give executives a balanced view.
2026-06-03 10:01:22 +02:00
kitos
b33562a34e feat: add tooltip to Overall Score gauge in Executive Dashboard
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-06-03 09:57:46 +02:00
kitos
757d99d22a feat(dashboards): hover tooltips on all metric cards
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
New MetricTooltip component — a small ⓘ icon showing an executive-
friendly explanation panel on hover (CSS, no JS, instant).

DashboardPage: tooltips on all 6 coverage summary cards (Total
Techniques, Validated, Partial, In Progress, Not Covered, Not
Evaluated), Coverage Evolution chart, Test Pipeline funnel,
Team Activity and Validation Rate section headers.

ExecutiveDashboardPage: tooltips on all 4 sub-scores (Coverage,
Detection, Critical, Response), Score Trend, Top Threat Actors,
4 KPIs (MTTD, MTTR, Detection Efficacy, Validation Throughput),
Coverage by Tactic, Critical Gaps table, and all 6 team metrics
(Red/Blue Tests Done, Avg Time, Rejection).

Each tooltip explains what the metric measures, what a good/bad
value looks like, and what action to take — written for non-
technical executives.
2026-06-03 09:49:58 +02:00
kitos
2bbc65993c fix(tests): lock editing for operators until timer starts
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
red_tech can only edit procedure/tool/summary when the test is in
red_executing state (after pressing Start Execution). In draft state they
see a read-only view and an orange hint 'Press Start Execution to begin
editing — the timer must be running first.'

blue_tech can only edit when blue_work_started_at is set (after pressing
Start Evaluation). Before that they see an indigo hint 'Press Start
Evaluation to begin editing — pick up the test first.'

red_lead, blue_lead and admin are unaffected — they retain full edit
access in all applicable states including draft.
2026-06-03 08:14:02 +02:00
kitos
46722aec19 fix(auth): silent token refresh — active sessions no longer expire mid-use
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Problem: 15-minute tokens with no refresh mechanism kicked users to login
even when actively using the app.

Fixes:
1. config.py: raise ACCESS_TOKEN_EXPIRE_MINUTES from 15 → 480 (8h).
   Reasonable for an enterprise internal tool; still configurable via env.

2. POST /auth/refresh: new endpoint that reads the current aegis_token
   cookie and issues a fresh token if the session is still valid. Returns
   the new token in the cookie + body (same shape as /auth/login).

3. frontend/api/client.ts: response interceptor now attempts a silent
   refresh on 401 before redirecting to login:
   - Calls POST /auth/refresh once per failed request
   - If refresh succeeds: retries the original request transparently
   - If refresh fails: redirects to /login as before
   - Deduplicates concurrent refresh attempts (refresh once, resolve all)
   - Never attempts refresh on /auth/refresh or /auth/login themselves

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 15:54:15 +02:00
kitos
eee0560aeb feat(admin): export/import configuration bundle for migration
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Backend: GET/POST /api/v1/admin/export-config and /import-config
  Export includes (sensitive values redacted):
  - system_configs (email/jira settings)
  - webhook_configs (secrets redacted)
  - sso_configs (private key redacted)
  - scoring_config (weights)
  - test_templates (source=custom only)
  - users (no passwords/tokens, must_change_password=True on import)
  Import is idempotent — upsert by natural keys, safe to run multiple times.

Frontend: ExportImportSection in SystemPage (admin only)
  - 'Export Configuration' → downloads aegis-config-YYYY-MM-DD.json
  - 'Import Configuration' → file picker, sends JSON, shows summary
  - Visual checklist of what is/isn't included in the export

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 15:49:51 +02:00
kitos
b4a264f2bd feat(tests): require evidence upload before phase transitions
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Backend:
- submit_red_evidence: raises InvalidOperationError if no Red Team
  evidence file has been uploaded for the test
- submit_blue_evidence: raises InvalidOperationError if no Blue Team
  evidence file has been uploaded

Frontend:
- 'Submit to Blue Team' button: disabled + '⚠ Upload evidence first'
  hint when test.red_evidences is empty
- 'Submit for Review' button: same for test.blue_evidences
- Native tooltip on disabled buttons explains the requirement
- Buttons re-enable automatically after the first file is uploaded

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:27:15 +02:00
kitos
2b41b191bd feat(campaigns): campaign timing panel with Red/Blue aggregated metrics
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Backend: GET /campaigns/{id}/timing-summary
  Aggregates timing across all campaign tests:
  - red_execution_secs: red_started_at → blue_started_at (minus paused)
  - blue_queue_secs:    blue_started_at → blue_work_started_at
  - blue_evaluation_secs: blue_work_started_at → validated (minus paused)
  - total_secs: sum of all three phases
  Returns totals + per-test breakdown sorted by total time desc.

Frontend: new CampaignTimingPanel component replaces WorklogTimeline
  - 4 summary cards: Red Execution / Blue Queue / Blue Evaluation / Total
  - Stacked horizontal bar showing time distribution
  - Per-test breakdown with individual mini-bars and phase durations
  - Shows 'No tests started yet' when no timing data available

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 11:06:42 +02:00
kitos
a518c06653 feat(threat-actors): hover tooltip on motivation badges
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
New MotivationBadge component with CSS tooltip showing:
- espionage: goal (intelligence theft), typical behavior, examples
- financial: goal (monetary), typical behavior, examples
- destruction: goal (disrupt/destroy infra), wiper/ICS attacks, examples
- hacktivism: goal (political/ideological), defacement/leaks, examples

Used in ThreatActorsPage (card list) and ThreatActorDetailPage (header).
2026-06-02 10:50:37 +02:00
kitos
61e705ece4 fix(status-badge): show tooltip below badge (not above) to prevent clipping
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-06-02 10:45:11 +02:00
kitos
2bfcc7e58c feat(status-badge): CSS hover tooltip — replaces native title attribute
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
title= attribute tooltip is browser-native, tiny, and often invisible.
New StatusBadge component uses a Tailwind group-hover absolute panel
that appears immediately on hover with:
  - Clear heading per status
  - 'Meaning' and 'Action' lines
  - Arrow pointing to the badge
  - 200ms fade-in transition

Used in TechniquesPage (list table) and TechniqueDetailPage (header).
2026-06-02 10:42:13 +02:00
kitos
7e4a44bbde feat(techniques): status hover tooltips + min 2 tests for validated
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
1. Status logic (v3): require ≥2 validated tests with 'detected' result
   to reach 'validated' status. With only 1 validated+detected test the
   technique stays 'partial' (single test is insufficient evidence).
   Backfilled existing data: T1012 and T1059.001 downgraded to 'partial'.

2. Hover tooltips on status badges in TechniquesPage and TechniqueDetailPage:
   - validated: ≥2 tests executed and detected
   - partial: some tests done but incomplete coverage
   - in_progress: tests exist but none validated yet
   - not_covered: tests run but Blue Team didn't detect
   - not_evaluated: no tests created yet
   - review_required: recent update needs acknowledgment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 10:32:52 +02:00
kitos
ba75baeb7d fix(exec-dashboard): sort Top Threat Actors by uncovered techniques
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Previously: alphabetical order (first 5 actors from list_actors query).
Now: ranked by uncovered technique count = technique_count × (1 - coverage_pct/100).
Tiebreak: higher technique_count first (broader attack surface).

Fetches 100 actors, sorts client-side, shows top 5 with:
- Rank badge (1-5) colored red/orange/yellow/gray
- 'N uncovered / M techniques' subtitle instead of target sectors
- Coverage bar + percentage

This ensures the actors with the largest coverage gap appear first.
2026-06-02 10:19:57 +02:00
kitos
646ac7146e fix(dashboard): force refetch on mount + refresh button for metric widgets
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Root cause: after backend restart (502 errors on startup), metric queries
(pipeline, team, recent, validation) get cached in error state. When the
user stays on the dashboard, the component never remounts so queries don't
auto-retry.

Fixes:
1. refetchOnMount:'always' — queries ALWAYS refetch when component mounts,
   even if cached with error/stale data. Prevents stuck empty state.
2. gcTime:0 — error state is not cached; next mount starts a fresh query.
3. retry:3 — more retries before giving up (covers slow startup windows).
4. Refresh button in header — manually invalidates and refetches all 4
   metric queries with a single click. Spinner icon during refetch.
2026-06-02 09:48:59 +02:00
kitos
0d4c105aa3 fix(dashboard): fix empty widgets + NULL created_at on campaign tests
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
1. metrics_query_service: use NULLS LAST in get_recent_tests() so tests
   with actual dates always appear before NULL-dated ones.

2. campaign_service: set created_at=datetime.utcnow() when creating tests
   from campaigns (was missing, leaving 21 tests with NULL created_at).
   Fixed existing NULL values directly in production DB.

3. DashboardPage: add isError handling to all V2 metric widgets
   (pipeline, team activity, validation rate, recent tests).
   - Add retry:2 to all secondary metric queries so transient failures
     are retried before showing empty state.
   - Show 'Could not load X — refresh' instead of empty/misleading
     'No tests created yet' when a query actually fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 08:58:04 +02:00
kitos
a566834e08 fix(branding): update logo reference in LoginPage
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-05-29 17:07:59 +02:00
kitos
51c506a86d feat(branding): replace logo with new Medusa shield emblem (PNG)
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
2026-05-29 17:04:39 +02:00
kitos
65c34c3374 fix(rt-import): require Blue Lead validation before coverage counts
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
RT tests are created in 'in_review' state (not validated):
- red_validation_status = 'approved' (RT confirmed execution)
- blue_validation_status = null (pending Blue Lead review)
- detection_result is pre-filled from the import JSON

Blue Lead sees these in their normal validation queue and confirms
or rejects the detection result. Only after Blue Lead approval does
the technique coverage update to validated/not_covered/partial.

This gives Blue Lead oversight over RT findings rather than auto-
accepting external engagement results as ground truth.
2026-05-29 16:21:06 +02:00
kitos
2f1ef7545d feat(rt-import): import Red Team engagement results as validated tests
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Backend — POST /tests/import-rt (red_lead + admin):
  Accepts engagement JSON with name/date/description/operator and
  a list of techniques each with mitre_id, result, attack_success,
  platform, notes. Creates one Test per technique directly in
  'validated' state (red + blue validation = approved) bypassing
  the normal workflow. Recalculates technique.status_global for
  all affected techniques. Returns created/skipped summary.

Frontend — /tests/import-rt (new dedicated page):
  - Format reference panel (collapsible) with field descriptions
  - Download template JSON button (generates a filled example)
  - Paste JSON textarea + file upload (.json)
  - Live validation + preview table showing what will be imported
  - Import button with spinner
  - Success / warning / error result display
  Accessible to admin and red_lead only.
  Added to sidebar under Tests > Import RT Results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 16:15:35 +02:00
kitos
b39a4fec14 feat(intel): major intel scan improvements + Review Queue integration
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Backend:
- intel_service: remove 50-technique limit (scan all techniques), improve
  pattern matching with word boundaries (\bT1059\b), raise min name length
  to 8 chars to reduce false positives, skip entries with empty titles
- technique_query_service: add intel_items to get_technique_detail() so
  the technique page now shows recent threat intel articles (last 20)
- New GET /intel/items endpoint with optional technique_id filter

Frontend:
- New api/intel.ts with listIntelItems()
- ReviewQueuePage: complete redesign
    * Expandable rows — click a technique to see its intel articles inline
    * IntelPanel component fetches articles per technique on expand
    * 'Create Template from Intel' button opens pre-filled modal:
      name (from article title), source_url (article link), technique_id
      User reads the article and fills the attack procedure
    * Updated explanation text: lists all 3 reasons a technique can be flagged
      (MITRE update / intel scan / new template or detection rule)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 16:04:30 +02:00
kitos
07c6164ceb fix(permissions): hide action buttons for unauthorized roles
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
TestCatalogPage: 'Use Template' button had no role check — any user
(including viewer/blue_tech/red_tech) could see and click it, which
would fail at the backend (POST /tests/from-template requires
red_lead|blue_lead). Added canUseTemplate check; button hidden for
viewer, blue_tech, red_tech.

TechniqueDetailPage: 'Run This Test' / 'Re-run' buttons in the
Available Templates section also had no role check. Added canRunTemplate
(same criteria: admin|red_lead|blue_lead). The 'View test' button for
active tests remains visible to everyone (read-only navigation).

Principle: if a user cannot perform the action, the button does not
appear — no permission error messages, just absence of the control.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 15:47:08 +02:00
kitos
f590a00006 fix(permissions): hide non-actionable UI + fix viewer route access
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
1. /executive-dashboard: add 'viewer' to ProtectedRoute roles — sidebar
   showed the link to viewers but the route redirected them to /dashboard.
2. /comparison: same fix — viewer was in sidebar roles but not in route.
3. /techniques/review-queue: add ProtectedRoute (leads+admin) — the page
   had no route-level protection, any authenticated user could access it.
4. TechniqueDetailPage review banner: hide from users who can't act on it.
   Previously shown to everyone with a 'Leads only' badge; now only shown
   to canReview users (admin/red_lead/blue_lead). Non-leads don't need to
   see alerts about changes they cannot acknowledge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 15:25:36 +02:00
kitos
7d856bef43 feat(compliance): add DORA (EU 2022/2554) framework with ATT&CK mappings
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Implements the Digital Operational Resilience Act as a compliance framework
using the same pattern as CIS Controls v8 (hardcoded curated mappings,
no official STIX bundle exists for DORA).

22 controls across 5 chapters mapped to MITRE ATT&CK techniques:
  Ch. II  — ICT Risk Management (Art. 5–15): governance, identification,
            protection, detection, response, backup, threat intel
  Ch. III — Incident Management (Art. 17–19): classification, reporting
  Ch. IV  — Resilience Testing (Art. 24–27): general testing + TLPT
            (Art. 26 explicitly based on TIBER-EU/ATT&CK threat-led testing)
  Ch. V   — Third-Party Risk (Art. 28, 30, 42): supply chain, trusted rels.
  Ch. VI  — Information Sharing (Art. 45)

Technique mappings derived from ENISA DORA guidelines and TIBER-EU framework.
Import is triggered via POST /api/v1/compliance/import/dora (admin only).
Frontend: new 'DORA' button in the Compliance page import section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 13:52:51 +02:00
kitos
70b5c833d4 fix(tests): move showTemplateModal useState before early returns (React #310)
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
The useState hook was placed after the isLoading/error early returns,
violating the Rules of Hooks. First render hit the early return without
calling the hook; second render (after data loaded) called it, producing
'more hooks than previous render' — React error #310 and a white screen.

Moved const [showTemplateModal] to the state block at the top of the
component, alongside the other useState declarations.
2026-05-29 13:29:17 +02:00
kitos
6c8a1317fd fix(layout): add React error boundary to catch render crashes
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Previously a JS rendering error produced a blank white screen with no
feedback. PageErrorBoundary now catches the error, shows the error
message + stack trace, and offers a reload button. This will surface
the exact crash message for the inaccessible test page.
2026-05-29 13:23:28 +02:00