Module: utils/notifications

Failure notification dispatcher (FEA-001).

Dispatches notifications to configured channels when a test run completes with failures. Supports three channels:

  1. Microsoft Teams — Adaptive Card via incoming webhook.
  2. Email — HTML summary via the existing emailSender.js transport.
  3. Generic webhook — POST JSON payload to a user-configured URL.

All dispatches are best-effort: errors are logged but never propagate to the caller, so a failing notification never affects the run outcome.

Usage

import { fireNotifications } from "../utils/notifications.js";
await fireNotifications(run, project);
Source:

Methods

(static) dispatchSiemEvent(workspaceId, row, optsopt) → {Promise.<Object>}

SEC-007 Part C — forward a single audit row to the workspace's configured SIEM target.

Lookup chain:

  1. Read per-workspace config via workspaceSiemConfigRepo.getDecrypted. If no row, or row has enabled = false, return immediately (no-op).
  2. POST the row as one NDJSON line with: Content-Type: application/x-ndjson X-Sentri-Audit-Signature: sha256=<hex(hmac(secret, body))> ... + any configured custom headers (e.g. Splunk HEC token).
  3. Retry on 5xx / 408 / 429 with backoff (immediate, then 1s, then 2s).
  4. After 3 attempts, enqueue the row in audit_dlq so an admin can replay it via the AuditLog DLQ inspector.

Fire-and-forget contract: this function NEVER throws to the caller. It's invoked from logActivity after every audit INSERT, and a SIEM outage MUST NOT block the originating request. Failures land in the DLQ; persistent outages surface as a non-empty DLQ count in the UI.

Parameters:
Name Type Attributes Description
workspaceId string

The workspace whose SIEM config to load.

row Object

The activity row that was just persisted.

opts Object <optional>
Properties
Name Type Attributes Default Description
skipDlqOnFailure boolean <optional>
false

When true, a failed dispatch will NOT enqueue a fresh DLQ row. Used by the admin DLQ replay path so that retrying an existing DLQ row doesn't create a duplicate row each time it fails — the route handler manages the original row's attempts counter via auditDlqRepo.incrementAttempts instead. Default false preserves the original fire-and-forget contract for the logActivity dispatch path.

Source:
Returns:

{ ok: boolean, attempts?: number, lastError?: string }

Type
Promise.<Object>

(static) fireNotifications(run, project) → {Promise.<void>}

Fire all configured notification channels for a completed run.

Only dispatches when:

  1. The run has failures (run.failed > 0).
  2. The project has notification settings configured and enabled.

All dispatches are best-effort — errors are logged but never thrown.

Parameters:
Name Type Description
run Object

The completed run object.

project Object

The project { id, name, url }.

Source:
Returns:
Type
Promise.<void>

(inner) formatDuration(run) → {string}

Compute human-readable run duration.

Parameters:
Name Type Description
run Object
Source:
Returns:
Type
string

(inner) getAppUrl() → {string}

Build the base URL for deep links into the Sentri UI.

Source:
Returns:
Type
string

(inner) getFailingTestNames(run) → {Array.<string>}

Extract failing test names from run results.

Parameters:
Name Type Description
run Object
Source:
Returns:
Type
Array.<string>

(inner) runDetailUrl(runId) → {string}

Build a deep link URL to a specific run detail page.

Parameters:
Name Type Description
runId string
Source:
Returns:
Type
string

(async, inner) sendEmailNotification(recipients, run, project) → {Promise.<void>}

Send a failure notification email to all configured recipients.

Parameters:
Name Type Description
recipients string

Comma-separated email addresses.

run Object

Completed run object.

project Object

Project object.

Source:
Returns:
Type
Promise.<void>

(async, inner) sendTeamsNotification(webhookUrl, run, project) → {Promise.<void>}

Send a Microsoft Teams Adaptive Card via incoming webhook.

Parameters:
Name Type Description
webhookUrl string

Teams incoming webhook URL.

run Object

Completed run object.

project Object

Project object.

Source:
Returns:
Type
Promise.<void>

(async, inner) sendWebhookNotification(url, run, project) → {Promise.<void>}

Send a generic webhook notification (POST JSON).

Parameters:
Name Type Description
url string

Webhook URL.

run Object

Completed run object.

project Object

Project object.

Source:
Returns:
Type
Promise.<void>