Integrations

This project can optionally publish run signals and datasets to external systems (chat, email, logging, search, and analytics).

How integrations are controlled

Global switches

  • notifications.enabled: enables notification channels (Slack / SendGrid / SMTP). If false, notifiers are disabled even if their integration block is enabled.

  • notifications.events_enabled + notifications.event_types: filters which RunEvent notifications are emitted (and which RunEvent documents are published to OpenSearch “events”).

  • notifications.fail_on_integration_error:

    • When true, integration failures can fail the run.

    • When false, integration failures are best-effort (logged and ignored).

Two types of outputs

  • RunEvents (notifications/log-style): start/end/error/report-ready and stage milestones. These are the events used for Slack/email and the OpenSearch “events” index.

  • Datasets (structured records): vulnerability rows, report-run summaries, and Top X report items. These are sent via Syslog/Splunk and (optionally) stored in OpenSearch dataset indices and Postgres (Metabase).


Integration: Report namer (shared report_name)

Config: integrations.report_namer

What it does:

  • Generates a stable report_name used as a shared identifier across dataset integrations (OpenSearch datasets, Metabase/Postgres, Syslog, Splunk).

  • When enabled, it may use the configured LLM to generate a short, slug-like name (no spaces, limited charset, max length). It always appends a short run id suffix for uniqueness.

Expected result:

  • Dataset records share a consistent report_name, making it easy to correlate:

    • “raw vulnerabilities” → “report run” → “report items”.


Integration: OpenSearch (RunEvent publisher)

Config: integrations.opensearch (base integration)

What it does:

  • Publishes RunEvent documents to an OpenSearch index (integrations.opensearch.index).

  • Supports strftime-style index patterns (for example qualys-ai-triage-pack-events-%Y.%m).

Expected result:

  • In OpenSearch you will see documents representing pipeline stages and outcomes, including:

    • event_type (start/end/error/report_ready)

    • stage

    • environment

    • csv_file

    • counts, duration_ms, artifacts (when present)


Integration: OpenSearch datasets (structured indices)

Config: integrations.opensearch.datasets_enabled (requires integrations.opensearch.enabled: true)

What it does:

  • Writes structured dataset documents using bulk indexing into fixed indices:

    • Vulnerabilities (raw): integrations.opensearch.datasets_index_vulnerabilities_raw

    • Report runs: integrations.opensearch.datasets_index_report_runs

    • Report items (Top X): integrations.opensearch.datasets_index_report_items

  • Optionally auto-creates indices with a minimal mapping when datasets_create_index_templates is enabled.

Expected result:

  • Index: vulnerabilities_raw

    • One document per ingested vulnerability row (includes report_name, row_seq, qid, severity, host/IP fields, etc.).

    • Document id format: "<report_name>:<row_seq>".

  • Index: report_runs

    • One document per processed CSV/run (includes generated_at, metrics like total_rows/valid/skipped/candidates/selected, and index_html_path).

    • Document id format: "<report_name>".

  • Index: report_items

    • One document per selected Top X item (includes qid, severity, priority, justification, remediation/evidence fields, and descriptive sections).

    • Document id format: "<report_name>:<candidate_id>".


Integration: Metabase (Postgres data warehouse writer)

Config: integrations.metabase (connects to a PostgreSQL database that Metabase queries)

What it does:

  • Creates (idempotently) a small schema of tables and writes scan/report data into Postgres.

  • Designed so Metabase can be connected to the database as a source and used to build dashboards.

Expected result (tables created and populated):

  • <schema>.qualys_vulnerabilities_raw

    • One row per ingested finding/vulnerability row.

    • Includes normalized columns (qid, severity, ip, port, results, etc.) + finding_json (JSONB) for full fidelity.

  • <schema>.qualys_report_runs

    • One row per report (keyed by report_name) with metrics and index_html_path.

    • Includes report_json (JSONB) with the full report model snapshot (for audit/debug).

  • <schema>.qualys_report_items

    • One row per selected Top X item (priority, justification, evidence/remediation JSON, and descriptive text fields).


Integration: Syslog (JSON sender)

Config: integrations.syslog

What it does:

  • Sends newline-delimited JSON payloads to a syslog server over UDP or TCP.

  • Uses an RFC5424-ish header for compatibility; the JSON payload is the message body.

Expected result:

  • Your syslog receiver will receive JSON messages for:

    • Vulnerability payloads (type=vulnerability)

    • Report payloads (type=report)

Notes:

  • UDP can drop messages; TCP can backpressure. Choose based on reliability needs.


Integration: Splunk HEC (HTTP Event Collector)

Config: integrations.splunk_hec

What it does:

  • Sends events to Splunk HEC as newline-delimited JSON, buffered and flushed in batches.

  • Uses host=<environment> so events are naturally grouped by scan/environment in Splunk.

  • If datasets_enabled is enabled, it can override sourcetype per dataset (vulnerabilities/report_runs/report_items).

Expected result:

  • In Splunk you will see events whose event field contains the JSON payloads, including:

    • type=vulnerability

    • type=report

    • type=report_item


Integration: Slack notifications

Config: notifications.enabled: true and integrations.slack.enabled: true

What it does:

  • Posts one message per selected RunEvent into the configured channel.

  • On report_ready, it can optionally upload a ZIP of the report folder (upload_report_zip: true).

Expected result:

  • Messages in Slack like:

    • pipeline stage summaries (parsed, selection, rendered_html, end, etc.)

    • error summaries (single-line)

    • report_ready lines including the index.html path (when available)

  • Optional file upload:

    • A ZIP named <report_folder>.zip placed next to the report folder (for example output/my_scan.zip) and uploaded to the channel.


Integration: Email via SendGrid

Config: notifications.enabled: true and integrations.sendgrid.enabled: true

What it does:

  • Sends an email per selected RunEvent using HTML + text templates from email_templates/.

  • Supports localized templates (tries <template_dir>/<lang>/..., then en-US, then root).

  • On report_ready, it can optionally attach a ZIP of the report folder (attach_report_zip: true), subject to size limits.

Expected result:

  • Recipients in integrations.sendgrid.to_emails receive:

    • Subject: [{subject_prefix}] <EVENT> · <env> · <stage>

    • Body: rendered from templates (HTML and plain text)

    • Optional ZIP attachment (when enabled and under the size limit)


Integration: Email via SMTP

Config: notifications.enabled: true and integrations.smtp.enabled: true

What it does:

  • Sends an email per selected RunEvent via an SMTP server (TLS optional).

  • Uses the same template and optional ZIP-attachment behavior as SendGrid.

Expected result:

  • Recipients in integrations.smtp.to_emails receive emails equivalent to SendGrid delivery (but via your SMTP infrastructure).