Replace the hardcoded Swagger 2.0 JSON template with SpecBuilder-backed
OpenAPI 3.1 generation. The swagger spec is now built lazily from
registered RouteGroups (including DescribableGroup and ToolBridge
endpoints) and cached via sync.Once. Uses unique swag instance names
to avoid global registry collisions in tests.
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ExportSpec writes the OpenAPI spec to any io.Writer in JSON or YAML
format. ExportSpecToFile is a convenience wrapper that creates the
parent directory and writes to a file path. Adds gopkg.in/yaml.v3
for YAML marshalling.
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds WithTracing(serviceName) option using the official otelgin
instrumentation (go.opentelemetry.io/contrib/.../otelgin v0.65.0).
Each request produces a span with http.request.method, http.route,
and http.response.status_code attributes. Trace context is propagated
via W3C traceparent headers.
Also exposes NewTracerProvider() convenience helper for wiring up
a synchronous TracerProvider in tests and simple deployments.
Co-Authored-By: Virgil <virgil@lethean.io>
Registers Go pprof handlers at /debug/pprof/ via gin-contrib/pprof
when the WithPprof() option is enabled. Uses the same flag-in-build()
pattern as WithSwagger() — routes are only mounted when explicitly
opted in.
Co-Authored-By: Virgil <virgil@lethean.io>
Mount a gqlgen ExecutableSchema as a Gin handler at /graphql with
optional playground UI at /graphql/playground. Supports custom path
via WithGraphQLPath().
Co-Authored-By: Virgil <virgil@lethean.io>
Lightweight Accept-Language header parsing using golang.org/x/text/language
for RFC 5646 language matching with quality weighting. Provides GetLocale()
and GetMessage() context helpers for handlers. Bridges to go-i18n grammar
engine later — no heavy file-based i18n dependencies needed.
Co-Authored-By: Virgil <virgil@lethean.io>
Add SSEBroker type that manages SSE client connections and broadcasts
events to subscribed clients. Clients connect via GET /events and
optionally filter by channel with ?channel=<name>. Includes Publish,
ClientCount, and Drain methods for event broadcasting and lifecycle
management.
Co-Authored-By: Virgil <virgil@lethean.io>
Adds WithStatic(urlPrefix, root) option using gin-contrib/static to
serve files from a local directory at the given URL prefix. Directory
listing is disabled for security.
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wraps gin-contrib/timeout to enforce per-request deadlines. When a
handler exceeds the configured duration, the client receives a 504
Gateway Timeout with the standard Fail("timeout", ...) error envelope.
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds WithSlog(logger) option wrapping gin-contrib/slog for structured
request logging via Go's standard log/slog package. Logs method, path,
status code, latency, and client IP for every request. Falls back to
slog.Default() when nil is passed.
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wraps gin-contrib/secure to set HSTS (1 year, includeSubdomains),
X-Frame-Options DENY, X-Content-Type-Options nosniff, and
Referrer-Policy strict-origin-when-cross-origin on all responses.
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validates go-api Authentik middleware against the production OIDC
provider at auth.lthn.io. Tests client_credentials token acquisition,
JWT validation via JWKS, forward-auth header extraction, RequireAuth/
RequireGroup enforcement, and permissive fail-open behaviour.
Gated behind AUTHENTIK_INTEGRATION=1 env var so normal CI is unaffected.
Also fixes README issuer URL to use auth.lthn.io.
Co-Authored-By: Virgil <virgil@lethean.io>
Add two route-level middleware helpers for enforcing authentication and
group membership. RequireAuth returns 401 when no user is in context.
RequireGroup returns 401 for unauthenticated requests and 403 when the
user lacks the specified group. Both use UK English error codes
("unauthorised", "forbidden") consistent with existing bearer auth.
Co-Authored-By: Virgil <virgil@lethean.io>
Add JWT validation as a second authentication block in the Authentik
middleware. Direct API clients can now send Authorization: Bearer <jwt>
tokens validated via OIDC discovery (coreos/go-oidc). Forward-auth
headers take priority; JWT is only attempted when no user was extracted
from headers. Validation is permissive — failures continue without a
user context. OIDC providers are cached per issuer to avoid repeated
discovery.
Co-Authored-By: Virgil <virgil@lethean.io>
Add permissive forward-auth middleware that extracts user identity from
X-authentik-* headers when TrustedProxy is enabled. Headers are ignored
when TrustedProxy is false to prevent spoofing from untrusted sources.
- GetUser(c) helper retrieves AuthentikUser from Gin context
- authentikMiddleware splits groups/entitlements on pipe delimiter
- /health and /swagger bypass header extraction
- WithAuthentik option wires middleware into the Engine
Co-Authored-By: Virgil <virgil@lethean.io>
Engine manages route groups and builds a Gin-based HTTP handler.
New() accepts functional options (WithAddr). Handler() builds a fresh
Gin engine with Recovery middleware and /health endpoint. Serve()
starts the server and performs graceful shutdown on context cancellation.
Co-Authored-By: Virgil <virgil@lethean.io>
RouteGroup declares Name, BasePath, and RegisterRoutes for subsystems
to mount their endpoints onto a Gin router group. StreamGroup optionally
declares WebSocket channel names. Gin v1.11.0 added as dependency.
Co-Authored-By: Virgil <virgil@lethean.io>
Generic Response[T] envelope with Success, Data, Error, and Meta fields.
Includes OK, Fail, FailWithDetails, and Paginated constructor functions.
JSON marshalling correctly omits empty fields via omitempty tags.
Co-Authored-By: Virgil <virgil@lethean.io>