webhooks

package
v0.0.0-...-fd72d3f Latest Latest
Warning

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

Go to latest
Published: May 11, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

Package cloudeng.io/webapp/webhooks

import cloudeng.io/webapp/webhooks

Constants

DefaultQueueSize, DefaultPayloadLimit
DefaultQueueSize = 100
DefaultPayloadLimit = 1024 * 1024 // 1MB


Variables

ErrWrongServiceSpecificConfig
ErrWrongServiceSpecificConfig = fmt.Errorf("missing service specific config")

Functions

Func NoopValidator
func NoopValidator(req *http.Request) ([]byte, int)

Types

Type Config
type Config struct {
	PublicAddr   string            `yaml:"public_addr" doc:"public address to serve webhooks on"`
	PublicIPACL  ipacl.Config      `yaml:"public_ip_acl" doc:"ACL of IPs allowed to access the webhook, if not specified all IPs are allowed"`
	PrivateAddr  string            `yaml:"private_addr" doc:"private address to listen on for webhook requests"`
	PrivateIPACL ipacl.Config      `yaml:"private_ip_acl" doc:"ACL of IPs allowed to access the webhook on the private address, if not specified all IPs are allowed"`
	Path         string            `yaml:"path" doc:"path to serve webhooks on"`
	Service      string            `yaml:"service" doc:"type of webhook to serve, e.g. github, etc."`
	Specific     *cmdyaml.Deferred `yaml:",inline" doc:"additional details about the webhook specific to the type of webhook being served"`
}

Config represents the configuration for a webhook server.

Methods
func (c Config) Github() (*GithubWebhookConfig, error)
Type GitHubSecrets
type GitHubSecrets struct {
	Secrets []string `yaml:"secrets"`
}

GitHubSecrets represents the structure of the YAML file that contains the GitHub webhook secrets. It supports multiple secrets to allow for rotation.

Methods
func (s *GitHubSecrets) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML unmarshals the YAML data into the GitHubSecrets struct by appending the secrets to the Secrets slice. This allows for multiple secrets to be specified in a single yaml.Node and across multiple yaml.Node instances (e.g. from multiple files).

Type GithubWebhookConfig
type GithubWebhookConfig struct {
	KeychainItemUser    string `yaml:"secret_user" doc:"user name of the key containing the GitHub webhook secret"`
	KeychainItemTokenID string `yaml:"secret_id" doc:"ID of the key containing the GitHub webhook secret as a token"`
}

GithubWebhookConfig represents the configuration specific to a GitHub webhook. In particular the secrete used to validate the webhook requests is accessed via a cloudeng.io/cmdutil/keys.InMemoryKeyStore item specified by the KeychainItemUser and KeychainItemTokenID fields. The keystore itself will be populated by the server hosting the webhook.

Type Option
type Option func(*options)

Option is a function that configures the Relay.

Functions
func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger for the Relay.

func WithMaxPayloadSize(size int) Option

WithMaxPayloadSize sets the maximum allowed payload size for incoming webhook requests.

func WithQueueSize(size int) Option

WithQueueSize sets the size of the channel buffer for relaying payloads.

Type Relay
type Relay struct {
	// contains filtered or unexported fields
}

Relay is an HTTP handler that receives JSON payloads and relays them over a channel for subsequent processing. It is designed to be used in a webhook server to receive webhook payloads and relay them to another http handler that is used as a long polling endpoint for a client to receive the payloads. The Webhook endpoint will accept POST requests with JSON payloads and the Wait endpoint will accept GET requests and will block until a payload is received/

Functions
func NewRelay(validator Validator, opts ...Option) *Relay

NewRelay creates a new Relay with the provided Validator and options. The

Methods
func (r *Relay) Handler(prefix string) func(w http.ResponseWriter, req *http.Request)

Handler returns an http.HandlerFunc that routes requests to the appropriate handler based on the URL path. It expects the webhook endpoint to be at {prefix}/webhook and the wait endpoint to be at {prefix}/wait. Requests to other paths will receive a 404 Not Found response.

func (r *Relay) ServeWebhook(w http.ResponseWriter, req *http.Request)

ServeWebhook handles incoming webhook requests, validates them using the provided Validator, and relays the payload to the channel for processing. It responds with appropriate HTTP status codes based on the validation and processing outcome.

func (r *Relay) WaitForWebhook(w http.ResponseWriter, req *http.Request)

WaitForWebhook waits for a payload to be received on the channel and responds with the payload as JSON. It is intended to support long polling by blocking until a webhook payload is available. If the request context is cancelled while waiting, it logs the cancellation and returns without responding.

Type Validator
type Validator func(r *http.Request) ([]byte, int)

Validator is called to validate and extract the webhook payload from an incoming request. It should return the payload as a byte slice and an error if validation fails.

Functions
func GitHubValidator(ctx context.Context, fs file.ReadFileFS, secretPaths ...string) (Validator, error)

GitHubValidator returns a Validator that verifies GitHub webhook payloads using one of possibly multiple secrets stored in the provided file.ReadFileFS instance at the provided path(s). Multiple secrets files and multiple secrets per file allow for rotation. GitHub does not currently directly support rotation, hence the only way to change the secret used by GitHub is to create a new one, wait for it be picked up by the validator then change the secret used by GitHub to the new one and remove the old secret from the file.ReadFileFS. Ideally, the file.ReadFileFS instance should be an in-memory or caching implementation to avoid the overhead of reading the secret from disk on every request but that also allows for the secret to be refreshed. GitHubValidator returns an error if no secret paths are provided, if any of the provided paths are empty or can't be successfully read and parsed. Note that this initial validation uses the context passed to GitHubValidator, whereas the returned Validator uses the context from the incoming request to read the secrets on each request.

Documentation

Index

Constants

View Source
const (
	DefaultQueueSize    = 100
	DefaultPayloadLimit = 1024 * 1024 // 1MB
)

Variables

View Source
var (
	ErrWrongServiceSpecificConfig = fmt.Errorf("missing service specific config")
)

Functions

func NoopValidator

func NoopValidator(req *http.Request) ([]byte, int)

Types

type Config

type Config struct {
	PublicAddr   string            `yaml:"public_addr" doc:"public address to serve webhooks on"`
	PublicIPACL  ipacl.Config      `yaml:"public_ip_acl" doc:"ACL of IPs allowed to access the webhook, if not specified all IPs are allowed"`
	PrivateAddr  string            `yaml:"private_addr" doc:"private address to listen on for webhook requests"`
	PrivateIPACL ipacl.Config      `` /* 129-byte string literal not displayed */
	Path         string            `yaml:"path" doc:"path to serve webhooks on"`
	Service      string            `yaml:"service" doc:"type of webhook to serve, e.g. github, etc."`
	Specific     *cmdyaml.Deferred `yaml:",inline" doc:"additional details about the webhook specific to the type of webhook being served"`
}

Config represents the configuration for a webhook server.

func (Config) Github

func (c Config) Github() (*GithubWebhookConfig, error)

type GitHubSecrets

type GitHubSecrets struct {
	Secrets []string `yaml:"secrets"`
}

GitHubSecrets represents the structure of the YAML file that contains the GitHub webhook secrets. It supports multiple secrets to allow for rotation.

func (*GitHubSecrets) UnmarshalYAML

func (s *GitHubSecrets) UnmarshalYAML(value *yaml.Node) error

UnmarshalYAML unmarshals the YAML data into the GitHubSecrets struct by appending the secrets to the Secrets slice. This allows for multiple secrets to be specified in a single yaml.Node and across multiple yaml.Node instances (e.g. from multiple files).

type GithubWebhookConfig

type GithubWebhookConfig struct {
	KeychainItemUser    string `yaml:"secret_user" doc:"user name of the key containing the GitHub webhook secret"`
	KeychainItemTokenID string `yaml:"secret_id" doc:"ID of the key containing the GitHub webhook secret as a token"`
}

GithubWebhookConfig represents the configuration specific to a GitHub webhook. In particular the secrete used to validate the webhook requests is accessed via a cloudeng.io/cmdutil/keys.InMemoryKeyStore item specified by the KeychainItemUser and KeychainItemTokenID fields. The keystore itself will be populated by the server hosting the webhook.

type Option

type Option func(*options)

Option is a function that configures the Relay.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger for the Relay.

func WithMaxPayloadSize

func WithMaxPayloadSize(size int) Option

WithMaxPayloadSize sets the maximum allowed payload size for incoming webhook requests.

func WithQueueSize

func WithQueueSize(size int) Option

WithQueueSize sets the size of the channel buffer for relaying payloads.

type Relay

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

Relay is an HTTP handler that receives JSON payloads and relays them over a channel for subsequent processing. It is designed to be used in a webhook server to receive webhook payloads and relay them to another http handler that is used as a long polling endpoint for a client to receive the payloads. The Webhook endpoint will accept POST requests with JSON payloads and the Wait endpoint will accept GET requests and will block until a payload is received/

func NewRelay

func NewRelay(validator Validator, opts ...Option) *Relay

NewRelay creates a new Relay with the provided Validator and options. The

func (*Relay) Handler

func (r *Relay) Handler(prefix string) func(w http.ResponseWriter, req *http.Request)

Handler returns an http.HandlerFunc that routes requests to the appropriate handler based on the URL path. It expects the webhook endpoint to be at {prefix}/webhook and the wait endpoint to be at {prefix}/wait. Requests to other paths will receive a 404 Not Found response.

func (*Relay) ServeWebhook

func (r *Relay) ServeWebhook(w http.ResponseWriter, req *http.Request)

ServeWebhook handles incoming webhook requests, validates them using the provided Validator, and relays the payload to the channel for processing. It responds with appropriate HTTP status codes based on the validation and processing outcome.

func (*Relay) WaitForWebhook

func (r *Relay) WaitForWebhook(w http.ResponseWriter, req *http.Request)

WaitForWebhook waits for a payload to be received on the channel and responds with the payload as JSON. It is intended to support long polling by blocking until a webhook payload is available. If the request context is cancelled while waiting, it logs the cancellation and returns without responding.

type Validator

type Validator func(r *http.Request) ([]byte, int)

Validator is called to validate and extract the webhook payload from an incoming request. It should return the payload as a byte slice and an error if validation fails.

func GitHubValidator

func GitHubValidator(ctx context.Context, fs file.ReadFileFS, secretPaths ...string) (Validator, error)

GitHubValidator returns a Validator that verifies GitHub webhook payloads using one of possibly multiple secrets stored in the provided file.ReadFileFS instance at the provided path(s). Multiple secrets files and multiple secrets per file allow for rotation. GitHub does not currently directly support rotation, hence the only way to change the secret used by GitHub is to create a new one, wait for it be picked up by the validator then change the secret used by GitHub to the new one and remove the old secret from the file.ReadFileFS. Ideally, the file.ReadFileFS instance should be an in-memory or caching implementation to avoid the overhead of reading the secret from disk on every request but that also allows for the secret to be refreshed. GitHubValidator returns an error if no secret paths are provided, if any of the provided paths are empty or can't be successfully read and parsed. Note that this initial validation uses the context passed to GitHubValidator, whereas the returned Validator uses the context from the incoming request to read the secrets on each request.

Jump to

Keyboard shortcuts

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