main
md 22.5 KB

Database Schema (AI Agent-Oriented)

This document summarizes the current schema for AI-agent workflows, using Alembic migrations as source of truth in backend/alembic/versions/*.py.

  • Current migration head in this repo: fb51d610b306 (backend/alembic/versions/fb51d610b306_add_github_audit_tables.py)
  • Base migration: bdf40d064ed1 (backend/alembic/versions/bdf40d064ed1_initial_database_migration.py)

Practical Domain Map

For typical agent change work, these domains are most relevant:

  • Connectors and integration metadata: connectors*, available_*, customer_*_connectors*, customer_*integrations*, integration_*, network_connectors_*, custom_alert_creation_*, monitoring_alerts, sigma_queries, github_audit_*
  • Auth / users / roles: user, role, user_customer_access, user_tag_access, role_tag_access
  • Incidents (alerts/cases/tags/comments): all incident_management_* tables
  • Scheduler/job metadata: scheduled_job_metadata, schedulerjob, index_snapshot_schedules
  • Agent data store / artifacts / reports: agent_datastore, incident_management_case_datastore, incident_management_case_report_template_datastore, vulnerability_reports, sca_reports, agent_vulnerabilities

Critical relationship graph

Compact relationship views for incident workflows and access controls.

incident_management_alert
  id (PK)
    |
    | 1-to-many via incident_management_asset.alert_linked
    v
incident_management_asset
  alert_linked (FK -> incident_management_alert.id)
  alert_context_id (FK -> incident_management_alertcontext.id)
  index_name, index_id (origin pointer into SIEM index document)
incident_management_case                      incident_management_alert
  id (PK)                                     id (PK)
     \                                           /
      \                                         /
       +-- incident_management_casealertlink --+
             case_id  (FK -> incident_management_case.id)
             alert_id (FK -> incident_management_alert.id)
             PK(case_id, alert_id)

Tags (alert/tag join)

incident_management_alert                 incident_management_alerttag
  id (PK)                                 id (PK), tag
     \                                      /
      \                                    /
       +-- incident_management_alert_to_tag --+
             alert_id (FK -> incident_management_alert.id)
             tag_id   (FK -> incident_management_alerttag.id)
             PK(alert_id, tag_id)

IoCs (alert/ioc join)

incident_management_alert                  incident_management_ioc
  id (PK)                                  id (PK), value/type/description
     \                                       /
      \                                     /
       +-- incident_management_alert_to_ioc --+
             alert_id (FK -> incident_management_alert.id)
             ioc_id   (FK -> incident_management_ioc.id)
             PK(alert_id, ioc_id)

Comments (alert comments + case comments)

incident_management_comment
  alert_id (FK -> incident_management_alert.id)
  comment, user_name, created_at

incident_management_case_comment
  case_id (FK -> incident_management_case.id)
  comment, user_name, created_at

Case datastore + report template datastore

incident_management_case
  id (PK)
    |
    | 1-to-many via incident_management_case_datastore.case_id
    v
incident_management_case_datastore
  case_id (FK -> incident_management_case.id)
  bucket_name, object_key, file_name, file_hash, upload_time

incident_management_case_report_template_datastore
  (global report templates; no case FK)
  report_template_name, bucket_name, object_key, file_name, file_hash, upload_time

Tag access control and alert visibility

incident_management_tag_access_settings
  enabled, untagged_alert_behavior, default_tag_id (FK -> incident_management_alerttag.id)

user_tag_access (user_id, tag_id)   role_tag_access (role_id, tag_id)
        \                                  /
         +------ allowed tag ids per identity ------+
                           |
incident_management_alert_to_tag (alert_id, tag_id)
                           |
                   incident_management_alert

When tag access control is enabled, alert visibility is constrained by the tag IDs reachable through user_tag_access and/or role_tag_access joined through incident_management_alert_to_tag. incident_management_tag_access_settings controls whether this filtering is active and what happens for untagged alerts (untagged_alert_behavior, optional default_tag_id fallback).

Tag access enforcement location (code pointers) - Core tag RBAC logic: backend/app/incidents/middleware/tag_access.py (TagAccessHandler) - is_tag_rbac_enabled() (global enable/disable) - build_alert_query_filters() (computes accessible tags + untagged behavior) - check_alert_tag_access() / can_user_access_alert() (per-alert decision) - Applied in incident DB query layer: - backend/app/incidents/services/db_operations.py uses tag_access_handler.build_alert_query_filters() to add SQL exists() conditions when counting/listing alerts.

SIEM data origin + query pattern

  • Graylog alerting uses the gl-events index pattern (for example gl-events* in query flows).
  • Those Graylog alert documents live in Wazuh indexer storage (OpenSearch-backed).
  • Wazuh indexer is the backing SIEM event store across event sources (endpoints, O365 integrations, network connectors, and other ingested streams).
  • CoPilot commonly resolves and displays SIEM records by querying Wazuh indexer with index_name plus index_id.
  • Code pointers:
    • backend/app/connectors/wazuh_indexer/routes/alerts.py
    • backend/app/connectors/wazuh_indexer/services/alerts.py
    • backend/app/routers/wazuh_indexer.py
    • frontend/src/api/endpoints/alerts.ts

Table Inventory (Alembic-Derived)

Customer, Auth, and Core Platform

Table PK Important columns Foreign keys Model file(s)
customers id customer_code, customer_name, contact/address fields, created_at None backend/app/db/universal_models.py (Customers)
customersmeta id customer_code, Graylog/Grafana/Wazuh metadata, customer_meta_portainer_stack_id customer_code -> customers.customer_code backend/app/db/universal_models.py (CustomersMeta)
customer_provisioning_default_settings id cluster_name, cluster_key, master_ip, grafana_url, wazuh_worker_hostname None backend/app/customer_provisioning/models/default_settings.py
user id username, password, email, created_at, role_id role_id -> role.id backend/app/auth/models/users.py (User)
role id name, description None backend/app/auth/models/users.py (Role)
user_customer_access id user_id, customer_code, created_at user_id -> user.id, customer_code -> customers.customer_code backend/app/auth/models/users.py
user_tag_access id user_id, tag_id, created_at user_id -> user.id, tag_id -> incident_management_alerttag.id backend/app/auth/models/users.py
role_tag_access id role_id, tag_id, created_at role_id -> role.id, tag_id -> incident_management_alerttag.id backend/app/auth/models/users.py
license id license_key, customer/company identity fields None backend/app/db/universal_models.py (License)
license_cache id license_key, feature_name, is_enabled, cached_at, expires_at, license_data None backend/app/db/universal_models.py (LicenseCache)
log_entries id timestamp, event_type, user_id, route, status_code, message None backend/app/db/universal_models.py (LogEntry)
customer_portal_settings id title, logo_base64, logo_mime_type, updated_at, updated_by None backend/app/db/universal_models.py (CustomerPortalSettings)

Agents, Vulnerability, and Artifact/Data Store

Table PK Important columns Foreign keys Model file(s)
agents id agent_id, host/OS/status fields, velociraptor_*, customer_code, quarantined, velociraptor_org customer_code -> customers.customer_code backend/app/db/universal_models.py (Agents)
agent_datastore id agent_id, velociraptor_id, artifact_name, flow_id, storage columns (bucket_name,object_key,file_name), file_hash, status agent_id -> agents.agent_id backend/app/db/universal_models.py (AgentDataStore)
agent_vulnerabilities id cve_id, severity, title, status, discovered_at, agent_id, customer_code agent_id -> agents.agent_id, customer_code -> customers.customer_code backend/app/db/universal_models.py (AgentVulnerabilities)
vulnerability_reports id report_name, customer_code, storage columns, generated_at, vulnerability counters, status customer_code -> customers.customer_code backend/app/db/universal_models.py (VulnerabilityReport)
sca_reports id report_name, customer_code, storage columns, generated_at, SCA counters, status customer_code -> customers.customer_code backend/app/db/universal_models.py (SCAReport)

Scheduler and Job Metadata

Table PK Important columns Foreign keys Model file(s)
scheduled_job_metadata id job_id, last_success, time_interval, extra_data, enabled, job_description None backend/app/schedulers/models/scheduler.py (JobMetadata)
schedulerjob id next_run_time, job_state None backend/app/db/universal_models.py (SchedulerJob)
index_snapshot_schedules id schedule metadata (name, index_pattern, repository), retention/last execution fields None backend/app/connectors/wazuh_indexer/models/snapshot_and_restore.py

Connectors and Integrations

Table PK Important columns Foreign keys Model file(s)
connectors id connector identity/endpoint/auth fields, capability flags, connector_enabled None backend/app/connectors/models.py (Connectors)
connectorhistory id connector_id, change_timestamp, change_description connector_id -> connectors.id backend/app/connectors/models.py (ConnectorHistory)
available_integrations id integration_name, description, integration_details None backend/app/integrations/models/customer_integration_settings.py
available_integrations_auth_keys id integration_id, integration_name, auth_key_name integration_id -> available_integrations.id backend/app/integrations/models/customer_integration_settings.py
customer_integrations id customer_code, integration_service_id, integration_service_name, deployed None backend/app/integrations/models/customer_integration_settings.py
integration_services id service_name, auth_type None backend/app/integrations/models/customer_integration_settings.py
integration_subscriptions id customer_id, integration_service_id customer_id -> customer_integrations.id, integration_service_id -> integration_services.id backend/app/integrations/models/customer_integration_settings.py
integration_configs id integration_service_id, config_key, config_value integration_service_id -> integration_services.id backend/app/integrations/models/customer_integration_settings.py
integration_auth_keys id subscription_id, auth_key_name, auth_value subscription_id -> integration_subscriptions.id backend/app/integrations/models/customer_integration_settings.py
customer_integrations_meta id Graylog/Grafana metadata (graylog_*, grafana_*, grafana_datasource_uid) None backend/app/integrations/models/customer_integration_settings.py
available_network_connectors id network_connector_name, description, network_connector_details None backend/app/network_connectors/models/network_connectors.py
available_network_connectors_keys id network_connector_id, network_connector_name, auth_key_name network_connector_id -> available_network_connectors.id backend/app/network_connectors/models/network_connectors.py
customer_network_connectors id customer_code, network_connector_service_id, network_connector_service_name, deployed None backend/app/network_connectors/models/network_connectors.py
network_connectors_services id service_name, auth_type None backend/app/network_connectors/models/network_connectors.py
network_connectors_subscriptions id customer_id, network_connectors_service_id customer_id -> customer_network_connectors.id, network_connectors_service_id -> network_connectors_services.id backend/app/network_connectors/models/network_connectors.py
network_connectors_configs id network_connector_service_id, config_key, config_value network_connector_service_id -> network_connectors_services.id backend/app/network_connectors/models/network_connectors.py
network_connectors_keys id subscription_id, auth_key_name, auth_value subscription_id -> network_connectors_subscriptions.id backend/app/network_connectors/models/network_connectors.py
customer_network_connectors_meta id Graylog/Grafana connector metadata (graylog_*, grafana_*, grafana_datasource_uid) None backend/app/network_connectors/models/network_connectors.py
custom_alert_creation_settings id customer-wide alert-creation settings, nvd_url, custom integration URLs None backend/app/integrations/alert_creation_settings/models/alert_creation_settings.py
custom_alert_creation_event_order id alert_creation_settings_id, order_label alert_creation_settings_id -> custom_alert_creation_settings.id backend/app/integrations/alert_creation_settings/models/alert_creation_settings.py
custom_alert_creation_condition id event_order_id, field_name, field_value event_order_id -> custom_alert_creation_event_order.id backend/app/integrations/alert_creation_settings/models/alert_creation_settings.py
custom_alert_creation_event_config id event_order_id, event_id, field, value event_order_id -> custom_alert_creation_event_order.id backend/app/integrations/alert_creation_settings/models/alert_creation_settings.py
monitoring_alerts id alert_id, alert_index, customer_code, alert_source None backend/app/integrations/monitoring_alert/models/monitoring_alert.py
sigma_queries id rule_name, rule_query, active, time_interval, execution timestamps None backend/app/connectors/wazuh_indexer/models/sigma.py

Incident Management (Alerts, Cases, Tags, Comments)

Table PK Important columns Foreign keys Model file(s)
incident_management_alert id alert_name, alert_description, status, alert_creation_time, customer_code, source, assigned_to, escalated None backend/app/incidents/models.py (Alert)
incident_management_alertcontext id source, context (JSON) None backend/app/incidents/models.py (AlertContext)
incident_management_asset id alert_linked, asset_name, alert_context_id, agent_id, customer_code, index_name, index_id alert_linked -> incident_management_alert.id, alert_context_id -> incident_management_alertcontext.id backend/app/incidents/models.py (Asset)
incident_management_comment id alert_id, comment, user_name, created_at alert_id -> incident_management_alert.id backend/app/incidents/models.py (Comment)
incident_management_case id case_name, case_description, case_creation_time, case_status, case_closed_time, assigned_to, customer_code, notification_invoked_number, escalated None backend/app/incidents/models.py (Case)
incident_management_casealertlink composite: (case_id, alert_id) link table case↔alert case_id -> incident_management_case.id, alert_id -> incident_management_alert.id backend/app/incidents/models.py (CaseAlertLink)
incident_management_case_comment id case_id, comment, user_name, created_at case_id -> incident_management_case.id backend/app/incidents/models.py (CaseComment)
incident_management_alerttag id tag None backend/app/incidents/models.py (AlertTag)
incident_management_alert_to_tag composite: (alert_id, tag_id) link table alert↔tag alert_id -> incident_management_alert.id, tag_id -> incident_management_alerttag.id backend/app/incidents/models.py (AlertToTag)
incident_management_ioc id value, type, description None backend/app/incidents/models.py (IoC)
incident_management_alert_to_ioc composite: (alert_id, ioc_id) link table alert↔IoC alert_id -> incident_management_alert.id, ioc_id -> incident_management_ioc.id backend/app/incidents/models.py (AlertToIoC)
incident_management_fieldname id source, field_name None backend/app/incidents/models.py (FieldName)
incident_management_assetfieldname id source, field_name None backend/app/incidents/models.py (AssetFieldName)
incident_management_timestampfieldname id source, field_name None backend/app/incidents/models.py (TimestampFieldName)
incident_management_alerttitlefieldname id source, field_name None backend/app/incidents/models.py (AlertTitleFieldName)
incident_management_iocfieldname id source, field_name None backend/app/incidents/models.py (IoCFieldName)
incident_management_customercodefieldname id source, field_name None backend/app/incidents/models.py (CustomerCodeFieldName)
incident_management_notification id customer_code, shuffle_workflow_id, enabled None backend/app/incidents/models.py (Notification)
incident_management_case_datastore id case_id, storage fields (bucket_name,object_key,file_name), upload_time, file_hash case_id -> incident_management_case.id backend/app/incidents/models.py (CaseDataStore)
incident_management_case_report_template_datastore id report_template_name, storage fields, upload_time, file_hash None backend/app/incidents/models.py (CaseReportTemplateDataStore)
incident_management_tag_access_settings id enabled, untagged_alert_behavior, default_tag_id, updated_at, updated_by default_tag_id -> incident_management_alerttag.id backend/app/incidents/models.py (TagAccessSettings)
incident_management_velo_sigma_exclusion id name, field_matches (JSON), channel, title, customer_code, created_by, enabled None backend/app/incidents/models.py (VeloSigmaExclusion)

GitHub Audit (Added at Head)

Table PK Important columns Foreign keys Model file(s)
github_audit_config id customer/org token/configuration, filters (JSON), notification and score threshold fields None backend/app/integrations/github_audit/model.py
github_audit_check_exclusion id config_id, customer_code, check/resource selectors, approval/expiry, enabled config_id -> github_audit_config.id backend/app/integrations/github_audit/model.py
github_audit_report id config_id, organization/report metadata, summary counts, status, report JSON blobs config_id -> github_audit_config.id backend/app/integrations/github_audit/model.py
github_audit_baseline id config_id, customer_code, baseline definition, expected checks (JSON), baseline_report_id, is_active config_id -> github_audit_config.id, baseline_report_id -> github_audit_report.id backend/app/integrations/github_audit/model.py

Quick Model Scan: Tables Not Obvious From Alembic

The following SQLModel tables are defined in code but do not appear in backend/alembic/versions/*.py migrations. Treat them as drift candidates / runtime-created tables unless there is an out-of-band migration process.

Table (in SQLModel) Model file
sublimealerts backend/app/connectors/sublime/models/alerts.py (SublimeAlerts)
flaggedrule backend/app/connectors/sublime/models/alerts.py (FlaggedRule)
mailbox backend/app/connectors/sublime/models/alerts.py (Mailbox)
triggeredaction backend/app/connectors/sublime/models/alerts.py (TriggeredAction)
sender backend/app/connectors/sublime/models/alerts.py (Sender)
recipient backend/app/connectors/sublime/models/alerts.py (Recipient)
disabledrule backend/app/connectors/wazuh_manager/models/rules.py (DisabledRule)
sap_siem_multiple_logins backend/app/integrations/sap_siem/models/sap_siem.py (SapSiemMultipleLogins)

Where To Change Schema

Source of truth locations

  • Alembic migrations: backend/alembic/versions/
  • Alembic env/config: backend/alembic/env.py
  • SQLModel definitions commonly touched:
    • backend/app/db/universal_models.py
    • backend/app/incidents/models.py
    • backend/app/auth/models/users.py
    • backend/app/network_connectors/models/network_connectors.py
    • backend/app/integrations/models/customer_integration_settings.py

Practical workflow

  1. Update or add SQLModel fields/classes in the relevant model file.
  2. Generate a migration under backend/alembic/versions/ (or author manually if needed).
  3. Review migration upgrade() and downgrade() carefully (FK names, nullable transitions, indexes).
  4. Apply migration locally and run tests.
  5. Update this document if table shape/ownership changes.

Notes for agent changes

  • Prefer extending existing domain tables over creating parallel tables when possible (especially incidents and connector metadata).
  • For incident workflows, changes usually involve: incident_management_alert, incident_management_case, link tables (*_to_*), and optional datastore tables.
  • For connector onboarding, changes usually involve: available_*, customer_*, *_services, *_subscriptions, *_configs, *_keys, and *_meta tables.
  • For scheduler automation, coordinate changes between scheduled_job_metadata, schedulerjob, and domain-specific tables storing job outcomes.