notification

package
v0.8.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Overview

Package notification manages operator-configured alert-delivery channels (Slack, generic webhook). It owns the encrypted-at-rest channel store and the alertrouter.Channel adapter that fans fired alerts out to every enabled, tag-matching channel.

Secret handling: a channel's target (Slack/webhook URL + optional bearer token) is encrypted with the shared AES-256-GCM data key (internal/secretkey) before it touches a column, and is never returned by the API. The list/read path renders a non-secret target_hint (the URL host) instead. Outbound delivery is SSRF-guarded: only https URLs to public hosts are dialed.

Spec: system-notifications, api-notifications.

Index

Constants

View Source
const (
	SMTPEncNone     = "none"
	SMTPEncSTARTTLS = "starttls"
	SMTPEncTLS      = "tls"
)

SMTP encryption modes for Config.SMTPEncryption.

Variables

View Source
var ErrChannelNotFound = errors.New("notification: channel not found")

ErrChannelNotFound is returned when a channel id does not exist.

View Source
var ErrInvalidConfig = errors.New("notification: invalid channel config")

ErrInvalidConfig is returned when create/update validation fails.

View Source
var ErrNotEmailChannel = errors.New("notification: channel is not an email channel")

ErrNotEmailChannel is returned when a report email is requested for a non-email channel (only email channels carry attachments).

Functions

func NormalizeSMTPEncryption added in v0.4.0

func NormalizeSMTPEncryption(mode string) string

NormalizeSMTPEncryption maps an empty/unknown mode to the secure default (STARTTLS, required). Callers persist and act on the result so legacy rows (no mode) behave predictably.

Types

type Channel

type Channel struct {
	ID         uuid.UUID
	Type       ChannelType
	Name       string
	Enabled    bool
	TargetHint string // non-secret URL host, for display
	TagFilter  map[string]string
	Config     Config // decrypted; zero on list/read
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

Channel is a stored delivery channel. Config is populated only on the paths that need the secret (delivery, test); list/read leave it zero.

type ChannelType

type ChannelType string

ChannelType enumerates the delivery backends this slice ships. Email (smtp) lands in a follow-up; the DB CHECK constraint mirrors this set.

const (
	TypeSlack   ChannelType = "slack"
	TypeWebhook ChannelType = "webhook"
	TypeEmail   ChannelType = "email"
)

func (ChannelType) IsHTTP

func (t ChannelType) IsHTTP() bool

IsHTTP reports whether the channel delivers over HTTP (slack/webhook), as opposed to SMTP (email).

func (ChannelType) IsValid

func (t ChannelType) IsValid() bool

IsValid reports whether t is a supported channel type.

type Config

type Config struct {
	// URL is the Slack incoming-webhook URL or the generic webhook
	// endpoint. Must be https to a public host (SSRF guard).
	URL string `json:"url,omitempty"`
	// Token, when set (webhook only), is sent as an Authorization:
	// Bearer header. Optional.
	Token string `json:"token,omitempty"`

	// Email/SMTP fields (TypeEmail). The relay may be an internal host —
	// SMTP is operator-trusted infrastructure, so the public-host SSRF
	// block that applies to webhook/slack is NOT applied here; TLS
	// (STARTTLS) + auth still protect the credential.
	SMTPHost string   `json:"smtp_host,omitempty"`
	SMTPPort int      `json:"smtp_port,omitempty"`
	Username string   `json:"username,omitempty"`
	Password string   `json:"password,omitempty"`
	From     string   `json:"from,omitempty"`
	To       []string `json:"to,omitempty"`
	// SMTPEncryption selects the transport security for the SMTP
	// connection: "none" (plaintext, for a trusted local relay),
	// "starttls" (connect plaintext then require a STARTTLS upgrade), or
	// "tls" (implicit TLS from connect — SMTPS, typically port 465). An
	// empty value is treated as "starttls" (the secure default). Not a
	// secret; returned to the edit form.
	SMTPEncryption string `json:"smtp_encryption,omitempty"`
	// SMTPInsecureSkipVerify, when true, disables TLS certificate
	// verification for the STARTTLS/implicit-TLS handshake. It exists ONLY
	// for an internal relay (e.g. a local postfix) that presents a
	// self-signed or private-CA certificate; it is a MITM-exposing downgrade
	// and has no effect when encryption is "none". Not a secret; returned to
	// the edit form.
	SMTPInsecureSkipVerify bool `json:"smtp_insecure_skip_verify,omitempty"`
}

Config is the decrypted, in-process-only secret payload for a channel. It is never serialized to the API or logged. The URL/Token fields apply to HTTP channels (slack/webhook); the SMTP* + mail fields apply to email.

type CreateParams

type CreateParams struct {
	Type      ChannelType
	Name      string
	Enabled   bool
	Config    Config
	TagFilter map[string]string
}

CreateParams is the input to Create.

type DispatchChannel

type DispatchChannel struct {
	// contains filtered or unexported fields
}

DispatchChannel is the single alertrouter.Channel that fans every fired alert out to all enabled, tag-matching notification channels loaded from the store. Registering this once means new channels take effect without re-registering with the router.

func NewDispatchChannel

func NewDispatchChannel(svc *Service) *DispatchChannel

NewDispatchChannel builds the fan-out channel for alertrouter.Register.

func (*DispatchChannel) Name

func (d *DispatchChannel) Name() string

Name satisfies alertrouter.Channel.

func (*DispatchChannel) Send

Send loads enabled channels and delivers to those whose tag filter matches. A delivery failure to one channel does not stop the others; the first error is returned for the router's failure metric.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the notification-channel CRUD entry point. Secrets are encrypted with the active data key on write and decrypted only on the delivery/test paths.

func NewService

func NewService(pool *pgxpool.Pool) *Service

NewService binds a Service to a DB pool.

func (*Service) Create

func (s *Service) Create(ctx context.Context, p CreateParams) (Channel, error)

Create persists a new channel, encrypting its config.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id uuid.UUID) error

Delete removes a channel. Idempotent for a missing id.

func (*Service) Get

func (s *Service) Get(ctx context.Context, id uuid.UUID) (Channel, error)

Get returns a single channel with its non-secret config (no password).

func (*Service) List

func (s *Service) List(ctx context.Context) ([]Channel, error)

List returns all channels without secrets (Config zero).

func (*Service) SendReportEmail

func (s *Service) SendReportEmail(ctx context.Context, channelID uuid.UUID, subject, body, filename string, attachment []byte) error

SendReportEmail delivers a report PDF as a MIME-multipart attachment through the email channel's SMTP config, to the channel's recipients.

func (*Service) Test

func (s *Service) Test(ctx context.Context, id uuid.UUID) error

Test delivers a synthetic alert through one channel so an operator can confirm wiring. Decrypts the channel secret for this single send.

func (*Service) Update

func (s *Service) Update(ctx context.Context, id uuid.UUID, p UpdateParams) (Channel, error)

Update mutates name/enabled/tag_filter, and the secret config only when ReplaceConfig is set.

type UpdateParams

type UpdateParams struct {
	Name          string
	Enabled       bool
	TagFilter     map[string]string
	ReplaceConfig bool
	Config        Config
}

UpdateParams is the input to Update. Config is replaced only when ReplaceConfig is true (so a PATCH that just toggles Enabled need not resend the secret).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL