Skip to content

feat: routing.filters pass-through, host-scoped WebOrigins, unified route builders#141

Open
viniciusdc wants to merge 3 commits into
mainfrom
refactor/routing-filters-overlap
Open

feat: routing.filters pass-through, host-scoped WebOrigins, unified route builders#141
viniciusdc wants to merge 3 commits into
mainfrom
refactor/routing-filters-overlap

Conversation

@viniciusdc

Copy link
Copy Markdown
Collaborator

Summary

PR 2 of the routing/SecurityPolicy consolidation (#139). Unifies the protected and public HTTPRoute builders onto a shared path, then builds the additive changes on top so they land in one place for both routes.

Refactor first

buildHTTPRoute/buildPublicHTTPRoute and their rule construction were ~95% duplicated. Extracted three shared helpers in routing/httproute.go:

  • resolveListenerSection — TLS listener/section resolution (was copy-pasted in both builders)
  • buildRouteMatches — path-match construction, parameterized by the default pathType so the main route stays PathPrefix and public routes stay Exact
  • buildRouteRule — a single rule with backend refs + filters, used by both routes

routing.filters pass-through (closes #137)

Host-scoped Keycloak WebOrigins (closes #37)

  • Replaced the wildcard WebOrigins: ["*"] with the NebariApp hostname (both schemes) on all four client paths — main client create/update and SPA client create/update — via a buildWebOrigins helper mirroring buildRedirectURLs. Keeps the OIDC client to least privilege for CORS to the token endpoint.

publicRoutes vs enforceAtGateway docs (partial #118)

Generated

  • zz_generated.deepcopy.go, the CRD, and docs/api-reference.md regenerated. The CRD grows substantially because the filters field inlines the full upstream HTTPRouteFilter schema — expected for a pass-through.

Test plan

  • go build ./..., go vet ./..., gofmt -l clean.
  • go test across all unit packages (excl. e2e) passes, including:
    • TestUserFiltersPropagateToRoutes — filters appear, in order, on both the protected and public route
    • TestUserFiltersAbsentWhenUnset — no filters when unconfigured
    • TestKeycloakProvider_BuildWebOrigins — host-scoped, no wildcard
  • The internal/controller envtest suite fails locally on a pre-existing scheme-registration gap (also fails on clean main; needs make test's CRD setup) — unrelated to this change.

…oute builders

Unify the protected and public HTTPRoute builders onto a shared path, then
build the additive changes on top so they land in one place for both routes.

Refactor (routing/httproute.go):
- Extract resolveListenerSection (TLS listener/section resolution),
  buildRouteMatches (path-match construction, parameterized by the default
  pathType so the main route stays PathPrefix and public routes stay Exact),
  and buildRouteRule (single rule with backend refs + filters). The main and
  public builders were ~95% duplicated; they now share these helpers.

routing.filters pass-through:
- Add RoutingConfig.Filters []gatewayv1.HTTPRouteFilter, appended in order to
  the rule of both the protected and public HTTPRoute via buildRouteRule. The
  operator does not interpret, reorder, or strip them -- same escape-hatch
  pattern as the existing Annotations field. Lets deployers fix gateway-side
  header issues (e.g. an upstream's invalid CORS header combo) without forking
  the operator or rebuilding the backend image.

Host-scoped Keycloak WebOrigins:
- Replace the wildcard WebOrigins ["*"] with the NebariApp hostname (both
  schemes) on all four client paths (main client create/update, SPA client
  create/update), via a buildWebOrigins helper mirroring buildRedirectURLs.
  Keeps the OIDC client to least privilege for CORS to the token endpoint.

publicRoutes vs enforceAtGateway docs:
- Cross-reference the two fields in the CRD comments and routing.md, calling
  out that publicRoutes carves out a subset of paths and is not the way to
  disable auth for the whole app (use enforceAtGateway: false). The
  reconciler/admission guard for the overlap case is intentionally left out of
  this change -- Gateway API precedence makes most overlaps intended, so the
  guard needs a precedence-aware design pass.

Regenerated zz_generated.deepcopy.go, the CRD, and docs/api-reference.md.
New unit tests cover filter propagation+ordering on both routes and the
host-scoped WebOrigins.

Closes #137
Closes #37
…budget

Inlining the full gateway.networking.k8s.io/v1 HTTPRouteFilter OpenAPI schema
copied its nested x-kubernetes-validations (CEL) rules -- notably the cors
filter's allowOrigins/allowMethods and the externalAuth/requestMirror backendRef
rules -- into the NebariApp CRD. That pushed the per-CRD CEL cost total past the
Kubernetes budget (~1.22x over, with cors.allowOrigins alone 7.2x over its
per-rule limit), so the CRD failed to install and the E2E, Helm, and install
checks all failed.

Mark Filters as Schemaless + PreserveUnknownFields (Type=array) so controller-gen
emits a permissive array schema with no nested CEL. The Go type stays
[]gatewayv1.HTTPRouteFilter, so each entry is still decoded into the typed struct
and applied to the generated HTTPRoute, where Gateway API validates it -- the
pass-through contract is unchanged. Shrinks the generated CRD by ~1300 lines.
The previous attempt set Type=array together with Schemaless, which produced
a `type: array` node with no `items` -- a structural schema requires `items`
for arrays, so the CRD still failed to install ("filters.items: Required
value: must be specified").

Drop the explicit Type marker and keep Schemaless + PreserveUnknownFields, so
controller-gen emits the field as `{x-kubernetes-preserve-unknown-fields: true}`
(the canonical "arbitrary content" schema) with no type constraint and no nested
CEL. Verified by installing the regenerated CRD into a real apiserver via
envtest: CRD installation now succeeds.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants