Skip to content

Webhook Middleware Phase 1: Core webhook package (types, HTTP client, HMAC signing) #3396

@JAORMX

Description

@JAORMX

Overview

Implement the foundational webhook package for the Dynamic Webhook Middleware feature. This phase creates the core types, HTTP client, and HMAC signing functionality that will be used by both validating and mutating webhook middleware.

RFC: https://github.com/stacklok/toolhive-rfcs/blob/main/rfcs/THV-0017-dynamic-webhook-middleware.md

Files to Create

File Purpose
pkg/webhook/types.go Core types: WebhookType, FailurePolicy, WebhookConfig, request/response structs
pkg/webhook/client.go HTTP client for calling webhooks with TLS/timeout support
pkg/webhook/signing.go HMAC-SHA256 payload signing (X-ToolHive-Signature header)
pkg/webhook/errors.go Error types: timeout, network, validation errors

Key Types

// pkg/webhook/types.go
type WebhookType string
const (
    WebhookTypeValidating WebhookType = "validating"
    WebhookTypeMutating   WebhookType = "mutating"
)

type FailurePolicy string
const (
    FailurePolicyFail   FailurePolicy = "fail"   // fail-closed
    FailurePolicyIgnore FailurePolicy = "ignore" // fail-open
)

type WebhookConfig struct {
    Name          string        `json:"name"`
    URL           string        `json:"url"`
    Timeout       time.Duration `json:"timeout"`
    FailurePolicy FailurePolicy `json:"failure_policy"`
    TLSConfig     *TLSConfig    `json:"tls_config,omitempty"`
    HMACSecretRef string        `json:"hmac_secret_ref,omitempty"`
}

type WebhookRequest struct {
    Version    string           `json:"version"` // "v0.1.0"
    UID        string           `json:"uid"`
    Timestamp  time.Time        `json:"timestamp"`
    Principal  *Principal       `json:"principal"`
    MCPRequest json.RawMessage  `json:"mcp_request"`
    Context    *RequestContext  `json:"context"`
}

type Principal struct {
    Sub    string            `json:"sub"`
    Email  string            `json:"email,omitempty"`
    Name   string            `json:"name,omitempty"`
    Groups []string          `json:"groups,omitempty"`
    Claims map[string]string `json:"claims,omitempty"`
}

type RequestContext struct {
    ServerName    string `json:"server_name"`
    BackendServer string `json:"backend_server,omitempty"`
    Namespace     string `json:"namespace,omitempty"`
    SourceIP      string `json:"source_ip"`
    Transport     string `json:"transport"`
}

HTTP Client Features

  • TLS configuration (CA bundles, skip verify for dev)
  • mTLS support (client certificates)
  • Configurable timeouts
  • Connection pooling
  • Use existing patterns from pkg/networking/http_client.go

HMAC Signing

Per RFC, implement HMAC-SHA256 signing:

  • Header: X-ToolHive-Signature: sha256=<hex-encoded-signature>
  • Header: X-ToolHive-Timestamp: <unix-timestamp>
  • Signature computed over: timestamp.payload
func SignPayload(secret []byte, timestamp int64, payload []byte) string
func VerifySignature(secret []byte, timestamp int64, payload []byte, signature string) bool

Error Types

type WebhookError struct {
    WebhookName string
    Err         error
}

type TimeoutError struct{ WebhookError }
type NetworkError struct{ WebhookError }
type InvalidResponseError struct{ WebhookError }

Tests

  • Unit tests for HMAC signing/verification
  • HTTP client tests with mock servers (use httptest)
  • Error handling tests (timeout, TLS errors, invalid responses)
  • Table-driven tests for various error conditions

Acceptance Criteria

  • All types defined per RFC specification
  • HTTP client supports TLS, mTLS, and configurable timeouts
  • HMAC signing matches RFC specification
  • Comprehensive unit tests with >80% coverage
  • Code passes task lint and task test

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiItems related to the APIauthenticationenhancementNew feature or requestgoPull requests that update go code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions