feat(rest,config): wire CORS, real readiness, TLS options, error hygiene

- CORS config is now actually applied to the router (the middleware
  existed but was never wired); preflight returns 204 for allowed
  origins and 403 with no CORS headers for disallowed ones.
- /readyz runs real dependency checks (queue, auth database) and
  returns 503 with per-component detail when not ready; exported
  handlers support dedicated health listeners.
- Optional server.tls (cert_file/key_file) for REST and gRPC, validated
  at config load.
- 5xx responses no longer echo internal error details; not-found and
  already-sent map to 404/409 on cancel/retry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-18 09:15:57 -07:00
parent 21990f2533
commit ee82522b7c
6 changed files with 154 additions and 31 deletions
+20 -4
View File
@@ -27,10 +27,20 @@ type Config struct {
// ServerConfig contains server configuration
type ServerConfig struct {
GRPCPort int `mapstructure:"grpc_port"`
RESTPort int `mapstructure:"rest_port"`
Host string `mapstructure:"host"`
Mode string `mapstructure:"mode"` // "both", "grpc", "rest"
GRPCPort int `mapstructure:"grpc_port"`
RESTPort int `mapstructure:"rest_port"`
Host string `mapstructure:"host"`
Mode string `mapstructure:"mode"` // "both", "grpc", "rest"
TLS TLSConfig `mapstructure:"tls"`
}
// TLSConfig enables TLS on the REST and gRPC listeners. When disabled the
// servers speak plaintext, which is only appropriate behind a TLS-terminating
// gateway or service mesh.
type TLSConfig struct {
Enabled bool `mapstructure:"enabled"`
CertFile string `mapstructure:"cert_file"`
KeyFile string `mapstructure:"key_file"`
}
// NotifiersConfig contains configuration for all notifier types
@@ -258,6 +268,12 @@ func (c *Config) Validate() error {
return fmt.Errorf("invalid server mode: %s (must be both, grpc, or rest)", c.Server.Mode)
}
if c.Server.TLS.Enabled {
if c.Server.TLS.CertFile == "" || c.Server.TLS.KeyFile == "" {
return fmt.Errorf("server.tls.enabled requires both cert_file and key_file")
}
}
// Validate queue config
validQueueTypes := map[string]bool{"local": true, "kafka": true}
if !validQueueTypes[c.Queue.Type] {