Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DevDonzo/warden/llms.txt

Use this file to discover all available pages before exploring further.

Warden can push a structured notification to your team’s communication channels at the end of every scan run. Notifications are posture-driven: a critical posture fires an error-severity message, an elevated posture fires a warning, and anything better sends a success signal. This lets your alerting rules in Slack or PagerDuty key off severity rather than requiring you to parse log output.
Notifications are opt-in. The notifications.enabled field defaults to false in every new .wardenrc.json. No messages are sent until you explicitly set "enabled": true.

When Notifications Fire

The NotificationService is called by the orchestrator at the end of every scan run that produces a result. It maps the scan posture to a NotificationSeverity value:
PostureNotification severity
criticalerror
elevatedwarning
guarded or stablesuccess
The notification payload always includes the scan summary text, the total vulnerability count, how many fixes were applied, and the PR URL (if one was created).

The NotificationPayload Shape

Every channel receives the same normalized payload:
interface NotificationPayload {
  title: string;          // e.g. "Warden Scan Completed"
  message: string;        // Remediation plan summary
  severity: 'info' | 'warning' | 'error' | 'success';
  details?: {
    repository?: string;  // Target path or repo URL
    vulnerabilities?: number;
    fixed?: number;
    prUrl?: string;       // URL of the fix PR, if created
  };
}
The Slack and Discord channels render details fields as inline attachment fields. The email channel renders them as a plain-text or HTML table.

Slack

Add a notifications.slack object to .wardenrc.json:
{
  "notifications": {
    "enabled": true,
    "slack": {
      "webhook": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXX",
      "channel": "#security-alerts"
    }
  }
}
FieldRequiredDescription
slack.webhookYesSlack Incoming Webhook URL — create one at api.slack.com/messaging/webhooks
slack.channelNoChannel override (e.g. #security-alerts). If omitted, the webhook’s default channel is used
Warden posts a Slack attachment with a color-coded sidebar (#ef4444 red for error, #f59e0b amber for warning, #10b981 green for success), the scan title, the remediation summary, and inline fields for repository, vulnerability count, fixes applied, and PR URL.

Discord

Add a notifications.discord object:
{
  "notifications": {
    "enabled": true,
    "discord": {
      "webhook": "https://discord.com/api/webhooks/000000000000000000/xxxxxxxxxxxx"
    }
  }
}
FieldRequiredDescription
discord.webhookYesDiscord Webhook URL — create one under Server Settings → Integrations → Webhooks
Warden posts a Discord embed with a matching integer color (Discord does not accept hex strings), emoji prefix on the title, and the same fields as Slack.

Email via Resend

Warden’s built-in email provider is Resend. Set up an API key in the Resend dashboard and export it as an environment variable:
export RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxx
Then configure the email block:
{
  "notifications": {
    "enabled": true,
    "email": {
      "to": ["security@example.com", "oncall@example.com"],
      "from": "Warden <warden@yourdomain.com>",
      "provider": "resend",
      "apiKeyEnv": "RESEND_API_KEY",
      "subjectPrefix": "MyApp"
    }
  }
}
FieldDefaultDescription
email.toArray of recipient email addresses
email.fromSender address (must be a verified domain in Resend)
email.provider"resend"Email provider — "resend" is the only built-in provider
email.apiKeyEnv"RESEND_API_KEY"Name of the environment variable holding the Resend API key
email.subjectPrefix"Warden"Prefix used in the email subject line, e.g. [MyApp] ✅ Warden Scan Completed
If apiKeyEnv is set but the environment variable is not present at runtime, Warden skips email silently (with a debug log) rather than failing the scan.

Email via Generic Webhook

For teams that route email through Zapier, Make, an AWS SES Lambda, or an internal notification service, set email.webhook instead of configuring a Resend API key:
{
  "notifications": {
    "enabled": true,
    "email": {
      "to": ["security@example.com"],
      "from": "Warden <warden@yourdomain.com>",
      "webhook": "https://hooks.zapier.com/hooks/catch/0000000/xxxxxxx/",
      "subjectPrefix": "MyApp"
    }
  }
}
When email.webhook is set, Warden posts a JSON body to that URL via POST:
{
  "to": ["security@example.com"],
  "from": "Warden <warden@yourdomain.com>",
  "subject": "[MyApp] ⚠️ Warden Scan Completed",
  "text": "3 high-severity findings — 2 are auto-fixable via dependency upgrades.\n\nRepository: /home/runner/work/myapp\nVulnerabilities Found: 14\nFixed: 2\nPull Request: https://github.com/org/myapp/pull/47",
  "html": "<p>3 high-severity findings...</p><table>...</table>",
  "severity": "warning",
  "details": {
    "repository": "/home/runner/work/myapp",
    "vulnerabilities": 14,
    "fixed": 2,
    "prUrl": "https://github.com/org/myapp/pull/47"
  }
}
Use email.webhook when you need custom routing logic — for example, paging on-call only when severity is "error", or sending to different distribution lists based on the repository name. Your webhook handler has full access to the severity and details fields to implement any routing rule.

Complete Notifications Configuration

{
  "notifications": {
    "enabled": true,
    "slack": {
      "webhook": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXX",
      "channel": "#security-alerts"
    },
    "discord": {
      "webhook": "https://discord.com/api/webhooks/000000000000000000/xxxxxxxxxxxx"
    },
    "email": {
      "to": ["security@example.com"],
      "from": "Warden <warden@yourdomain.com>",
      "provider": "resend",
      "apiKeyEnv": "RESEND_API_KEY",
      "subjectPrefix": "MyApp"
    }
  }
}
All three channels can be active at the same time. Warden dispatches to all configured channels concurrently using Promise.all, so a failure in one channel (e.g., an expired Slack webhook) does not block the others. Failures are logged as errors but do not cause the scan to exit with a non-zero code.

Build docs developers (and LLMs) love