Commit graph

33 commits

Author SHA1 Message Date
Snider
465bd60a8a feat: add DescribableGroup interface for OpenAPI metadata
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:42:13 +00:00
Snider
8ba1716215 feat: add WithTracing OpenTelemetry distributed tracing middleware
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>
2026-02-21 00:24:46 +00:00
Snider
f5d2f45b94 feat: add WithExpvar runtime metrics endpoint
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:20:31 +00:00
Snider
32b3680402 feat: add WithPprof runtime profiling endpoints
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>
2026-02-21 00:18:05 +00:00
Snider
d517fa2d71 feat: add WithGraphQL endpoint and playground support
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>
2026-02-21 00:12:25 +00:00
Snider
36d77ea015 feat: add WithI18n locale detection middleware
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>
2026-02-21 00:08:17 +00:00
Snider
a612d85dba feat: add WithLocation reverse proxy header detection middleware
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 00:04:28 +00:00
Snider
8fc307b454 feat: add WithSSE server-sent events support
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>
2026-02-21 00:01:04 +00:00
Snider
7b3f99e421 feat: add WithHTTPSign HTTP signature verification middleware
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 23:57:30 +00:00
Snider
67dcc83a37 feat: add WithAuthz Casbin authorisation middleware
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 23:49:02 +00:00
Snider
e00ef00db8 feat: add WithSessions server-side session middleware
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 23:44:46 +00:00
Snider
0ab962a258 feat: add WithCache response caching middleware
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:41:48 +00:00
Snider
64a8b16ca2 feat: add WithBrotli response compression middleware
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 23:37:46 +00:00
Snider
daae6f7879 feat: add WithStatic static file serving middleware
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>
2026-02-20 23:23:17 +00:00
Snider
68ba956587 feat: add WithGzip response compression middleware
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:20:46 +00:00
Snider
6521b90d26 feat: add WithTimeout per-request timeout middleware
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>
2026-02-20 23:18:24 +00:00
Snider
0cce70082b fix: correct misleading IsDevelopment comments in WithSecure
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 23:15:29 +00:00
Snider
f5ce02d661 feat: add WithSlog structured request logging middleware
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>
2026-02-20 23:14:15 +00:00
Snider
6bb7195cca feat: add WithSecure security headers middleware
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>
2026-02-20 23:10:52 +00:00
Snider
8f3e496173 test: add live Authentik integration tests
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>
2026-02-20 19:29:20 +00:00
Snider
0d424903e6 docs: add Authentik integration guide to CLAUDE.md and README
Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 16:45:26 +00:00
Snider
d279343491 feat(authentik): add RequireAuth and RequireGroup middleware
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>
2026-02-20 16:43:55 +00:00
Snider
5cba2f2cd4 feat(authentik): add OIDC JWT validation middleware
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>
2026-02-20 16:42:23 +00:00
Snider
d760e77e49 feat(authentik): add header extraction middleware and WithAuthentik option
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>
2026-02-20 16:38:13 +00:00
Snider
6cd3b7e7e0 feat(authentik): add AuthentikUser and AuthentikConfig types
Introduce core types for the Authentik forward-auth integration:
- AuthentikConfig with Issuer, ClientID, TrustedProxy, PublicPaths
- AuthentikUser with Username, Email, Name, UID, Groups, Entitlements, JWT
- HasGroup helper for group membership checks

Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 16:36:38 +00:00
Snider
17ae94530d docs: add CLAUDE.md and README.md
Agent instructions and quick start guide with RouteGroup example.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 15:57:44 +00:00
Snider
095c38a8c4 feat: add Swagger UI endpoint with runtime spec serving
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 15:56:29 +00:00
Snider
22f8a6915c feat: add WebSocket endpoint and channel listing from StreamGroups
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 15:53:10 +00:00
Snider
d21734d8d9 feat: add bearer auth, request ID, and CORS middleware
Co-Authored-By: Virgil <virgil@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 15:49:35 +00:00
Snider
db75c88d58 feat: add Engine with Register, Handler, Serve, and graceful shutdown
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>
2026-02-20 15:46:11 +00:00
Snider
6f5fb69944 feat: add RouteGroup and StreamGroup interfaces
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>
2026-02-20 15:44:58 +00:00
Snider
7835837e38 feat: add response envelope with OK, Fail, Paginated helpers
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>
2026-02-20 15:44:17 +00:00
Snider
889391a3a7 chore: scaffold go-api module
EUPL-1.2 licence, module path forge.lthn.ai/core/go-api.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-02-20 15:42:16 +00:00