Help us shape the future of Go! Take the 2026 Go Developer Survey

webhook

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: AGPL-3.0 Imports: 14 Imported by: 0

Documentation

Overview

Package webhook delivers domain events to customer-configured HTTP endpoints. It composes maintained libraries rather than hand-rolling the security-critical parts: doyensec/safeurl for the SSRF-hardened HTTP client and the standard-webhooks library for interoperable HMAC signatures.

Index

Constants

View Source
const EventHeader = "X-sphericon-Event"

EventHeader carries the event name for receiver-side routing; the signed payload also carries "type". Identity/timestamp/signature use the Standard Webhooks headers (webhook-id, webhook-timestamp, webhook-signature).

View Source
const ExcerptBytes = 1 << 10

ExcerptBytes is how much of a receiver's answer a failed call keeps.

Variables

This section is empty.

Functions

func ParseRetryAfter

func ParseRetryAfter(value string, now time.Time) (wait time.Duration, ok bool)

ParseRetryAfter reads a Retry-After value (RFC 9110: delta-seconds or an HTTP-date) as the wait from now. ok is false for an absent or unreadable value; a date already past is a zero wait.

func Post

func Post(ctx context.Context, client Doer, c Call) error

Post makes the call through client, which should come from NewClient or NewClientAllowing. It returns a *DeliveryError for a transport failure or a non-2xx answer; the latter carries the first ExcerptBytes of the receiver's response.

func Send

func Send(ctx context.Context, client Doer, url, secret, eventName, deliveryID string, body []byte) error

Send signs the body with the endpoint secret (Standard Webhooks scheme) and POSTs it via client. It errors on transport failure or a non-2xx response so the caller can retry. Use a client from NewClient so the SSRF guard applies.

Types

type Allowlist

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

Allowlist names the internal host:port pairs an outbound call may reach although the address is private or loopback (ADR 0039). It is an instance-level setting, empty by default and never set in SaaS; there is no per-Workspace form. The zero value allows nothing.

func ParseAllowlist

func ParseAllowlist(value string) (Allowlist, error)

ParseAllowlist reads a comma- or space-separated list of host:port entries (a hostname, an IPv4 address or a bracketed IPv6 address, then a port). An empty value is the empty allowlist; a malformed entry is an error naming it.

type Call

type Call struct {
	URL     string
	Secret  string
	ID      string
	Headers map[string]string
	Body    []byte
}

Call is one outbound POST of a JSON body. A Secret signs it (Standard Webhooks, with ID as the message id); an empty Secret sends it unsigned. Headers are extra request headers, set after the standard ones.

type DeliveryError

type DeliveryError struct {
	Kind       ErrorKind
	Status     int
	RetryAfter string
	// Excerpt is the first ExcerptBytes of the receiver's answer to a KindHTTPStatus failure.
	Excerpt string
	// contains filtered or unexported fields
}

DeliveryError is a failed delivery with its closed kind. Status is set only for KindHTTPStatus. RetryAfter is the receiver's Retry-After header, verbatim, when it sent one (ParseRetryAfter reads it).

func RateLimited

func RateLimited(sendErr error) *DeliveryError

RateLimited returns the receiver's 429 answer, or nil for any other outcome. A 429 is neither a success nor a failure: the receiver is alive and asking us to slow down.

func (*DeliveryError) Error

func (e *DeliveryError) Error() string

func (*DeliveryError) Unwrap

func (e *DeliveryError) Unwrap() error

type Doer

type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer is the subset of *http.Client used for delivery; both *http.Client and safeurl's wrapped client satisfy it (the latter is not an *http.Client).

func NewClient

func NewClient(timeout time.Duration) Doer

NewClient builds an SSRF-hardened HTTP client via doyensec/safeurl: it blocks dialing private/loopback/link-local/CGNAT/metadata addresses on the *resolved* IP (defeating DNS rebinding), restricts schemes to http(s), and does not follow redirects.

func NewClientAllowing

func NewClientAllowing(timeout time.Duration, allow Allowlist) Doer

NewClientAllowing is NewClient for the callers that honour the Instance's internal allowlist (ADR 0039): a request to a host:port it names is made without the address check, every other request goes through the hardened client. Redirects are never followed either way, so a permitted host cannot bounce a call to an address that is not.

type ErrorKind

type ErrorKind string

ErrorKind is the closed set of reasons a delivery fails (ADR 0039). It is the vocabulary an owner, the API and an agent read; prose never carries it.

const (
	// KindTimeout: the receiver did not answer within the delivery timeout.
	KindTimeout ErrorKind = "timeout"
	// KindBlockedAddress: the URL names an address the Instance does not permit
	// (private, loopback, link-local, or a scheme or port the client refuses).
	KindBlockedAddress ErrorKind = "blocked_address"
	// KindHTTPStatus: the receiver answered with a non-2xx status (DeliveryError.Status).
	KindHTTPStatus ErrorKind = "http_status"
	// KindNetwork: any other transport failure (DNS, refused or reset connection).
	KindNetwork ErrorKind = "network"
)

Jump to

Keyboard shortcuts

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