Commit Graph

8 Commits

Author SHA1 Message Date
0f31c7645c feat(cache): add pingora-cache integration with per-route config
Add in-memory HTTP response cache using pingora-cache MemCache backend.
Cache runs after the detection pipeline so cache hits bypass upstream
request modifications and body rewriting. Respects Cache-Control
(no-store, private, s-maxage, max-age), skips caching for routes with
body rewrites or auth subrequest headers, and supports configurable
default TTL, stale-while-revalidate, and max file size per route.

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:20 +00:00
76ad9e93e5 feat(static_files): add static file serving, SPA fallback, rewrites, body rewriting, and auth subrequests
Add static file serving with try_files chain ($uri, $uri.html,
$uri/index.html, fallback), regex-based URL rewrites compiled at
startup, response body find/replace for text/html and JS content,
auth subrequests with header capture for path routes, and custom
response headers per route. Extends RouteConfig with static_root,
fallback, rewrites, body_rewrites, and response_headers fields.

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:20 +00:00
0fd10110ff feat(proxy): add request IDs, tracing spans, and observability hooks
Generate UUID v4 request IDs per request, create manual tracing spans
(Pingora types don't impl Debug), record Prometheus metrics for
detection decisions and request totals, and forward X-Request-Id to
both upstream requests and downstream responses.

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:20 +00:00
867b6b2489 feat(proxy): integrate DDoS, scanner, and rate limiter into request pipeline
Wire up all three detection layers in request_filter with pipeline
logging at each stage for unfiltered training data. Add DDoS, scanner,
and rate_limit config sections. Bot allowlist check before scanner
model on the hot path. CLI subcommands for train/replay.

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:20 +00:00
10de00990c fix(proxy): handle Expect: 100-continue for large upstream uploads
Docker's OCI distribution protocol sends Expect: 100-continue for blob
uploads larger than ~5 MB. Without this fix, Pingora forwarded the header
to Gitea, Gitea responded with 100 Continue, and Pingora could not reliably
proxy the informational response back — causing spurious 400 errors for the
client on large image layer pushes.

Fix: respond with 100 Continue in request_filter before upstream_peer is
called, then strip the Expect header in upstream_request_filter so the
upstream never sends its own 100 Continue.

Also adds a unit test verifying that remove_header("expect") strips the
header from the upstream request without disturbing other headers.

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:19 +00:00
4ce008dc11 fix(proxy): forward X-Forwarded-Proto via insert_header; add e2e test
Root cause: upstream_request_filter was inserting x-forwarded-proto with
a raw headers.insert() call (via DerefMut) which only updates base.headers
but NOT the CaseMap. header_to_h1_wire zips CaseMap with base.headers, so
headers added without a CaseMap entry are silently dropped on the wire.

Fix: use insert_header() which keeps both maps in sync.

Also adds:
- src/lib.rs + [lib] section: exposes SunbeamProxy/RouteConfig/AcmeRoutes
  to integration tests without re-declaring modules in main.rs
- tests/e2e.rs: real end-to-end test — starts a SunbeamProxy over plain
  HTTP, routes it to a TCP echo backend, and asserts x-forwarded-proto: http
  is present in the upstream request headers
- Updated unit tests to verify header_to_h1_wire round-trip (not just that
  HeaderMap::insert works in isolation)

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:19 +00:00
d0146b47e3 feat(proxy): add per-route disable_secure_redirection; preserve query string in redirect
By default every plain-HTTP request is 301-redirected to HTTPS — no upstream
is ever contacted, making it as close to an L4 redirect as HTTP allows.

New RouteConfig field `disable_secure_redirection` (bool, default false):
when set to true on a route, plain-HTTP requests for that host pass through
to the backend unchanged instead of being redirected.

Also fixes the redirect URL to include the original query string, which was
previously dropped (e.g. ?next=/dashboard would be lost after redirect).

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:19 +00:00
6ec0f78a5b feat: initial sunbeam-proxy implementation
Custom Pingora-based edge proxy for the Sunbeam infrastructure stack.

- HTTPS termination: mkcert file-based (local dev) or rustls-acme ACME (production)
- Host-prefix routing with path-based sub-routing (auth virtual host)
- HTTP→HTTPS redirect, WebSocket passthrough
- cert-manager HTTP-01 challenge routing via Kubernetes Ingress watcher
- TLS cert auto-reload via K8s Secret watcher
- JSON structured audit logging (tracing-subscriber)
- OpenTelemetry OTLP stub (disabled by default)
- Multi-stage Dockerfile: musl static binary on chainguard/static distroless image

Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
2026-03-10 23:38:19 +00:00