webhook

package
v0.19.0 Latest Latest
Warning

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

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

Documentation

Overview

Package webhook implements the core types, HTTP client, HMAC signing, and error handling for ToolHive's dynamic webhook middleware system.

Index

Constants

View Source
const (
	// SignatureHeader is the HTTP header containing the HMAC signature.
	SignatureHeader = "X-ToolHive-Signature"
	// TimestampHeader is the HTTP header containing the Unix timestamp.
	TimestampHeader = "X-ToolHive-Timestamp"
)

Header names for webhook HMAC signing.

View Source
const APIVersion = "v0.1.0"

APIVersion is the version of the webhook API protocol.

View Source
const DefaultTimeout = 10 * time.Second

DefaultTimeout is the default timeout for webhook HTTP calls.

View Source
const MaxResponseSize = 1 << 20

MaxResponseSize is the maximum allowed size in bytes for webhook responses (1 MB).

View Source
const MaxTimeout = 30 * time.Second

MaxTimeout is the maximum allowed timeout for webhook HTTP calls.

View Source
const MinTimeout = 1 * time.Second

MinTimeout is the minimum allowed timeout for webhook HTTP calls.

Variables

This section is empty.

Functions

func IsAlwaysDenyError added in v0.19.0

func IsAlwaysDenyError(err error) bool

IsAlwaysDenyError reports whether the webhook error should deny the request regardless of the configured failure policy.

func SignPayload

func SignPayload(secret []byte, timestamp int64, payload []byte) string

SignPayload computes an HMAC-SHA256 signature over the given timestamp and payload. The signature is computed over the string "timestamp.payload" and returned in the format "sha256=<hex-encoded-signature>".

func ValidateConfig added in v0.19.0

func ValidateConfig(cfg *FileConfig) error

ValidateConfig validates all webhook configurations in a FileConfig, collecting all validation errors before returning.

func VerifySignature

func VerifySignature(secret []byte, timestamp int64, payload []byte, signature string) bool

VerifySignature verifies an HMAC-SHA256 signature against the given timestamp and payload. The signature should be in the format "sha256=<hex-encoded-signature>". Comparison is done in constant time to prevent timing attacks.

Note: This function only verifies cryptographic correctness. Callers should independently verify that the timestamp is recent (e.g., within 5 minutes) to prevent replay attacks.

Types

type Client

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

Client is an HTTP client for calling webhook endpoints.

func NewClient

func NewClient(cfg Config, webhookType Type, hmacSecret []byte) (*Client, error)

NewClient creates a new webhook Client from the given configuration. The hmacSecret parameter is the resolved secret bytes for HMAC signing; pass nil if signing is not configured.

func (*Client) Call

func (c *Client) Call(ctx context.Context, req *Request) (*Response, error)

Call sends a request to a validating webhook and returns its response.

func (*Client) CallMutating

func (c *Client) CallMutating(ctx context.Context, req *Request) (*MutatingResponse, error)

CallMutating sends a request to a mutating webhook and returns its response.

type Config

type Config struct {
	// Name is a unique identifier for this webhook.
	Name string `json:"name" yaml:"name"`
	// URL is the HTTPS endpoint to call.
	URL string `json:"url" yaml:"url"`
	// Timeout is the maximum time to wait for a webhook response.
	Timeout time.Duration `json:"timeout" yaml:"timeout" swaggertype:"primitive,integer"`
	// FailurePolicy determines behavior when the webhook call fails.
	FailurePolicy FailurePolicy `json:"failure_policy" yaml:"failure_policy"`
	// TLSConfig holds optional TLS configuration (CA bundles, client certs).
	TLSConfig *TLSConfig `json:"tls_config,omitempty" yaml:"tls_config,omitempty"`
	// HMACSecretRef is an optional reference to an HMAC secret for payload signing.
	HMACSecretRef string `json:"hmac_secret_ref,omitempty" yaml:"hmac_secret_ref,omitempty"`
}

Config holds the configuration for a single webhook.

func (*Config) UnmarshalJSON added in v0.19.0

func (c *Config) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts webhook timeout values as either strings (for example "5s") or numeric nanoseconds, while keeping the rest of the struct on the standard JSON path.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that the WebhookConfig has valid required fields.

type FailurePolicy

type FailurePolicy string

FailurePolicy defines how webhook errors are handled.

const (
	// FailurePolicyFail denies the request on webhook error (fail-closed).
	FailurePolicyFail FailurePolicy = "fail"
	// FailurePolicyIgnore allows the request on webhook error (fail-open).
	FailurePolicyIgnore FailurePolicy = "ignore"
)

type FileConfig added in v0.19.0

type FileConfig struct {
	// Validating is the list of validating webhook configurations.
	Validating []Config `yaml:"validating" json:"validating"`
	// Mutating is the list of mutating webhook configurations.
	Mutating []Config `yaml:"mutating" json:"mutating"`
}

FileConfig is the top-level structure for a webhook configuration file. It supports both YAML and JSON formats.

Example YAML:

validating:
  - name: policy-check
    url: https://policy.example.com/validate
    timeout: 5s
    failure_policy: fail

mutating:
  - name: hr-enrichment
    url: https://hr-api.example.com/enrich
    timeout: 3s
    failure_policy: ignore

func LoadConfig added in v0.19.0

func LoadConfig(path string) (*FileConfig, error)

LoadConfig reads and parses a webhook configuration file. The format is auto-detected by file extension: ".json" uses JSON decoding; all other extensions (including ".yaml" and ".yml") use YAML decoding.

func MergeConfigs added in v0.19.0

func MergeConfigs(configs ...*FileConfig) *FileConfig

MergeConfigs merges multiple FileConfigs into one. Webhooks with the same name are de-duplicated: entries from later configs override entries from earlier ones (last-writer-wins per webhook name). The resulting Validating and Mutating slices preserve the order in which unique names were first seen and apply overrides in place.

type InvalidResponseError

type InvalidResponseError struct {
	WebhookError
	// StatusCode is the HTTP status code returned by the webhook, if applicable.
	// A value of 0 means no HTTP response was received (e.g., JSON decode error).
	StatusCode int
}

InvalidResponseError indicates that a webhook returned an unparsable or invalid response.

func NewInvalidResponseError

func NewInvalidResponseError(webhookName string, err error, statusCode int) *InvalidResponseError

NewInvalidResponseError creates a new InvalidResponseError. statusCode is the HTTP status code from the webhook response (0 if not applicable).

func (*InvalidResponseError) Error

func (e *InvalidResponseError) Error() string

Error implements the error interface.

type MutatingResponse

type MutatingResponse struct {
	Response
	// PatchType indicates the type of patch (e.g., "json_patch").
	PatchType string `json:"patch_type,omitempty"`
	// Patch contains the JSON Patch operations to apply.
	Patch json.RawMessage `json:"patch,omitempty"`
}

MutatingResponse is the response from a mutating webhook.

type NetworkError

type NetworkError struct {
	WebhookError
}

NetworkError indicates a network-level failure when calling a webhook.

func NewNetworkError

func NewNetworkError(webhookName string, err error) *NetworkError

NewNetworkError creates a new NetworkError.

func (*NetworkError) Error

func (e *NetworkError) Error() string

Error implements the error interface.

type Request

type Request struct {
	// Version is the webhook API protocol version.
	Version string `json:"version"`
	// UID is a unique identifier for this request, used for idempotency.
	UID string `json:"uid"`
	// Timestamp is when the request was created.
	Timestamp time.Time `json:"timestamp"`
	// Principal contains the authenticated user's identity information.
	// Uses PrincipalInfo (not Identity) so credentials never enter the webhook payload.
	Principal *auth.PrincipalInfo `json:"principal"`
	// MCPRequest is the raw MCP JSON-RPC request.
	MCPRequest json.RawMessage `json:"mcp_request"`
	// Context provides additional metadata about the request origin.
	Context *RequestContext `json:"context"`
}

Request is the payload sent to webhook endpoints.

type RequestContext

type RequestContext struct {
	// ServerName is the ToolHive/vMCP instance name handling the request.
	ServerName string `json:"server_name"`
	// BackendServer is the actual MCP server being proxied (when using vMCP).
	BackendServer string `json:"backend_server,omitempty"`
	// Namespace is the Kubernetes namespace, if applicable.
	Namespace string `json:"namespace,omitempty"`
	// SourceIP is the client's IP address.
	SourceIP string `json:"source_ip"`
	// Transport is the connection transport type (e.g., "sse", "stdio").
	Transport string `json:"transport"`
}

RequestContext provides metadata about the request origin and environment.

type Response

type Response struct {
	// Version is the webhook API protocol version.
	Version string `json:"version"`
	// UID is the unique request identifier, echoed back for correlation.
	UID string `json:"uid"`
	// Allowed indicates whether the request is permitted.
	Allowed bool `json:"allowed"`
	// Code is an optional HTTP status code for denied requests.
	Code int `json:"code,omitempty"`
	// Message is an optional human-readable explanation.
	Message string `json:"message,omitempty"`
	// Reason is an optional machine-readable denial reason.
	Reason string `json:"reason,omitempty"`
	// Details contains optional structured information about the denial.
	Details map[string]string `json:"details,omitempty"`
}

Response is the response from a validating webhook.

type TLSConfig

type TLSConfig struct {
	// CABundlePath is the path to a CA certificate bundle for server verification.
	CABundlePath string `json:"ca_bundle_path,omitempty" yaml:"ca_bundle_path,omitempty"`
	// ClientCertPath is the path to a client certificate for mTLS.
	ClientCertPath string `json:"client_cert_path,omitempty" yaml:"client_cert_path,omitempty"`
	// ClientKeyPath is the path to a client key for mTLS.
	ClientKeyPath string `json:"client_key_path,omitempty" yaml:"client_key_path,omitempty"`
	// InsecureSkipVerify disables server certificate verification.
	// WARNING: This should only be used for development/testing.
	InsecureSkipVerify bool `json:"insecure_skip_verify,omitempty" yaml:"insecure_skip_verify,omitempty"`
}

TLSConfig holds TLS-related configuration for webhook HTTP communication.

type TimeoutError

type TimeoutError struct {
	WebhookError
}

TimeoutError indicates that a webhook call timed out.

func NewTimeoutError

func NewTimeoutError(webhookName string, err error) *TimeoutError

NewTimeoutError creates a new TimeoutError.

func (*TimeoutError) Error

func (e *TimeoutError) Error() string

Error implements the error interface.

type Type

type Type string

Type indicates whether a webhook is validating or mutating.

const (
	// TypeValidating indicates a validating webhook that accepts or denies requests.
	TypeValidating Type = "validating"
	// TypeMutating indicates a mutating webhook that transforms requests.
	TypeMutating Type = "mutating"
)

type WebhookError

type WebhookError struct {
	// WebhookName is the name of the webhook that caused the error.
	WebhookName string
	// Err is the underlying error.
	Err error
}

WebhookError is the base error type for all webhook-related errors.

func (*WebhookError) Error

func (e *WebhookError) Error() string

Error implements the error interface.

func (*WebhookError) Unwrap

func (e *WebhookError) Unwrap() error

Unwrap returns the underlying error for errors.Is/errors.As support.

Directories

Path Synopsis
Package mutating implements a mutating webhook middleware for ToolHive.
Package mutating implements a mutating webhook middleware for ToolHive.
Package validating implements a validating webhook middleware for ToolHive.
Package validating implements a validating webhook middleware for ToolHive.

Jump to

Keyboard shortcuts

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