Commit Graph

483 Commits

Author SHA1 Message Date
kitos 0a6cb5510c fix(install): generate PLATFORM_URL in install.sh, backfill on existing .env
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
Fresh installs failed at 'docker compose up' with 'required variable
PLATFORM_URL is missing a value' — the install script computes ORIGIN_URL
for CORS_ORIGINS already but never wrote PLATFORM_URL, which the backend
now requires with no default. Also backfills it into an existing .env
(from CORS_ORIGINS) when the user chooses to keep their current config,
so upgrading an older install in place doesn't hit the same error.
2026-07-23 10:38:13 +02:00
kitos d932134975 feat(users): admin can permanently delete users, fix set-password redirect bug
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
- New DELETE /users/{id}: hard-deletes a user only if they have zero
  activity footprint (no tests, evidence, worklogs, audit entries, Jira
  links, procedure/template suggestions, reviewed imports) — otherwise
  rejects with a clear message to deactivate instead, to keep the audit
  trail intact. Cleans up the user's own notifications/password-setup
  tokens as part of deletion. Self-delete is blocked. Wired to a trash
  icon in the Users page with a confirm dialog.
- Registered the EvaluationImport model in app/models/__init__.py — it
  was missing, so its table never existed in the SQLite test DB; only
  surfaced once the new delete-user footprint check queried it.
- Fixed a redirect bug: the axios response interceptor's on-401 redirect
  to /login didn't exempt /set-password, so the auth provider's routine
  mount-time /auth/me check (401 for a logged-out visitor) bounced anyone
  opening their emailed set-password link away before they could use it.
2026-07-23 08:58:17 +02:00
kitos 545a84b137 fix(config): require PLATFORM_URL explicitly, no hardcoded domain default
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
The previous fix defaulted PLATFORM_URL to this deployment's own domain
directly in docker-compose.prod.yml — any other deployment of this repo
would silently inherit it if they forgot to set their own. Now there is
no default at all: the compose file requires the env var to be set, and
the backend refuses to start in production if PLATFORM_URL still equals
the dev value, mirroring the existing SECRET_KEY enforcement.
2026-07-22 16:19:27 +02:00
kitos 3cd0f6fd99 fix(users): admin can never strip their own admin permission
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
Both backend (PATCH /users/{id}) and frontend (Edit User modal) now block
an admin from changing their own primary role away from admin or removing
admin from their own extra_roles, closing off a self-lockout scenario.
2026-07-22 10:52:46 +02:00
kitos 66951086fb fix(auth): refresh cached user after self-role edit so RoleSwitcher shows up
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
extra_roles changes made to the currently-logged-in admin's own account
weren't reflected until logout/login, since AuthContext only fetches
/users/me once at mount. Now refetches it when the edited user is the
caller themselves.
2026-07-22 09:41:52 +02:00
kitos 06c913955c fix(campaigns,ui): remove admin from campaign-from-threat-actor gate, bump red/blue label saturation
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
- ThreatActorDetailPage wrongly let admins see/click 'Generate Campaign' —
  the backend already rejects admin there (require_any_role_strict), but
  the button was still shown, exposing a dead-end action. Now matches
  CampaignsPage's own admin-excluded gate.
- Red/blue team badges (role pills, team tabs, assignee controls, test
  state badges) bumped from -400 text/-900/50 bg to -500 text/-900/70 bg
  for more saturated, readable team colors.
2026-07-20 16:18:27 +02:00
kitos e4f768962f fix(email): use client-native fonts instead of forcing Segoe UI/Arial
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
Let each mail client render with its own default font (Calibri/Aptos/etc)
instead of a forced web-safe stack that read heavier/less familiar than
the plain-text emails.
2026-07-20 16:08:51 +02:00
kitos d25d876c2c fix(email): wire PLATFORM_URL into prod compose, was always falling back to localhost
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
Set-password links in every password-setup/reset email pointed at
http://localhost:5173 in production because PLATFORM_URL was never mapped
in docker-compose.prod.yml's backend environment block — the app silently
used its dev default. Now defaults to the real domain from CORS_ORIGINS.
2026-07-20 14:00:26 +02:00
kitos 91442ede60 feat(email): HTML branded templates with inline logo, wire remaining notification types
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
- All webhook emails now render as branded HTML (dark header, inline base64
  Aegis logo, card layout, CTA-button links) instead of plain text.
- Wired the 7 remaining notification-preference keys that had no trigger:
  stale coverage alerts, campaign-activated assignment emails, generic
  test-state-change steps (execution started / blue evaluating / in review),
  all-team-validation broadcasts on every lead vote, webhook delivery
  failures (3rd consecutive failure), new user registration, and background
  job errors (APScheduler global error listener).
- New notify_roles_by_email() helper for role-scoped, preference-gated,
  actor-excludable broadcasts.
- Fixed apscheduler.events stubbing gaps in several test files' sys.modules
  fakes that broke full-suite collection after adding the APScheduler
  error-listener import.
2026-07-20 11:49:21 +02:00
kitos 1d0d880929 feat(email): generic webhook for all notification emails, hide SMTP UI
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
- Renamed the password-setup webhook (email_webhook.*, /system/email-webhook-config)
  and made it the single transport for all notification emails.
- New webhook_email_service.py shared by password_setup_service and
  notification_service.
- Wired test validated/rejected, campaign completed, and new-MITRE-technique
  notifications through the webhook (previously dead SMTP code, never triggered).
- Added POST /system/email-webhook-test to send a real test email.
- Hid the Email/SMTP settings tab from the UI (SMTP code kept intact, unused).
- Redact email_webhook.api_key on config export.
2026-07-20 10:24:15 +02:00
kitos bbe7f49c86 feat(tests,users): blocking procedure-suggestion review on test detail, multi-role switcher, Power Automate webhook payload
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
- A lead opening a test with a pending procedure suggestion awaiting
  their review now gets a blocking popup (approve/reject only) instead
  of discovering it later in a separate queue.
- Users can be granted more than one role via extra_roles; only one is
  ever active at a time (no permission mixing) and a top-bar switcher
  lets the user swap which one, taking effect immediately since role
  is read fresh from the DB on every request.
- The password-setup/reset webhook now posts the agreed Power Automate
  contract ({to, subject, body} with the platform's standard greeting
  and signature template) and supports an admin-configured API key
  sent as an x-api-key header.
2026-07-20 09:29:36 +02:00
kitos 4dea19cae9 feat(users): passwordless user creation via emailed set-password link, display full name instead of username
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
Admins now create users with a name + email (no password) and role;
a Send Email action (per-user, also reusable for resets) issues a
one-time token and POSTs it to an admin-configurable webhook URL —
intended for a Power Automate flow that delivers the actual email.
The old admin-sets-the-password flow is kept server-side
(LegacyUserCreateWithPassword) but no longer wired into the UI.

Every user-facing surface (top bar, sidebar, user management, audit
log, assignee pickers, dispute notifications) now shows full_name
instead of username, falling back to username when unset.

Also fixes long attack_procedure/expected_detection/suggested_text
text overflowing its container in the template review panels and
Red/Blue team fields (missing break-words on whitespace-pre-wrap
blocks).
2026-07-17 16:58:25 +02:00
kitos 60ab2e558f fix(campaigns,tests): admin cannot create campaigns, manager can delete unstarted tests, intensify red/blue team colors
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
- Campaign creation and generate-from-threat-actor now use the strict
  role check — admin no longer gets a free pass into campaign content,
  same principle already applied to test-template creation.
- New manager-only DELETE /tests/{id}: removes a standalone test still
  in draft (not started, not linked to any campaign).
- Replaced the orange/indigo stand-ins used across team badges, tabs,
  action buttons, and timers with true red/blue so Red Team and Blue
  Team read unambiguously at a glance.
2026-07-17 14:34:14 +02:00
kitos 82ac9c7014 feat(templates,campaigns): validate MITRE technique IDs, surface template suggestions first, manager can re-approve rejected campaigns
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
- TestTemplate/TemplateSuggestion creation and updates now reject any
  mitre_technique_id that doesn't match a real, already-synced MITRE
  ATT&CK technique. Frontend swaps the free-text ID input for a
  technique picker.
- Test Catalog now shows pending template suggestions before the
  catalog grid, with full field detail (platform, severity, tool,
  atomic ID, source URL, remediation) instead of just name/procedure.
- A manager can edit and directly re-approve a campaign they previously
  rejected, instead of needing the original lead to resubmit it.
2026-07-16 14:29:01 +02:00
kitos 4809c4a662 feat(manager): allow manager to create auto-approved campaigns and tests from templates
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
A manager organizes and validates work, so their own campaigns skip the
draft -> submit -> pending_approval queue and go straight to active with
the start_date they provide (they're the same role that would otherwise
approve it). Manager can also now create tests from the catalog, same as
red_lead/blue_lead.
2026-07-16 12:57:20 +02:00
kitos c753797019 feat(test-catalog): add template creation and lead-approval workflow
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
Leads get a Create Template button that adds directly to the catalog
(existing POST /test-templates). Operators (red_tech/blue_tech) get the
same button, but their proposal now lands in a new template_suggestions
review queue instead — a lead on their team can approve it as-is, edit
fields before approving, or discard it. Modeled on the existing
ProcedureSuggestion review workflow.
2026-07-16 12:08:23 +02:00
kitos cf4a6c3cde fix(campaigns): defer Jira ticket creation to start_date, gate recurring campaigns behind manager approval
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
- Approve endpoint now only creates Jira tickets immediately when
  start_date is now/past; a new periodic job (every 15 min) catches
  campaigns whose scheduled start_date has since arrived.
- Recurring campaign clones now go to pending_approval instead of
  active, routing through the same manager-approval gate as any other
  campaign; managers are notified instead of red_tech.
- Fix UTC conversion for the campaign approval start_date input and
  extract shared isoToDatetimeLocal/datetimeLocalToIso helpers.
2026-07-16 11:09:10 +02:00
kitos 0b60531677 fix(users): grant manager Review Queue access, restrict Webhooks to admin
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
Manager could not see the Review Queue nav item, load the page, or
call mark-reviewed (red_lead/blue_lead/admin only) — added to the
route guard, sidebar visibility, badge query, and the backend
endpoint's role check.

Webhook Configuration was shown to red_lead/blue_lead in Settings
even though the backend already restricted every webhook endpoint to
admin only — the tab is now admin-only in the UI too, matching what
was already enforced server-side.
2026-07-16 10:31:21 +02:00
kitos 0002601b50 feat(templates): add pagination with total counts to catalog and campaign picker
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
Test Catalog's pagination showed only 'Page N' with no way to know
how many pages existed, and the campaign 'Add Test' modal's template
picker had no pagination at all — with 2800+ templates in the
catalog, its flat 100-row fetch made most templates unreachable
unless a search happened to match. Adds GET /test-templates/count
(open to any authenticated user, mirrors the list endpoint's filters)
and wires real 'Page N of M' + total-available counts into both.
2026-07-16 10:01:20 +02:00
kitos 8493a6a764 feat(nav): hide unfinished Reports section platform-wide
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
Route and nav link removed (not the page/component files, kept as a
base to resume later) — navigating to /reports now falls through to
the catch-all redirect to /dashboard for every role, including admin.

fix(campaigns): show all non-campaign tests when adding to a campaign

The 'Existing Test' picker only ever queried state=draft, but the
backend places no restriction on a test's own state when adding it to
a campaign (only the campaign's own status matters) — tests already
in progress or completed were invisible here for no real reason.
2026-07-16 08:32:31 +02:00
kitos 8d9e25703d fix(campaigns): make Expected Detection editable when adding a test to a campaign
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
Was a read-only reference shown only when the template already had
content, unlike the standalone create-from-template form where it's
an editable field feeding detect_procedure on the new test. Brought
the campaign flow in line with that so leads get the same editing
capability regardless of whether the test is going into a campaign.
2026-07-15 16:49:43 +02:00
kitos 68ab6406d4 fix(jira,tests): clarify manager-resolved disputes in Jira and the Summary tab
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
The validated/rejected Jira comment always said 'by both leads' and
never carried the manager's own notes, even when a manager had just
overridden two disagreeing votes — misleading, since that combination
of statuses is only reachable via a manager decision. Now detected
from the disagreement itself and worded accordingly, with the
manager's notes included via the existing extra-data mechanism.

Also reworks the Summary tab: Final Result moves to the top (was the
very last thing on the page) and now shows Containment alongside
Detection — previously the only place Containment appeared at all was
inside the editable Blue tab. Both team cards now show the validating
lead's notes, not just the approved/rejected badge, and flag when a
manager's decision resolved a disagreement between the two leads.
2026-07-15 15:26:00 +02:00
kitos 09553f5c42 fix(users): add manager to the valid-role whitelist
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
'manager' has been a fully-functional role throughout the app —
notifications, operator assignment, dispute mediation — but was
missing from both the user creation/update whitelist and the SSO
auto-provisioning role list, so a manager account could never
actually be created.
2026-07-15 14:16:27 +02:00
kitos 3a01facd46 feat(tests): let managers escalate and directly resolve disputed tests
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
Request Discussion only ever nudged the peer lead, and the one-time
manager notification when a dispute starts had no real follow-up
action attached to it — a manager could be told a dispute existed but
had no way to actually do anything about it. Adds:

- POST /tests/{id}/escalate-to-manager — either lead can explicitly
  ask managers to step in, distinct from the passive initial notice.
- POST /tests/{id}/manager-resolve-dispute — a manager decides the
  final outcome (validated/rejected) directly, bypassing both leads'
  votes entirely, reusing the same dual-validation event dispatch so
  Jira/notifications behave like any other resolution.

Both leads are notified of the manager's final call, win or lose.
2026-07-15 13:03:01 +02:00
kitos 32f4fd25bd fix(tests): surface cross-validation and disputed tests in the review queue
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
Cross-validation (in_review) tests awaiting a lead's vote were only
reachable via the 'My Tasks' toggle, so the default review queue view
never showed them despite being exactly the kind of work a lead
expects to find there. Added an 'Awaiting My Validation' section to
the review queue, and a standalone 'Disputed' section — always
fetched independently of other filters, shown above everything else,
and only rendered when non-empty — since disputed tests need the
most urgent attention.
2026-07-15 11:41:29 +02:00
kitos 8973f199b8 feat(tests): make Expected Detection editable when creating a test from template
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
Leads can now edit Expected Detection in the create-from-template
form, same as Suggested Attack Procedure — the edit seeds the new
test's detect_procedure via a detect_procedure_override, without
touching the template itself. The template only updates later through
the existing procedure-suggestion approval flow, once a round is
actually submitted — same mechanism as the red side, no new bypass.
2026-07-15 11:05:41 +02:00
kitos 60f9464ec5 refactor(tests): merge detect_suggested_procedure into expected_detection
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
Two overlapping TestTemplate fields (expected_detection: narrative
guidance from imports/leads; detect_suggested_procedure: concrete
commands from approved suggestions) are now one. Blue-side procedure
suggestions target expected_detection directly, appending onto
whatever is already there rather than overwriting it — same
merge-not-overwrite behavior already used for the red side. Existing
detect_suggested_procedure data is folded into expected_detection
before the column is dropped.
2026-07-15 10:29:13 +02:00
kitos 7416d1688f fix(jira): unwrap detection_result enum in the in_review comment
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
Was rendering the raw Python enum repr (TestResult.detected) instead
of the plain value, the only branch in _build_state_comment that
skipped _enum_value(). Caught while verifying the system-gap fix on a
live ticket.
2026-07-15 09:57:46 +02:00
kitos 44fdb4dbd3 fix(jira,tests): push system gaps to Jira, show detect suggested procedure in catalog
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
flag_blue_review_gap saved system_gaps on the test but the Jira
in_review comment never mentioned it, so a flagged capability gap was
silently invisible in Jira. Now included in the comment and tagged
with a system-gap label for filtering.

Also surfaces TestTemplate.detect_suggested_procedure as a read-only
reference in the Test Catalog's create-from-template modal — it was
only ever shown in the admin template editor, not here, so an approved
suggestion appeared to vanish when viewed from the catalog.
2026-07-15 08:56:19 +02:00
kitos 11080bd627 fix(tests): recognize sysmon, wevtutil, auditpol as detection commands
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
Blue's detect_procedure extraction had zero Blue-team-oriented tool
names in its known-binaries list — sysmon.exe, one of the most common
Windows detection tools, silently produced no suggestion at all.
Verified against the exact production input that surfaced this.
2026-07-14 17:24:14 +02:00
kitos 1b7fd6fb36 fix(tests): restrict On Hold/Resume to whichever team currently owns the test
canHold checked role OR role instead of matching the current phase, so
a red_tech still saw (and could call) Hold/Resume on a test already
sitting in blue_evaluating. Fixed on both frontend and backend — the
API had the same gap, not just the button visibility.
2026-07-14 17:24:05 +02:00
kitos 8fcd733d4a fix(tests): merge approved procedure suggestions instead of overwriting
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
Approving a suggestion was replacing the template's whole procedure
field with just that submission's extracted text, silently dropping
whatever an earlier approved round had already added. Now it appends
only the genuinely new lines, so templates accumulate commands across
rounds instead of losing them.
2026-07-14 16:25:24 +02:00
kitos 4692a8b93e feat(tests): add Detect Procedure UI, template suggested-procedure editing, lead review panel
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
Blue Team gets a Detect Procedure textarea in the test detail view,
mirroring Red's Attack Procedure field. Template create/edit forms
gain a Detect Suggested Procedure field for leads to curate directly.
Leads also get a Procedure Suggestions panel on the Tests page,
scoped to their own team by the backend, to approve or reject
suggestions extracted from submitted rounds.
2026-07-14 15:30:47 +02:00
kitos 7ec3c5bc8b feat(tests): auto-propose procedure suggestions from submitted rounds, add lead review workflow
When Red or Blue submits a round for a test created from a template,
any extractable command in their procedure text is proposed as an
update to the template's suggested procedure — never written
automatically. Adds GET/approve/reject endpoints scoped so a lead only
reviews their own team's suggestions; approving writes the suggested
text into the template, rejecting leaves it untouched.
2026-07-14 15:22:03 +02:00
kitos 8bdbe48fbe feat(tests): add Blue detect_procedure field mapped from template suggestion
Blue Team gets a detect_procedure field on Test (what they actually
did to detect the attack), Blue's counterpart to Red's procedure_text.
It's seeded from a new detect_suggested_procedure field on
TestTemplate at test-creation time, so a junior who later reuses the
same template starts with prior guidance instead of a blank field.

Also adds the procedure_suggestions review table and Test.source_template_id,
laying the groundwork for suggesting template improvements from filled-in
procedure fields (reviewed and approved by a lead, never auto-written).
detect_procedure is archived (not cleared) on Blue reopen, matching
blue_summary, and now appears in the Jira round-archived and blue_review
comments alongside the existing detection/containment fields.
2026-07-14 14:58:29 +02:00
kitos fd94e55799 feat(tests): add regex-based command extraction heuristic
Extracts the actual command(s)/query out of a free-text procedure
field, discarding narrative and pasted output, for use in building
procedure-improvement suggestions from operator submissions.
2026-07-14 13:36:25 +02:00
kitos f87959369b fix(tests): remove blind visibility, both teams always see each other's fields
Red and Blue could not see each other's real field data until both
reviews passed, showing a placeholder message instead. This kept
detection testing blind to what Red actually did; both sides now see
the full, live test data at all times.
2026-07-14 13:36:19 +02:00
kitos bdc6579c10 fix(jira): stop sending numeric hours to Time to Detect/Contain (datetime fields)
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
Confirmed via issue_editmeta and a real production failure log: Time to
Detect / Time to Contain are Jira datetime fields despite the name, not
numeric duration fields. Pushing a computed hour count made Jira reject
the entire fields payload (validated atomically), silently sinking BT End
Date and Attack Detected on the same call even though only these two
fields were actually invalid. Now pushes the real detection_time/
containment_time timestamps. Removed the now-unused _compute_hours.
2026-07-14 12:48:14 +02:00
kitos 92d65374ef fix(tests): stop requiring Containment Time when result is Not Contained
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
Containment Time was gated on detection alone, so picking "Not Contained"
still showed the field and required it before saving — there's no
containment moment to record when nothing was contained. Now only shown
and required when the result is Contained or Partially Contained; a
stale value from a prior Contained selection is cleared when the result
changes away from it, so it can't get silently resubmitted once hidden.
2026-07-14 12:00:53 +02:00
kitos 9d66c30127 feat(tests): add team queue overview section for leads
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
red_lead/blue_lead never saw a plain "All Tests" list — they were always
routed into their own review two-queue view or "My Tasks", with no way to
see every test and who's actually working it. Adds an always-visible
section at the end of the Tests page for leads showing every test with
both Red and Blue assignee columns, so they can monitor the queues and
spot a stuck ticket or an overloaded operator.

The list endpoint (GET /tests) now joinedloads the assignee relationships
and resolves usernames the same way the detail endpoint already does, so
the new section doesn't depend on GET /users/operators (lead/manager-only).
2026-07-14 11:03:17 +02:00
kitos c6bdded3f6 fix(jira): keep BT Start Date across reopens, resolve Jira accounts on the fly everywhere
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
- BT Start Date had the same bug RT Start Date did: pushed on every round,
  clobbering round 1's real pickup date. Now only pushed on round 1,
  mirroring the "first round survives every reopen" rule.
- push_test_event's assignment branches (red_executing, red/blue reviewer,
  blue_evaluating reassignment) only read the cached jira_account_id and
  silently no-op'd if it was never populated — which is exactly what
  happened to a blue_lead who hadn't logged in since Jira was configured,
  making it look like Blue's reviewer reassignment was broken when Red's
  wasn't purely because that particular red_lead happened to have logged
  in already. Extracted the live-lookup fallback that only
  push_assignee_update had into a shared _resolve_jira_account_id(), used
  by every assignment call site now.
2026-07-14 10:23:30 +02:00
kitos 814cfa9671 feat(jira): label standalone tests, include round data in submission comments
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
- Tests created without a campaign parent ticket now get a "standalone-test"
  label, so they're identifiable in Jira without cross-referencing Aegis.
- The comment posted on every red/blue submission was a generic one-liner
  with no data — only a reopened round got a full data dump (via
  push_round_archived), so a round that was approved outright left no
  record in Jira of what was actually done. Now every submission comment
  includes the round number, procedure/tool/attack success (red) or
  detection/containment result (blue), and summary.
2026-07-14 08:37:40 +02:00
kitos 6d6f87b968 fix(jira,tests): send real datetime to RT/BT date fields, resolve assignee usernames for operators
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
- RT/BT Start/End Date are genuine Jira "datetime" custom fields (confirmed
  via issue_editmeta), not plain dates. Pushing a bare "YYYY-MM-DD" string
  made Jira default the time-of-day to midnight, so RT Start Date and RT
  End Date ended up showing the same meaningless midnight timestamp instead
  of the actual execution window. Now sends a full ISO datetime.
- The test detail page showed "RT: Unassigned" for the operator who WAS
  correctly assigned, because GET /users/operators (the only source
  AssigneeControl used to resolve an assignee ID into a username) is
  restricted to leads/managers — a plain operator has no other way to
  resolve their own ID. TestOut now resolves and includes the assignee's
  username directly (red/blue tech + reviewer), so the badge no longer
  depends on a permission-gated list the viewer might not have access to.
2026-07-13 16:53:31 +02:00
kitos 4221d2858b 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.
2026-07-13 14:57:42 +02:00
kitos b48de743b6 fix(tests): keep free-text round fields in place on reopen, only blank verdicts
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
Only the per-round verdict/timing fields (attack_success, execution
start/end for red; detection_result, containment_result, detection/
containment time for blue) get cleared on reopen — the operator must
answer those fresh for each round, and the prior round's answer stays
visible via round_history + the archived Phase Timeline card. Free-text
fields (procedure_text, tool_used, red_summary, blue_summary) are no
longer cleared: the operator edits them in place for the new round
instead of retyping everything from scratch.
2026-07-13 12:46:46 +02:00
kitos 8fe38dc661 feat(tests): archive round history on reopen, stop pausing from setting Jira On Hold
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
- Reopening a test for rework (red or blue) now archives the round that's
  ending into a new test_round_history table before resetting the live
  fields — procedure/results/detection data is preserved instead of
  overwritten, and Phase Timeline renders every past round alongside the
  current one, so Blue Team keeps visibility into earlier Red attempts.
- Each archived round also posts a permanent Jira comment (push_round_archived)
  since Jira's custom fields only ever show the latest value once the next
  round resubmits — the comment thread is what preserves full history there.
- push_pause_event no longer transitions the Jira issue to "On Hold" — a
  timer pause is not a real Hold, and flipping Jira status for it was
  misleading. Only the explicit Hold action (push_hold_event) does that now.
2026-07-13 12:08:45 +02:00
kitos 0bb34f6834 fix(tests): pause reopen timer, lock edits to assignee, restore Jira operator on reopen
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
- reopen_red_review starts the timer paused (paused_at set) instead of
  immediately running, since the operator hasn't resumed working yet —
  blue already did this via blue_work_started_at, red needed the same
  behavior via the existing pause/resume mechanism.
- update_test_red/update_test_blue now lock edits to the actual assigned
  operator for leads too, not just techs — a lead could previously edit
  another operator's in-progress test. Mirrored in TeamTabs.tsx.
- push_test_event reassigns the Jira ticket to the original operator
  (not the reopening lead) when a test returns to red_executing or
  blue_evaluating for rework, instead of leaving it on the lead.
2026-07-13 10:53:10 +02:00
kitos a3f86c7b31 fix(permissions): admin can no longer operate tests — start/submit/edit/create, view only
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
Admin still bypassed require_any_role (non-strict) on the pure
operator actions: start-execution, submit-red, start-blue-work,
submit-blue, pause/resume-timer, and the red/blue field-edit + general
test create/update/remediation/import-rt/template endpoints all used
the loose dependency even where admin wasn't in the role tuple.
Switched every one of these to require_any_role_strict, matching the
review/validate/dispute/hold/assign endpoints already fixed earlier.

Frontend: removed every remaining role === "admin" disjunct gating
Start Execution, Submit to Blue Team, blue evaluating actions, timer
control, red/blue field editing, test creation, and template creation.
Team-blindness visibility (isBlind) deliberately keeps the admin
bypass — admin still sees both sides unmasked for oversight, since
that's visibility, not operating.

Updated ~20 tests whose fixtures used the admin account as a
convenience shortcut to create/drive tests through the workflow —
switched them to a red_lead account, fixing an incidental
fixture-resolution-order cookie bug along the way (client's cookie
jar prefers the last-logged-in role's cookie over any Bearer header
explicitly passed to a later request).
2026-07-13 09:27:43 +02:00
kitos 337faf824d fix(jira): clear stale assignee on hand-off to blue team / dual validation
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
The red_lead reviewer stayed assigned in Jira through blue_evaluating
(and the blue_lead reviewer through in_review) since push_test_event
never touched the assignee on those transitions — only red_executing
and the review gates did. Both are hand-offs with no single owner yet,
so the assignee is cleared instead of left stale.

Also fixes push_bt_work_started never assigning the blue_tech who
actually picks up the queued test — it only moved the status to
In Progress before.
2026-07-10 16:49:16 +02:00
kitos 0fc2427f71 feat(review): review queue for leads + manual reviewer reassignment
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
Leads get the same two-queue view operators already have: 'Available
to Review' (pending reviews currently assigned to a peer lead) and
'My Assigned Reviews' (assigned to me), replacing the old single
'My Reviews' toggle. Since the load-balanced auto-assignment always
picks a reviewer immediately, 'available' means peer-assigned reviews
a lead could pick up if the assignee can't get to them, not unclaimed
ones (there aren't any).

POST /tests/{id}/assign now also accepts red_reviewer_assignee /
blue_reviewer_assignee, validated against the matching lead role and
synced to Jira the same way operator assignment already is. The
AssigneeControl UI gained a 'reviewer' kind (leads-only picker) shown
on the test detail header while a test sits in red_review/blue_review
— this also fixes the reviewer assignment being invisible in Aegis
even though it was already being pushed to Jira correctly.
2026-07-10 16:19:14 +02:00