webhook

package
v0.12.5 Latest Latest
Warning

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

Go to latest
Published: Mar 24, 2026 License: Apache-2.0 Imports: 20 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.

Variables

This section is empty.

Functions

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 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"`
	// URL is the HTTPS endpoint to call.
	URL string `json:"url"`
	// Timeout is the maximum time to wait for a webhook response.
	Timeout time.Duration `json:"timeout"`
	// FailurePolicy determines behavior when the webhook call fails.
	FailurePolicy FailurePolicy `json:"failure_policy"`
	// TLSConfig holds optional TLS configuration (CA bundles, client certs).
	TLSConfig *TLSConfig `json:"tls_config,omitempty"`
	// HMACSecretRef is an optional reference to an HMAC secret for payload signing.
	HMACSecretRef string `json:"hmac_secret_ref,omitempty"`
}

Config holds the configuration for a single webhook.

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 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"`
	// ClientCertPath is the path to a client certificate for mTLS.
	ClientCertPath string `json:"client_cert_path,omitempty"`
	// ClientKeyPath is the path to a client key for mTLS.
	ClientKeyPath string `json:"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"`
}

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.

Jump to

Keyboard shortcuts

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