feat(hook): add AllowInsecure option for TLS verification
Some checks failed
CI / Test (1.23) (push) Failing after -20m40s
CI / Test (1.22) (push) Failing after -20m33s
CI / Build (push) Failing after -23m2s
CI / Lint (push) Failing after -22m34s

* Introduced AllowInsecure field in Hook configuration to skip TLS certificate verification.
* Updated database schema and models to support the new field.
* Modified HTTP client behavior based on AllowInsecure setting.
This commit is contained in:
Hein
2026-02-20 15:33:53 +02:00
parent 35a548e7e2
commit 3fb65e0285
8 changed files with 37 additions and 16 deletions

View File

@@ -70,14 +70,15 @@ type BusinessAPIConfig struct {
// Hook represents a registered webhook
type Hook struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers,omitempty"`
Active bool `json:"active"`
Events []string `json:"events,omitempty"`
Description string `json:"description,omitempty"`
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Method string `json:"method"`
Headers map[string]string `json:"headers,omitempty"`
Active bool `json:"active"`
Events []string `json:"events,omitempty"`
Description string `json:"description,omitempty"`
AllowInsecure bool `json:"allow_insecure,omitempty"` // Skip TLS certificate verification
}
// DatabaseConfig holds database connection information

View File

@@ -3,6 +3,7 @@ package hooks
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
@@ -335,6 +336,18 @@ func (m *Manager) sendToHook(ctx context.Context, hook config.Hook, payload inte
eventCtx = context.Background()
}
// Select the appropriate HTTP client. If the hook allows insecure TLS, use a
// dedicated client that skips certificate verification; otherwise use the shared client.
httpClient := m.client
if hook.AllowInsecure {
httpClient = &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec // intentional: user opted in via AllowInsecure
},
}
}
// Publish hook triggered event
m.eventBus.Publish(events.HookTriggeredEvent(eventCtx, hook.ID, hook.Name, hook.URL, payload))
@@ -391,7 +404,7 @@ func (m *Manager) sendToHook(ctx context.Context, hook config.Hook, payload inte
logging.Debug("Sending to hook", "hook_id", hook.ID, "url", hook.URL)
resp, err := m.client.Do(req)
resp, err := httpClient.Do(req)
if err != nil {
logging.Error("Failed to send to hook", "hook_id", hook.ID, "error", err)
m.eventBus.Publish(events.HookFailedEvent(eventCtx, hook.ID, hook.Name, err))

View File

@@ -11,6 +11,7 @@ type ModelPublicHook struct {
bun.BaseModel `bun:"table:hooks,alias:hooks"`
ID resolvespec_common.SqlString `bun:"id,type:varchar(36),pk," json:"id"` // UUID
Active bool `bun:"active,type:boolean,default:true,notnull," json:"active"`
AllowInsecure bool `bun:"allow_insecure,type:boolean,default:false,notnull," json:"allow_insecure"` // Skip TLS certificate verification
CreatedAt resolvespec_common.SqlTime `bun:"created_at,type:timestamp,default:now(),notnull," json:"created_at"`
DeletedAt resolvespec_common.SqlTime `bun:"deleted_at,type:timestamp,nullzero," json:"deleted_at"`
Description resolvespec_common.SqlString `bun:"description,type:text,nullzero," json:"description"`

View File

@@ -141,8 +141,10 @@ func createTablesSQLite(ctx context.Context) error {
headers TEXT,
events TEXT,
active BOOLEAN NOT NULL DEFAULT 1,
allow_insecure BOOLEAN NOT NULL DEFAULT 0,
retry_count INTEGER NOT NULL DEFAULT 3,
timeout_seconds INTEGER NOT NULL DEFAULT 30,
timeout INTEGER NOT NULL DEFAULT 30,
secret VARCHAR(255),
description TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

View File

@@ -226,12 +226,13 @@ func (wh *WhatsHooked) loadHooksFromDatabase(ctx context.Context) error {
configHooks := make([]config.Hook, 0, len(dbHooks))
for _, dbHook := range dbHooks {
hook := config.Hook{
ID: dbHook.ID.String(),
Name: dbHook.Name.String(),
URL: dbHook.URL.String(),
Method: dbHook.Method.String(),
Description: dbHook.Description.String(),
Active: dbHook.Active,
ID: dbHook.ID.String(),
Name: dbHook.Name.String(),
URL: dbHook.URL.String(),
Method: dbHook.Method.String(),
Description: dbHook.Description.String(),
Active: dbHook.Active,
AllowInsecure: dbHook.AllowInsecure,
}
// Parse headers JSON if present

View File

@@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS public.api_keys (
CREATE TABLE IF NOT EXISTS public.hooks (
active boolean NOT NULL DEFAULT true,
allow_insecure boolean NOT NULL DEFAULT false,
created_at timestamp NOT NULL DEFAULT now(),
deleted_at timestamp,
description text,

View File

@@ -47,6 +47,7 @@ Table hooks {
headers text [note: 'JSON encoded headers']
events text [note: 'JSON array of event types']
active boolean [not null, default: true]
allow_insecure boolean [not null, default: false, note: 'Skip TLS certificate verification']
description text
secret varchar(255) [note: 'HMAC signature secret']
retry_count int [not null, default: 3]

View File

@@ -51,6 +51,7 @@ CREATE TABLE IF NOT EXISTS hooks (
retry_count INTEGER NOT NULL DEFAULT 3,
timeout INTEGER NOT NULL DEFAULT 30,
active BOOLEAN NOT NULL DEFAULT 1,
allow_insecure BOOLEAN NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,