From f4af997a286d0ab4566da25f4281515046f08f99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Houpert?= <10154151+lhoupert@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:59:11 +0100 Subject: [PATCH 1/2] fix: render shared ingress annotations as a merged map and guard nil browser.ingress Merging traefik entrypoints and user ingress.annotations via string concatenation dropped the newline between them, producing invalid YAML whenever both were set (whole release failed to template). Build a dict and toYaml it once instead; mergeOverwrite keeps user annotations winning over the generated entrypoints key. Also make eoapi.browserIngressPath nil-safe: browser.ingress: null crashed the browser Deployment render via the new SB_pathPrefix env, even with ingress disabled. Regression tests added for both. --- .../eoapi/templates/_helpers/networking.tpl | 15 +++--- charts/eoapi/tests/ingress_test.yaml | 46 +++++++++++++++++++ charts/eoapi/tests/stac_browser_tests.yaml | 15 ++++++ 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/charts/eoapi/templates/_helpers/networking.tpl b/charts/eoapi/templates/_helpers/networking.tpl index 116b2da8..7da08bb1 100644 --- a/charts/eoapi/templates/_helpers/networking.tpl +++ b/charts/eoapi/templates/_helpers/networking.tpl @@ -56,14 +56,13 @@ Shared Traefik entrypoints and user annotations for ingress resources. */}} {{- define "eoapi.ingressCommonAnnotations" -}} {{- $root := . -}} -{{- $ingressAnnotations := $root.Values.ingress.annotations | default dict -}} -{{- if eq $root.Values.ingress.className "traefik" -}} -{{- if and $root.Values.ingress.entrypoints (not (hasKey $ingressAnnotations "traefik.ingress.kubernetes.io/router.entrypoints")) -}} -traefik.ingress.kubernetes.io/router.entrypoints: {{ $root.Values.ingress.entrypoints | quote }} +{{- $annotations := dict -}} +{{- if and (eq $root.Values.ingress.className "traefik") $root.Values.ingress.entrypoints -}} +{{- $_ := set $annotations "traefik.ingress.kubernetes.io/router.entrypoints" ($root.Values.ingress.entrypoints | toString) -}} {{- end -}} -{{- end -}} -{{- if not (empty $ingressAnnotations) -}} -{{- toYaml $ingressAnnotations -}} +{{- $annotations = mergeOverwrite $annotations (deepCopy ($root.Values.ingress.annotations | default dict)) -}} +{{- if not (empty $annotations) -}} +{{- toYaml $annotations -}} {{- end -}} {{- end -}} @@ -166,7 +165,7 @@ Return true when the browser should be exposed via its own ingress. Return the configured browser ingress path without trailing slash ("/" for a root path). */}} {{- define "eoapi.browserIngressPath" -}} -{{- trimSuffix "/" (.Values.browser.ingress.path | default "/browser") | default "/" -}} +{{- trimSuffix "/" ((((.Values.browser).ingress).path) | default "/browser") | default "/" -}} {{- end -}} {{/* diff --git a/charts/eoapi/tests/ingress_test.yaml b/charts/eoapi/tests/ingress_test.yaml index 9fdb08f5..15c4424a 100644 --- a/charts/eoapi/tests/ingress_test.yaml +++ b/charts/eoapi/tests/ingress_test.yaml @@ -200,6 +200,52 @@ tests: traefik.ingress.kubernetes.io/router.entrypoints: web traefik.ingress.kubernetes.io/router.middlewares: NAMESPACE-RELEASE-NAME-strip-prefix-middleware@kubernetescrd + - it: "traefik entrypoints coexist with custom annotations" + template: templates/networking/ingress.yaml + set: + ingress.className: "traefik" + ingress.entrypoints: "websecure" + ingress.annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + ingress.host: "eoapi.local" + raster.enabled: true + stac.enabled: false + vector.enabled: false + multidim.enabled: false + browser.enabled: false + asserts: + - isKind: + of: Ingress + - equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + cert-manager.io/cluster-issuer: "letsencrypt-prod" + traefik.ingress.kubernetes.io/router.middlewares: NAMESPACE-RELEASE-NAME-strip-prefix-middleware@kubernetescrd + + - it: "browser ingress combines entrypoints with custom annotations" + template: templates/networking/browser-ingress.yaml + set: + ingress.className: "traefik" + ingress.entrypoints: "websecure" + ingress.annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + ingress.host: "eoapi.local" + raster.enabled: false + stac.enabled: false + vector.enabled: false + multidim.enabled: false + browser.enabled: true + asserts: + - isKind: + of: Ingress + - equal: + path: metadata.annotations["traefik.ingress.kubernetes.io/router.entrypoints"] + value: websecure + - equal: + path: metadata.annotations["cert-manager.io/cluster-issuer"] + value: letsencrypt-prod + - it: "all services enabled with custom paths" template: templates/networking/ingress.yaml set: diff --git a/charts/eoapi/tests/stac_browser_tests.yaml b/charts/eoapi/tests/stac_browser_tests.yaml index 4dcd9f18..67ea09dc 100644 --- a/charts/eoapi/tests/stac_browser_tests.yaml +++ b/charts/eoapi/tests/stac_browser_tests.yaml @@ -42,6 +42,21 @@ tests: content: name: SB_pathPrefix value: "/stac-browser/" + - it: "stac browser deployment tolerates null browser ingress block" + set: + raster.enabled: false + stac.enabled: false + vector.enabled: false + multidim.enabled: false + browser.enabled: true + browser.ingress: null + template: templates/services/browser/deployment.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: SB_pathPrefix + value: "/browser/" - it: "stac browser deployment with root ingress path" set: raster.enabled: false From d8f7d4ec6ef04304fa62d832d1b714f91b2a8620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Houpert?= <10154151+lhoupert@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:06:47 +0100 Subject: [PATCH 2/2] test: pin traefik middleware guarantees and ingress.rootPath behavior Pin three previously untested behaviors of the centralized ingress logic: the strip-prefix middleware annotation and Middleware object are absent when no path needs stripping (the dangling-reference fix), the auth-proxied stac path is excluded from strip-prefix prefixes, and docServer honors ingress.rootPath. --- charts/eoapi/tests/ingress_test.yaml | 54 ++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/charts/eoapi/tests/ingress_test.yaml b/charts/eoapi/tests/ingress_test.yaml index 15c4424a..9b5a6f50 100644 --- a/charts/eoapi/tests/ingress_test.yaml +++ b/charts/eoapi/tests/ingress_test.yaml @@ -75,6 +75,8 @@ tests: - equal: path: spec.ingressClassName value: "traefik" + - notExists: + path: metadata.annotations["traefik.ingress.kubernetes.io/router.middlewares"] - it: "vector ingress with nginx controller" template: templates/networking/ingress.yaml @@ -431,6 +433,26 @@ tests: path: spec.rules[0].http.paths[0].backend.service.name value: RELEASE-NAME-doc-server + - it: "docServer honors ingress.rootPath" + template: templates/networking/ingress.yaml + set: + ingress.enabled: true + ingress.className: "nginx" + ingress.rootPath: "docs" + raster.enabled: false + stac.enabled: false + vector.enabled: false + multidim.enabled: false + browser.enabled: false + docServer.enabled: true + asserts: + - equal: + path: spec.rules[0].http.paths[0].path + value: "/docs" + - equal: + path: spec.rules[0].http.paths[0].backend.service.name + value: RELEASE-NAME-doc-server + - it: "mockOidcServer with custom path" template: templates/networking/ingress.yaml set: @@ -581,3 +603,35 @@ tests: - /stac - /raster - /multidim + + - it: "renders no strip-prefix middleware when no path needs stripping" + template: templates/networking/traefik-middleware.yaml + set: + ingress.className: "traefik" + stac.enabled: true + stac.ingress.path: "/" + raster.enabled: false + vector.enabled: false + multidim.enabled: false + browser.enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: "excludes auth-proxied stac from strip-prefix prefixes" + template: templates/networking/traefik-middleware.yaml + set: + ingress.className: "traefik" + stac.enabled: true + stac-auth-proxy.enabled: true + raster.enabled: true + vector.enabled: false + multidim.enabled: false + browser.enabled: false + asserts: + - isKind: + of: Middleware + - equal: + path: spec.stripPrefix.prefixes + value: + - /raster