Send the build version in the outbound User-Agent (closes #313)
check / check (push) Successful in 3m45s

The http and slack targets sent the fixed User-Agent webhooker/1.0. The
delivery engine now takes the version from Globals, the value the web UI
footer shows, and one method builds webhooker/<version> for both
targets. The http target still sets it after the configured headers, so
a configured or inbound User-Agent never reaches the wire.

A test builds the engine through its real constructor with a known
version and checks the header each target sends.

Model: opus-5-5
This commit is contained in:
2026-10-02 06:54:39 +00:00
parent cb7bafab17
commit 014105a039
7 changed files with 114 additions and 9 deletions
+14
View File
@@ -14,6 +14,7 @@ import (
"go.uber.org/fx"
"gorm.io/gorm"
"sneak.berlin/go/webhooker/internal/database"
"sneak.berlin/go/webhooker/internal/globals"
"sneak.berlin/go/webhooker/internal/lifecycle"
"sneak.berlin/go/webhooker/internal/logger"
"sneak.berlin/go/webhooker/internal/metrics"
@@ -146,6 +147,7 @@ type EngineParams struct {
DB *database.Database
DBManager *database.WebhookDBManager
Globals *globals.Globals
Logger *logger.Logger
SSRFGuard *Guard
}
@@ -167,6 +169,10 @@ type Engine struct {
retryCh chan Task
workers int
// version is the running build's version, the one the web UI
// footer shows. userAgent puts it on every outbound request.
version string
// mtr is the delivery metric set. Production wires the
// process-wide one; a test can substitute a set registered on
// a private registry so its assertions are not disturbed by
@@ -204,6 +210,7 @@ func New(
deliveryCh: make(chan Task, deliveryChannelSize),
retryCh: make(chan Task, retryChannelSize),
workers: defaultWorkers,
version: params.Globals.Version,
mtr: metrics.Default(),
}
@@ -300,6 +307,13 @@ func (e *Engine) ScheduleRetry(
})
}
// userAgent is the User-Agent header of every http and slack
// delivery request: the program name and the running build's
// version.
func (e *Engine) userAgent() string {
return "webhooker/" + e.version
}
// registerHooks wires the engine's start and stop into the fx
// lifecycle. The start hook's context is deliberately ignored
// (see start for why the worker pool must not inherit it); the