From e37a69208628747615938af732dfc98ec539bcfc Mon Sep 17 00:00:00 2001 From: rcourtman <8825017+rcourtman@users.noreply.github.com> Date: Mon, 5 Oct 2026 07:23:30 +0100 Subject: [PATCH] Point Audit Webhooks visitors to alert notifications Audit Webhooks is the only webhook page in Settings, so people looking to send alerts to Discord or Slack land there. Issue 1344 tried to add a Discord webhook from it and filed a bug when that did not work. Alert delivery lives in Alerts, Notifications, which Settings never mentions. The panel now opens, gated or enabled, with one line saying these webhooks carry security events only and linking to alert notifications. --- .../subsystems/frontend-primitives.md | 5 +++ .../internal/subsystems/security-privacy.md | 4 +++ .../17f991e2b5caadc9.json | 36 +++++++++++++++++++ .../components/Settings/AuditWebhookPanel.tsx | 24 ++++++++++++- .../__tests__/settingsArchitecture.test.ts | 7 ++++ .../auditWebhookPresentation.test.ts | 9 +++++ .../src/utils/auditWebhookPresentation.ts | 10 ++++++ 7 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 frontend-modern/browser-verification/17f991e2b5caadc9.json diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 0b0de622ad..e341fd6020 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -5948,6 +5948,11 @@ canonical `SettingsPanel` shell, while license/paywall lifecycle, webhook fetch/save flow, validation, paywall tracking, and hidden-upgrade copy posture. The shell must not re-accumulate API calls or paywall tracking inline. +Because it is the only webhook page in Settings, the shell opens with a +signpost, in both the gated and enabled states, saying audit webhooks carry +security events only and linking to the Alerts notifications tab for Discord, +Slack, ntfy or email delivery (issue #1344 tried to add a Discord webhook +here). The link is a plain anchor the app Router intercepts. The same paid-runtime-required route applies to Audit Webhooks: missing `audit_logging` caused by a community runtime must keep the panel reachable, hide normal upgrade-plan prompts, and present the private Pulse Pro runtime diff --git a/docs/release-control/v6/internal/subsystems/security-privacy.md b/docs/release-control/v6/internal/subsystems/security-privacy.md index 241e41af8d..abfc25b295 100644 --- a/docs/release-control/v6/internal/subsystems/security-privacy.md +++ b/docs/release-control/v6/internal/subsystems/security-privacy.md @@ -1325,6 +1325,10 @@ failure. If `runtime-capabilities` blocks `audit_logging` with active Pro license needs the private Pulse Pro runtime, but they must not expose license keys, billing identity, or plan-upgrade copy as part of that security/privacy feature gate. +The Audit Webhooks panel also states its scope before any gate or endpoint +list: these webhooks carry security events only, and alert delivery lives in +alert notifications (`getAuditWebhookNotificationsSignpost`), so an operator +looking for Discord or Slack alerts is not left configuring an audit sink. Audit-log storage availability is also a security/privacy trust boundary. The `pkg/audit/` runtime package owns persistent audit-store classification: transient SQLite busy/locked conditions must be retried and surfaced as diff --git a/frontend-modern/browser-verification/17f991e2b5caadc9.json b/frontend-modern/browser-verification/17f991e2b5caadc9.json new file mode 100644 index 0000000000..f3fc46b9d7 --- /dev/null +++ b/frontend-modern/browser-verification/17f991e2b5caadc9.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "base_sha": "a28b1056459b2ae0fe01bbbe7aebd4c6ca7d3738", + "verified_at": "2026-10-05T06:23:30Z", + "result": "passed", + "changed_paths": [ + "frontend-modern/src/components/Settings/AuditWebhookPanel.tsx", + "frontend-modern/src/utils/auditWebhookPresentation.ts" + ], + "content_sha256": { + "frontend-modern/src/components/Settings/AuditWebhookPanel.tsx": "416aa81cc2a011b937f9ad1d85174db72020c61e2d0f3a6bcc0d2eee99419457", + "frontend-modern/src/utils/auditWebhookPresentation.ts": "f94b530c79dddedec64ecf4a9f5c80fe017580ea73ebcc479418c2bafaed3fba" + }, + "routes": [ + "/settings/security-webhooks", + "/alerts/notifications" + ], + "viewports": [ + { + "width": 1440, + "height": 900 + }, + { + "width": 390, + "height": 844 + } + ], + "states": [ + "Audit Webhooks at 1440 with audit delivery not enabled on this instance: the panel opens with These carry security events only. To send alerts to Discord, Slack, ntfy or email, set up alert notifications, above the existing gate card. Before, the page gave no hint that alert webhooks live elsewhere", + "Phone at 390: the signpost wraps over two lines above the gate card", + "The enabled state (endpoint list) is not reachable on this mock instance, so its placement is covered by the settings architecture test" + ], + "interactions": [ + "Clicked alert notifications and landed on /alerts/notifications without a full page reload" + ] +} diff --git a/frontend-modern/src/components/Settings/AuditWebhookPanel.tsx b/frontend-modern/src/components/Settings/AuditWebhookPanel.tsx index b849909224..895fc5bb34 100644 --- a/frontend-modern/src/components/Settings/AuditWebhookPanel.tsx +++ b/frontend-modern/src/components/Settings/AuditWebhookPanel.tsx @@ -19,13 +19,33 @@ import { getAuditWebhookEmptyStateCopy, getAuditWebhookFeatureGateCopy, getAuditWebhookLoadingState, + getAuditWebhookNotificationsSignpost, } from '@/utils/auditWebhookPresentation'; +import { pathForTab } from '@/features/alerts/types'; import { useAuditWebhookPanelState } from '@/components/Settings/useAuditWebhookPanelState'; interface AuditWebhookPanelProps { canManage?: boolean; } +const AuditWebhookNotificationsSignpost: Component = () => { + // A plain anchor: the app Router intercepts same-origin links, and the + // panel also renders outside a Router in its read-only tests. + const copy = getAuditWebhookNotificationsSignpost(); + return ( +
+ {copy.text}{' '} + + {copy.linkLabel} + + . +
+ ); +}; + export const AuditWebhookPanel: Component