statuswebhook

package
v0.9.2 Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package statuswebhook delivers signed status page events to subscriber URLs.

Index

Constants

View Source
const (
	EnvMaxSubscribers = "APP_STATUS_WEBHOOK_MAX_SUBSCRIBERS"
	EnvTimeout        = "APP_STATUS_WEBHOOK_TIMEOUT"
	EnvMaxAttempts    = "APP_STATUS_WEBHOOK_MAX_ATTEMPTS"
	EnvBackoffBase    = "APP_STATUS_WEBHOOK_BACKOFF_BASE"
	EnvBackoffMax     = "APP_STATUS_WEBHOOK_BACKOFF_MAX"
	EnvPauseAfter     = "APP_STATUS_WEBHOOK_PAUSE_AFTER"
	EnvPoll           = "APP_STATUS_WEBHOOK_POLL_INTERVAL"
	EnvLogKeep        = "APP_STATUS_WEBHOOK_LOG_KEEP"
	EnvAllowHTTP      = "APP_STATUS_WEBHOOK_ALLOW_HTTP"
	EnvAllowPrivate   = "APP_STATUS_WEBHOOK_ALLOW_PRIVATE"
)

Environment variables that tune delivery. Every value has a default; none is a secret.

View Source
const (
	IncidentOpened       = "incident_opened"
	IncidentUpdated      = "incident_updated"
	IncidentResolved     = "incident_resolved"
	ComponentChanged     = "component_changed"
	MaintenanceScheduled = "maintenance_scheduled"
	MaintenanceUpdated   = "maintenance_updated"
	MaintenanceCompleted = "maintenance_completed"
	// Ping is the signed test event; it is never subject to a filter.
	Ping = "ping"
)

Event types a subscriber can filter on.

Variables

View Source
var ErrSealerUnavailable = errors.New("statuswebhook: sealed signing secret needs a master key")

ErrSealerUnavailable means a sealed secret cannot be opened because no master key is configured.

EventTypes lists every type a subscriber may filter on.

Functions

func Sign

func Sign(secret, timestamp string, body []byte) string

Sign returns the X-Signature value for a timestamp and body.

func Verify

func Verify(secret, timestamp string, body []byte, signature string) bool

Verify reports whether signature matches, in constant time.

Types

type ComponentRef

type ComponentRef struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	Change      string `json:"change"`
}

ComponentRef is the public view of a component in an event.

type Config

type Config struct {
	MaxSubscribers int
	Timeout        time.Duration
	MaxAttempts    int
	BackoffBase    time.Duration
	BackoffMax     time.Duration
	PauseAfter     int
	Poll           time.Duration
	LogKeep        int
	AllowHTTP      bool
	AllowPrivate   bool
}

Config holds the delivery limits.

func ConfigFromEnv

func ConfigFromEnv() Config

ConfigFromEnv reads Config, falling back to defaults for unset or invalid values.

type Envelope

type Envelope struct {
	ID        string                   `json:"id"`
	Type      string                   `json:"type"`
	CreatedAt time.Time                `json:"created_at"`
	Page      PageRef                  `json:"page"`
	Incident  *statuspage.IncidentView `json:"incident,omitempty"`
	Component *ComponentRef            `json:"component,omitempty"`
}

Envelope is the JSON body posted to subscribers.

type Event

type Event struct {
	Type      string
	ObjectID  string
	Stamp     string
	Page      PageRef
	Incident  *statuspage.IncidentView
	Component *ComponentRef
}

Event is what callers hand to Emit. ObjectID and Stamp make the event id deterministic.

type PageRef

type PageRef struct {
	Title string `json:"title"`
	Path  string `json:"path"`
}

PageRef identifies the page in an event.

type Sealer

type Sealer interface {
	SetValue(ctx context.Context, serviceName, envKey, plaintext string) error
	Resolve(ctx context.Context, serviceName, envKey string) (string, error)
	DeleteAll(ctx context.Context, serviceName string) error
}

Sealer is the envelope-encryption surface signing secrets are stored with; *secrets.Manager satisfies it.

type Service

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

Service manages subscribers and delivers events.

func New

func New(st Store, sealer func() Sealer, cfg Config, logger *slog.Logger) *Service

New builds a Service. sealer may return nil, in which case secrets are stored in the clear column.

func (*Service) Config

func (s *Service) Config() Config

Config returns the active limits.

func (*Service) Create

func (s *Service) Create(ctx context.Context, rawURL, label string, events []string) (store.StatusWebhook, string, error)

Create validates and stores a subscriber and returns it with its one-time signing secret.

func (*Service) Delete

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

Delete removes a subscriber, its log and its sealed secret.

func (*Service) Deliveries

func (s *Service) Deliveries(ctx context.Context, id string) ([]store.StatusWebhookDelivery, error)

Deliveries returns a subscriber's log, newest first.

func (*Service) Emit

func (s *Service) Emit(ctx context.Context, ev Event) error

Emit queues ev for every active subscriber whose filter admits it. Repeating the same event is a no-op, so callers may retry freely.

func (*Service) ProcessDue

func (s *Service) ProcessDue(ctx context.Context) (int, error)

ProcessDue attempts every delivery whose time has come and returns how many it tried.

func (*Service) Rotate

func (s *Service) Rotate(ctx context.Context, id string) (string, error)

Rotate replaces the signing secret and returns the new one once.

func (*Service) Run

func (s *Service) Run(ctx context.Context) error

Run delivers queued events until ctx ends. It is one goroutine and returns when ctx does.

func (*Service) Test

func (s *Service) Test(ctx context.Context, id string, page PageRef) (TestResult, error)

Test sends one signed ping now and logs it. It never counts toward auto-pause.

func (*Service) ValidateURL

func (s *Service) ValidateURL(ctx context.Context, raw string) error

ValidateURL applies the scheme and SSRF rules for subscriber URLs.

type Store

type Store interface {
	CreateStatusWebhook(ctx context.Context, w store.StatusWebhook, limit int) error
	ListStatusWebhooks(ctx context.Context) ([]store.StatusWebhook, error)
	GetStatusWebhook(ctx context.Context, id string) (store.StatusWebhook, error)
	SetStatusWebhookSecret(ctx context.Context, id, plain string, sealed bool) error
	SetStatusWebhookPaused(ctx context.Context, id string, paused bool, reason string) error
	DeleteStatusWebhook(ctx context.Context, id string) error
	AddStatusWebhookDelivery(ctx context.Context, d store.StatusWebhookDelivery) (bool, error)
	DueStatusWebhookDeliveries(ctx context.Context, now time.Time, limit int) ([]store.StatusWebhookDelivery, error)
	ListStatusWebhookDeliveries(ctx context.Context, webhookID string, limit int) ([]store.StatusWebhookDelivery, error)
	RecordStatusWebhookAttempt(ctx context.Context, d store.StatusWebhookDelivery, ok, countStreak bool, pauseAfter, keep int) (bool, error)
}

Store is the persistence surface; *store.DB satisfies it.

type TestResult

type TestResult struct {
	Delivered  bool   `json:"delivered"`
	StatusCode int    `json:"status_code"`
	Error      string `json:"error,omitempty"`
}

TestResult is the outcome of a test ping.

type ValidationError

type ValidationError string

ValidationError is a user-facing problem with a subscriber's input.

func (ValidationError) Error

func (e ValidationError) Error() string

Jump to

Keyboard shortcuts

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