feat: register email as feature-flagged notification service
Add email as a recognized, feature-flagged notification service type. The flag defaults to false and acts as a dispatch gate alongside the existing discord, gotify, and webhook notification service flags. - Add FlagEmailServiceEnabled constant to the notifications feature flag registry with the canonical key convention - Register the flag in the handler defaults so it appears in the feature flags API response with a false default - Recognise 'email' as a supported notification provider type so that providers of this type pass the type validation gate - Gate email dispatch on the new flag in isDispatchEnabled() following the same pattern as gotify and webhook service flags - Expand the E2E test fixtures FeatureFlags interface to include the new flag key so typed fixture objects remain accurate No email message dispatch is wired in this commit; the flag registration alone makes the email provider type valid and toggleable.
This commit is contained in:
@@ -30,6 +30,7 @@ var defaultFlags = []string{
|
||||
"feature.crowdsec.console_enrollment",
|
||||
"feature.notifications.engine.notify_v1.enabled",
|
||||
"feature.notifications.service.discord.enabled",
|
||||
"feature.notifications.service.email.enabled",
|
||||
"feature.notifications.service.gotify.enabled",
|
||||
"feature.notifications.service.webhook.enabled",
|
||||
"feature.notifications.security_provider_events.enabled", // Blocker 3: Add security_provider_events gate
|
||||
@@ -41,6 +42,7 @@ var defaultFlagValues = map[string]bool{
|
||||
"feature.crowdsec.console_enrollment": false,
|
||||
"feature.notifications.engine.notify_v1.enabled": false,
|
||||
"feature.notifications.service.discord.enabled": false,
|
||||
"feature.notifications.service.email.enabled": false,
|
||||
"feature.notifications.service.gotify.enabled": false,
|
||||
"feature.notifications.service.webhook.enabled": false,
|
||||
"feature.notifications.security_provider_events.enabled": false, // Blocker 3: Default disabled for this stage
|
||||
|
||||
@@ -14,10 +14,10 @@ type NotificationConfig struct {
|
||||
MinLogLevel string `json:"min_log_level"` // error, warn, info, debug
|
||||
WebhookURL string `json:"webhook_url"`
|
||||
// Blocker 2 Fix: API surface uses security_* field names per spec (internal fields remain notify_*)
|
||||
NotifyWAFBlocks bool `json:"security_waf_enabled"`
|
||||
NotifyACLDenies bool `json:"security_acl_enabled"`
|
||||
NotifyRateLimitHits bool `json:"security_rate_limit_enabled"`
|
||||
NotifyCrowdSecDecisions bool `json:"security_crowdsec_enabled"`
|
||||
NotifyWAFBlocks bool `json:"security_waf_enabled"`
|
||||
NotifyACLDenies bool `json:"security_acl_enabled"`
|
||||
NotifyRateLimitHits bool `json:"security_rate_limit_enabled"`
|
||||
NotifyCrowdSecDecisions bool `json:"security_crowdsec_enabled"`
|
||||
|
||||
// Legacy destination fields (compatibility, not stored in DB)
|
||||
DiscordWebhookURL string `gorm:"-" json:"discord_webhook_url,omitempty"`
|
||||
|
||||
@@ -3,6 +3,7 @@ package notifications
|
||||
const (
|
||||
FlagNotifyEngineEnabled = "feature.notifications.engine.notify_v1.enabled"
|
||||
FlagDiscordServiceEnabled = "feature.notifications.service.discord.enabled"
|
||||
FlagEmailServiceEnabled = "feature.notifications.service.email.enabled"
|
||||
FlagGotifyServiceEnabled = "feature.notifications.service.gotify.enabled"
|
||||
FlagWebhookServiceEnabled = "feature.notifications.service.webhook.enabled"
|
||||
FlagSecurityProviderEventsEnabled = "feature.notifications.security_provider_events.enabled"
|
||||
|
||||
@@ -105,7 +105,7 @@ func supportsJSONTemplates(providerType string) bool {
|
||||
|
||||
func isSupportedNotificationProviderType(providerType string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(providerType)) {
|
||||
case "discord", "gotify", "webhook":
|
||||
case "discord", "email", "gotify", "webhook":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@@ -116,6 +116,8 @@ func (s *NotificationService) isDispatchEnabled(providerType string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(providerType)) {
|
||||
case "discord":
|
||||
return true
|
||||
case "email":
|
||||
return s.getFeatureFlagValue(notifications.FlagEmailServiceEnabled, false)
|
||||
case "gotify":
|
||||
return s.getFeatureFlagValue(notifications.FlagGotifyServiceEnabled, true)
|
||||
case "webhook":
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Wikid82/charon/backend/internal/models"
|
||||
"github.com/Wikid82/charon/backend/internal/notifications"
|
||||
"github.com/Wikid82/charon/backend/internal/security"
|
||||
"github.com/Wikid82/charon/backend/internal/trace"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -2316,6 +2317,30 @@ func TestIsDispatchEnabled_WebhookDefaultTrue(t *testing.T) {
|
||||
assert.True(t, svc.isDispatchEnabled("webhook"))
|
||||
}
|
||||
|
||||
func TestFlagEmailServiceEnabled_ConstantValue(t *testing.T) {
|
||||
assert.Equal(t, "feature.notifications.service.email.enabled", notifications.FlagEmailServiceEnabled)
|
||||
}
|
||||
|
||||
func TestIsSupportedNotificationProviderType_Email(t *testing.T) {
|
||||
assert.True(t, isSupportedNotificationProviderType("email"))
|
||||
}
|
||||
|
||||
func TestIsDispatchEnabled_EmailDefaultFalse(t *testing.T) {
|
||||
db := setupNotificationTestDB(t)
|
||||
_ = db.AutoMigrate(&models.Setting{})
|
||||
svc := NewNotificationService(db)
|
||||
|
||||
// No feature flag row — email defaults to false
|
||||
assert.False(t, svc.isDispatchEnabled("email"))
|
||||
|
||||
// Explicitly set flag to true — should now return true
|
||||
require.NoError(t, db.Create(&models.Setting{
|
||||
Key: notifications.FlagEmailServiceEnabled,
|
||||
Value: "true",
|
||||
}).Error)
|
||||
assert.True(t, svc.isDispatchEnabled("email"))
|
||||
}
|
||||
|
||||
func TestTestProvider_GotifyWorksWithoutFeatureFlag(t *testing.T) {
|
||||
db := setupNotificationTestDB(t)
|
||||
_ = db.AutoMigrate(&models.Setting{})
|
||||
|
||||
3
tests/fixtures/settings.ts
vendored
3
tests/fixtures/settings.ts
vendored
@@ -272,6 +272,7 @@ export const certificateEmailSettings = {
|
||||
export interface FeatureFlags {
|
||||
cerberus_enabled: boolean;
|
||||
crowdsec_console_enrollment: boolean;
|
||||
"feature.notifications.service.email.enabled": boolean;
|
||||
uptime_monitoring: boolean;
|
||||
}
|
||||
|
||||
@@ -281,6 +282,7 @@ export interface FeatureFlags {
|
||||
export const defaultFeatureFlags: FeatureFlags = {
|
||||
cerberus_enabled: false,
|
||||
crowdsec_console_enrollment: false,
|
||||
"feature.notifications.service.email.enabled": false,
|
||||
uptime_monitoring: false,
|
||||
};
|
||||
|
||||
@@ -290,6 +292,7 @@ export const defaultFeatureFlags: FeatureFlags = {
|
||||
export const allFeaturesEnabled: FeatureFlags = {
|
||||
cerberus_enabled: true,
|
||||
crowdsec_console_enrollment: true,
|
||||
"feature.notifications.service.email.enabled": false,
|
||||
uptime_monitoring: true,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user