Documentation
¶
Overview ¶
Package webhook implements the reference server's native webhook contract, subscription management, encrypted capture and receiver authentication.
Delivery uses eventstore's persistent leases. Payloads are immutable for a delivery; replay creates another delivery for the same occurrence. Network delivery is at least once and unordered. Consumers deduplicate delivery IDs. Full decoded bodies and original bytes require root-managed subscriptions.
Index ¶
- Constants
- Variables
- func BlobColumns() []sqlcommon.BlobColumn
- func ClassifyRoute(pattern, path string) (family, operation string)
- func CorrelationID(ctx context.Context) string
- func MigrationSet(d sqlcommon.Dialect) (sqlcommon.MigrationSet, error)
- func ObserveMDM(ctx context.Context, ck *mdm.Checkin, resp *mdm.Response, accepted bool)
- func ObserveOutcome(ctx context.Context, outcome string)
- func ObserveSubject(ctx context.Context, subject Subject)
- func OutcomeType(internal string) string
- func Sign(secret, id string, at time.Time, body []byte) (string, error)
- func Verify(secret string, headers http.Header, body []byte, now time.Time) error
- func WithCorrelation(ctx context.Context, id string) context.Context
- type CatalogueEntry
- type Change
- type Config
- type Credentials
- type Delivery
- type Event
- type Filters
- type Payload
- type PayloadPolicy
- type ReplayRequest
- type ReplayResult
- type Spec
- type Store
- func (s *Store) Admin(w http.ResponseWriter, r *http.Request, root bool)
- func (s *Store) Capture(ctx context.Context, e Event) error
- func (s *Store) CaptureOutcome(ctx context.Context, in event.Event) error
- func (s *Store) Create(ctx context.Context, spec Spec, root bool) (Change, error)
- func (s *Store) Deliveries(ctx context.Context, id, after string, limit int) ([]Delivery, error)
- func (s *Store) Get(ctx context.Context, id string) (Subscription, error)
- func (s *Store) List(ctx context.Context, after string, limit int) ([]Subscription, error)
- func (s *Store) Observe(next http.Handler, mux *http.ServeMux) http.Handler
- func (s *Store) ObserveCertificates(repository state.Store) state.Store
- func (s *Store) PayloadHandler() http.Handler
- func (s *Store) Prune(ctx context.Context) error
- func (s *Store) Replay(ctx context.Context, req ReplayRequest, root bool) (ReplayResult, error)
- func (s *Store) Resolve(_ context.Context, dest string) (eventstore.Sender, error)
- func (s *Store) Retry(ctx context.Context, id string, root bool) error
- func (s *Store) Rewrap(ctx context.Context) (int, error)
- func (s *Store) Rotate(ctx context.Context, id string, overlap time.Duration, root bool) (Change, error)
- func (s *Store) RunRetention(ctx context.Context) error
- func (s *Store) Send(ctx context.Context, id string) error
- func (s *Store) SetState(ctx context.Context, id, action string, root bool) (Subscription, error)
- func (s *Store) Status(ctx context.Context) (map[string]any, error)
- func (s *Store) Test(ctx context.Context, id string, root bool) (string, error)
- func (s *Store) Update(ctx context.Context, id string, revision int, spec Spec, root bool) (Change, error)
- type Subject
- type Subscription
Constants ¶
const ( HeaderID = "webhook-id" HeaderTimestamp = "webhook-timestamp" HeaderSignature = "webhook-signature" )
const ( SchemaVersion = "1" InlineLimit = 256 << 10 DefaultMaxBody = 16 << 20 DefaultPayloadRetention = 7 * 24 * time.Hour DefaultMetadataRetention = 30 * 24 * time.Hour PayloadPath = "/webhooks/v1/payloads/" )
Variables ¶
var ( ErrInvalid = errors.New("webhook: invalid argument") ErrNotFound = errors.New("webhook: not found") ErrForbidden = errors.New("webhook: root or receiver authority required") ErrConflict = errors.New("webhook: conflicting revision or delivery state") ErrExpired = errors.New("webhook: payload expired") )
Functions ¶
func BlobColumns ¶
func BlobColumns() []sqlcommon.BlobColumn
BlobColumns registers every sealed column for backup verification and rekey.
func ClassifyRoute ¶
ClassifyRoute deliberately excludes administration, internal DDM forwarding, health endpoints and payload retrieval. A missing route produces no event.
func CorrelationID ¶
func MigrationSet ¶
func MigrationSet(d sqlcommon.Dialect) (sqlcommon.MigrationSet, error)
func ObserveMDM ¶
ObserveMDM records decoded vocabulary and the independently determined service result. HTTP 200 alone is never interpreted as successful MDM authorization.
func ObserveOutcome ¶
ObserveOutcome records the service result independently of its HTTP status.
func ObserveSubject ¶
ObserveSubject records a resource only after the server has authenticated it.
func OutcomeType ¶
Types ¶
type CatalogueEntry ¶
type CatalogueEntry struct {
Type string `json:"type"`
Operations []string `json:"operations,omitempty"`
SummaryFields []string `json:"summary_fields"`
FullJSON bool `json:"full_json"`
Raw bool `json:"raw"`
}
func Catalogue ¶
func Catalogue() []CatalogueEntry
Catalogue returns a fresh copy of the native vocabulary.
type Change ¶
type Change struct {
Subscription Subscription `json:"subscription"`
Credentials *Credentials `json:"credentials,omitempty"`
}
type Config ¶
type Config struct {
Enabled bool
Source string
PayloadRetention time.Duration
MetadataRetention time.Duration
MaxBody int
PrivateNetworks []string
RootCAFile string
Client *http.Client
Now func() time.Time
// CommandType looks up already-authorized command metadata in the caller's
// transaction. Missing/cleared commands return an empty type.
CommandType func(context.Context, mdm.EnrollmentID, string) (string, error)
}
Config controls capture bounds and transport. PrivateNetworks explicitly opts an operator's trusted receiver networks into the outbound dial policy.
type Credentials ¶
type Credentials struct {
SigningSecret string `json:"signing_secret"`
PayloadToken string `json:"payload_token"`
}
Credentials are returned only when created or rotated; ordinary reads omit them.
type Delivery ¶
type Delivery struct {
ID string `json:"id"`
EventID string `json:"event_id"`
SubscriptionID string `json:"subscription_id"`
Revision int `json:"revision"`
State string `json:"state"`
Attempts int `json:"attempts"`
NextAttempt time.Time `json:"next_attempt"`
LastCode string `json:"last_code"`
ExpiresAt time.Time `json:"expires_at"`
Sensitive bool `json:"sensitive"`
Event Event `json:"event"`
}
type Event ¶
type Event struct {
SchemaVersion string `json:"schema_version"`
EventID string `json:"event_id"`
Type string `json:"type"`
OccurredAt time.Time `json:"occurred_at"`
Source string `json:"source"`
Subject *Subject `json:"subject,omitempty"`
CorrelationID string `json:"correlation_id,omitempty"`
Data map[string]any `json:"data"`
Payloads map[string]Payload `json:"payloads,omitempty"`
}
Event is the immutable occurrence carried by one or more deliveries.
type Filters ¶
type Filters struct {
Operations []string `json:"operations,omitempty"`
Outcomes []string `json:"outcomes,omitempty"`
Channels []string `json:"channels,omitempty"`
Subjects []string `json:"subjects,omitempty"`
CommandTypes []string `json:"command_types,omitempty"`
}
Filters use OR within a field and AND between fields. Subject filters never match unverified claims or exchanges without a verified subject.
type Payload ¶
type Payload struct {
ContentType string `json:"content_type"`
Encoding string `json:"encoding"`
Availability string `json:"availability"`
Size int `json:"size"`
SHA256 string `json:"sha256,omitempty"`
Value json.RawMessage `json:"value,omitempty"`
Href string `json:"href,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
Payload is either inline, referenced, or explicitly unavailable. SHA256 and Size describe the representation fetched from Href (raw bytes or JSON).
type PayloadPolicy ¶
type PayloadPolicy struct {
FullJSON bool `json:"full_json"`
RawRequest bool `json:"raw_request"`
RawResponse bool `json:"raw_response"`
}
PayloadPolicy is a disclosure ceiling, including when replaying older data.
func (PayloadPolicy) Sensitive ¶
func (p PayloadPolicy) Sensitive() bool
type ReplayRequest ¶
type ReplayRequest struct {
SubscriptionID string `json:"subscription_id"`
EventIDs []string `json:"event_ids,omitempty"`
Type string `json:"type,omitempty"`
After time.Time `json:"after,omitempty"`
Before time.Time `json:"before,omitempty"`
Key string `json:"key"`
DryRun bool `json:"dry_run"`
Limit int `json:"limit,omitempty"`
}
type ReplayResult ¶
type Spec ¶
type Spec struct {
Name string `json:"name"`
URL string `json:"url"`
Events []string `json:"events"`
Filters Filters `json:"filters"`
Payload PayloadPolicy `json:"payload"`
}
Spec is the writable subscription configuration. URLs may contain secrets and are only exposed to webhook administrators, never through delivery diagnostics.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
func Open ¶
func Open(ctx context.Context, db *sql.DB, d sqlcommon.Dialect, keys *crypt.Keyring, outbox *eventstore.Store, cfg Config) (*Store, error)
Open requires encryption even for summary-only subscriptions because signing keys are recoverable secrets. It never owns the supplied SQL pool.
func (*Store) Admin ¶
Admin serves after the host application's ordinary Cedar authorization. Root remains a separate mandatory gate for sensitive destination operations.
func (*Store) Capture ¶
Capture participates in the caller's SQL transaction. It copies payloads at capture time, never retains mutable pointers, and records nothing when no enabled subscription matches.
func (*Store) CaptureOutcome ¶
CaptureOutcome adapts existing in-process events without changing library APIs. The projection remains the summary; complete internal data is a distinct, root-controlled representation.
func (*Store) Deliveries ¶
func (*Store) Observe ¶
Observe captures only bytes consumed/written by the handler. It never drains rejected bodies or changes protocol responses when observation persistence fails. Capture failures remain visible through Status.
func (*Store) ObserveCertificates ¶
ObserveCertificates joins SQL-backed managed certificate transitions and capture in one transaction. The supplied store must use this Store's SQL pool. The concrete state.Tx reaches the callback unchanged, preserving publication adapters; private material is never extracted from state records.
func (*Store) PayloadHandler ¶
PayloadHandler authenticates only subscription-scoped receiver credentials. It accepts no administrator tokens and never grants administrative access.
func (*Store) Replay ¶
func (s *Store) Replay(ctx context.Context, req ReplayRequest, root bool) (ReplayResult, error)