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). Iffalse, 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)
report_name)Config: integrations.report_namer
What it does:
Generates a stable
report_nameused 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)stageenvironmentcsv_filecounts,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_rawReport runs:
integrations.opensearch.datasets_index_report_runsReport items (Top X):
integrations.opensearch.datasets_index_report_items
Optionally auto-creates indices with a minimal mapping when
datasets_create_index_templatesis 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_rawOne row per ingested finding/vulnerability row.
Includes normalized columns (qid, severity, ip, port, results, etc.) +
finding_json(JSONB) for full fidelity.
<schema>.qualys_report_runsOne row per report (keyed by
report_name) with metrics andindex_html_path.Includes
report_json(JSONB) with the full report model snapshot (for audit/debug).
<schema>.qualys_report_itemsOne 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_enabledis enabled, it can override sourcetype per dataset (vulnerabilities/report_runs/report_items).
Expected result:
In Splunk you will see events whose
eventfield contains the JSON payloads, including:type=
vulnerabilitytype=
reporttype=
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.htmlpath (when available)
Optional file upload:
A ZIP named
<report_folder>.zipplaced next to the report folder (for exampleoutput/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>/..., thenen-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_emailsreceive: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_emailsreceive emails equivalent to SendGrid delivery (but via your SMTP infrastructure).