Skip to content

feat(extension-server): branded data-plane error pages#205

Merged
scotwells merged 1 commit into
mainfrom
feat/branded-error-pages
Jun 19, 2026
Merged

feat(extension-server): branded data-plane error pages#205
scotwells merged 1 commit into
mainfrom
feat/branded-error-pages

Conversation

@scotwells

@scotwells scotwells commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Why

When a customer's site is reached through Datum's edge and the origin can't be served — an offline Connector tunnel, a down backend, a timeout — Envoy answers, not the customer's app. On the downstream/Connector data plane that's a raw 503 no healthy upstream. This serves a Datum-branded HTML error page there instead — the page a customer's own users see during the customer's outage.

Implements the Branded Data-Plane Error Pages enhancement — proposal in #204 (doc).

What changed

  • New InjectLocalReplyConfig listener mutation in the extension server: any edge-generated response ≥ 500 renders the branded body (status code preserved). Covers HTTP/2 and HTTP/3 listeners; skips internal/readiness listeners; idempotent.
  • Content from an optional mounted ConfigMap (envoy-error-pages) with a compiled-in fallback — works out of the box, editable later via GitOps.
  • Config: gateway.errorPage.{enabled,bodyPath,minStatusCode}.

Notes for review

  • Fail-safe: the downstream hook is failOpen:false; missing/empty content is a no-op, and the injector errors only on a malformed HCM.
  • Ships working via the embedded default. The envoy-error-pages ConfigMap content + a content-change reload are a follow-up in the infra repo.
  • golangci-lint skipped locally (go1.25 vs repo's go1.26.4 toolchain — not a code issue).

Draft — not for merge/release yet; pending live verification on staging (503 → branded HTML).

🤖 Generated with Claude Code

Serve a Datum-branded HTML error page for edge-generated 5xx responses on
the downstream / Connector data plane, replacing raw bodies like
"no healthy upstream" that visitors see during a customer outage.

The extension server attaches an Envoy local_reply_config to every RDS-based
(customer-facing) HCM during PostTranslateModify, mirroring the existing
Coraza listener mutation:

- New mutator InjectLocalReplyConfig (mutate/localreply.go): one response
  mapper, status_code_filter >= minStatusCode gated by a runtime key, body +
  content-type override, original status code preserved. Skips non-RDS HCMs
  (EG readiness listener), idempotent, no-op when disabled or body empty.
- Embedded default page (assets/error-5xx-default.html) compiled into the
  operator as an always-valid fallback.
- GatewayConfig.errorPage block (enabled / bodyPath / minStatusCode, plus
  defaulted runtimeKey + contentType); run.go sources the body from the
  optional ConfigMap mount and falls back to the embed on any read problem.
- Optional envoy-error-pages ConfigMap volume mounted read-only at
  /etc/datum/error-pages; pod starts cleanly when the ConfigMap is absent.
- New nso_extension_local_reply_mutations_total metric + log/trace fields.

Fail-safe by construction: with failOpen:false on the downstream EG, a hook
error blocks xDS fleet-wide, so the injector only errors on a genuinely
malformed HCM. Missing/empty content is a no-op, never an error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scotwells
scotwells marked this pull request as ready for review June 19, 2026 13:45
@mattdjenkinson

Copy link
Copy Markdown
Contributor

@scotwells do you want to merge this and then i can re-create the old template in a new pr?

@scotwells

Copy link
Copy Markdown
Contributor Author

@mattdjenkinson we'd keep the real template we use in the infra repo so we don't need to do software releases to update the template

@mattdjenkinson

Copy link
Copy Markdown
Contributor

Sorry apparently i completely ignored that in the enhancement doc!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants