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
- Variables
- func NormalizeSMTPEncryption(mode string) string
- type Channel
- type ChannelType
- type Config
- type CreateParams
- type DispatchChannel
- type Service
- func (s *Service) Create(ctx context.Context, p CreateParams) (Channel, error)
- func (s *Service) Delete(ctx context.Context, id uuid.UUID) error
- func (s *Service) Get(ctx context.Context, id uuid.UUID) (Channel, error)
- func (s *Service) List(ctx context.Context) ([]Channel, error)
- func (s *Service) SendReportEmail(ctx context.Context, channelID uuid.UUID, subject, body, filename string, ...) error
- func (s *Service) Test(ctx context.Context, id uuid.UUID) error
- func (s *Service) Update(ctx context.Context, id uuid.UUID, p UpdateParams) (Channel, error)
- type UpdateParams
Constants ¶
const ( SMTPEncNone = "none" SMTPEncSTARTTLS = "starttls" SMTPEncTLS = "tls" )
SMTP encryption modes for Config.SMTPEncryption.
Variables ¶
var ErrChannelNotFound = errors.New("notification: channel not found")
ErrChannelNotFound is returned when a channel id does not exist.
var ErrInvalidConfig = errors.New("notification: invalid channel config")
ErrInvalidConfig is returned when create/update validation fails.
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
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 ¶
func (d *DispatchChannel) Send(ctx context.Context, a alertrouter.Alert) error
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 ¶
NewService binds a Service to a DB pool.
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.