Skip to main content

Notifications

The notification system tells you about events on projects you care about — scans finishing, gates failing, new CVEs landing on a component you depend on, approvals waiting, and license-policy violations. Notifications fan out across four channels (in-app, email, Slack, Microsoft Teams) and you decide globally which channels to receive on.

Audience

Any signed-in user. The header bell and /notifications page are visible to every role; admins additionally configure the SMTP / Slack / Teams transports under Disk & system health.

note

Notification triggers are wired into the producing services — scans, vulnerability ingest, license findings, the build gate, and the approval workflow all emit in-app rows (and external channels per your Preferences). See the full trigger catalog under Triggers.

The header bell

Every page has a bell icon in the top-right of the header. The badge shows the number of unread in-app notifications:

  • 0 — no badge.
  • 1–99 — exact count.
  • 100+ — capped at 99+ so the badge does not break the layout.

Header bell with the unread-count badge — the red circle to the upper right of the bell carries the current unread total

Click the bell to navigate directly to the /notifications inbox. The bell does not surface a dropdown preview in this release — see Roadmap.

The Inbox at /notifications

/notifications is the full list of every notification you have received, newest first. Pages of 20 are loaded one at a time; use the Previous / Next controls at the bottom to walk through history.

Notifications inbox at /notifications — read/unread rows with kind badges and pagination controls

Each row shows:

  • Title — bold while unread.
  • Body — one or two lines.
  • Channel icons — which channels delivered this event for you (in-app always shows; email / Slack / Teams show only if you opted in).
  • Timestamp — absolute on hover, relative otherwise.
  • Mark read — a click anywhere on the row marks it read; the row dim-loads.
  • Open — clicking navigates to the source resource and marks read on the way.

Bulk actions: Mark all as read (clears the unread badge for the current page).

Preferences

Below the inbox, the Preferences section lists every trigger with four global, per-channel toggles. The choice applies across every trigger — there is no per-trigger matrix in this release (see Roadmap).

Notifications preferences — per-channel toggles for email, Slack, Teams, and the always-on in-app row

ChannelDefaultNotes
In-apponThe fallback channel. Always available; toggle still surfaces for symmetry.
EmailonRequires SMTP_* configured by the operator.
SlackoffRequires SLACK_WEBHOOK_URL configured.
TeamsoffRequires TEAMS_WEBHOOK_URL configured.

Toggles enter a draft state. Click Save to persist your changes — the page tracks dirty state and disables Save until something changes.

Routing rules: who else hears

Your toggles decide what reaches you. A routing rule decides who else hears, and it is written by an administrator rather than by the person receiving it. The rule an organization actually has is usually of this shape: "the security team hears about every critical finding", or "release@ gets a line whenever a scan finishes in this one project".

A rule names some conditions and some destinations. Every condition is optional and an absent one matches everything:

  • Kinds: which triggers it covers. Empty means all of them.
  • Minimum severity: that severity and everything above it. A rule naming one does not fire for a notification that carries no severity at all, since "no severity" is the absence of an answer rather than a low one.
  • Project: one project, and it must be a project the rule's scope covers.

And the destinations: channels to add, addresses to add, or both. A rule that names neither is refused, because a row that does nothing reads later as a row that is broken.

Team administrators write rules for their own team at POST /v1/notification-rules/teams/{team_id}; a super admin writes rules for the whole deployment at /v1/notification-rules/org/{organization_id}. Reading is open to everyone in the team, so people can see what reaches them without being able to change it. A team's list includes the organization's rules, because those apply to the team too.

Rules add, and never take away

Every rule whose condition matches contributes, and the results are combined. A rule cannot remove a recipient or switch off a channel somebody enabled: two mechanisms deciding one question would mean the silencing one wins an argument nobody had, and a person whose notifications quietly stopped would have no way to find out why.

Write no rules and nothing changes. Every notification goes exactly where it went before.

How fresh is the bell?

The frontend polls the unread count every 60 seconds while the tab is active. Two optimisations keep the channel lean:

  • When the browser tab is hidden (Page Visibility API reports hidden), polling pauses to conserve battery and server bandwidth.
  • When the tab regains focus, the frontend fires an immediate poll so the badge catches up before the next 60-second tick.

If you have multiple portal tabs open, each polls independently — the unread state is server-authoritative, so the counts converge.

Triggers

Eight distinct triggers fire notifications:

TriggerWhen it fires
scan_completedA scan you started, or one on a project you watch, finishes successfully.
scan_failedA scan you started, or one on a project you watch, fails.
cve_detectedA new CVE lands on a component already present in one of your scans (DT NVD ingest correlates against existing components).
license_violationA scan surfaces a forbidden-license component on a project you watch.
approval_pendingA component requires approval. In this release the notification is delivered to all super-admins in the org (no per-team approver routing); a designated-approver model is on the roadmap.
approval_state_changedAn approval request you filed changes state (approved / rejected / moved to review) — the requester is notified of the disposition.
policy_gate_failedA CI build gate fails (Critical CVE or forbidden license blocks the build).
vuln_sla_breachOpen findings on a project's latest succeeded scan crossed their remediation-SLA due date within the last 24 hours (daily sweep at 02:45 UTC). One aggregated alert per project, delivered to every member of the owning team, with a link to the Vulnerabilities tab pre-filtered to overdue. See Remediation SLA and aging.
malicious_detectedA component already present in a project's latest succeeded scan was named by a newly published malicious-package advisory (weekly re-check, Sundays 02:40 UTC). No scan produces this finding — nobody re-scans an old release. Delivered to every member of the owning team. Treat it as an incident, not an upgrade: the published artifact is the attack, so remove it and rotate any credential the build had access to. See Malicious packages.

Channel selection is global — the Preferences tab decides which channels deliver every trigger. Two exceptions: vuln_sla_breach and malicious_detected are delivered in-app only (your in-app preference is still respected); it never goes out via email, Slack, or Teams.

Verify it worked

  • Trigger a scan on a project you own; within seconds of completion, the bell badge increments and /notifications shows the new row.
  • Open /notifications in a second tab and mark a row read; the first tab's bell badge decrements within 60 seconds.
  • Globally disable email under Preferences and click Save; run another scan and confirm the next scan_completed notification arrives via in-app only.

Troubleshooting

  • Bell badge never updates — the tab may be hidden behind another window. Bring it to the foreground; the immediate poll on focus refreshes the count.
  • Email never arrives — verify the operator has configured SMTP and that the destination address is your verified email (visible on /profile).
  • Slack message never arrives — confirm the operator has set SLACK_WEBHOOK_URL and that the channel still exists. Slack returns 404 silently when a webhook is revoked.

Roadmap

Items the manual previously promised that are not in this release; tracked for later releases.

  • Header-bell dropdown with the five most recent notifications and a "go to inbox" footer — planned; today the bell navigates straight to /notifications.
  • Infinite scroll on /notifications — planned; today the inbox uses Previous / Next pagination.
  • Per-trigger × per-channel preference matrix (e.g. Slack only for policy_gate_failed) — planned; today the channel choice is global across all triggers.
  • disk_pressure notification trigger for admins — planned; the disk-pressure event is currently surfaced only on the admin dashboard.

See also