From 8bd88b2be38c03760ec17df727db663768a2c0fd Mon Sep 17 00:00:00 2001 From: Ludal Date: Fri, 27 Feb 2026 09:03:50 +0100 Subject: [PATCH 1/9] CH-243: Make route pattern customizable --- applications/samples/deploy/values.yaml | 3 ++- deployment-configuration/helm/templates/ingress.yaml | 8 +++++--- deployment-configuration/helm/values.yaml | 4 +++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/applications/samples/deploy/values.yaml b/applications/samples/deploy/values.yaml index 607c9944..23886789 100644 --- a/applications/samples/deploy/values.yaml +++ b/applications/samples/deploy/values.yaml @@ -7,6 +7,7 @@ harness: service: port: 8080 auto: true + route_pattern: '(?!\/metrics\/?$)\/.*' use_services: - name: common deployment: @@ -96,4 +97,4 @@ harness: dockerfile: buildArgs: - TEST_ARGUMENT: example value \ No newline at end of file + TEST_ARGUMENT: example value diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index 5d3ea8ee..bfbb9466 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -2,6 +2,7 @@ {{ $domain := .root.Values.domain }} {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }} {{ $app := .app }} + {{- $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} http: paths: {{- if and $app.harness.secured $secured_gatekeepers $app.harness.uri_role_mapping }} @@ -39,7 +40,7 @@ {{- end }} {{- end }} {{- end }} - - path: /(.*) + - path: /{{ $routePattern }} pathType: ImplementationSpecific backend: service: @@ -52,7 +53,8 @@ {{ $domain := .root.Values.domain }} {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }} {{ $app := get .root.Values.apps .service_name}} - - path: /proxy/{{ $app.harness.service.name }}/(.*) + {{- $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} + - path: /proxy/{{ $app.harness.service.name }}/{{ $routePattern }} pathType: ImplementationSpecific backend: service: @@ -147,4 +149,4 @@ spec: {{- end }} secretName: tls-secret {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/deployment-configuration/helm/values.yaml b/deployment-configuration/helm/values.yaml index 8b83c047..07391f3a 100644 --- a/deployment-configuration/helm/values.yaml +++ b/deployment-configuration/helm/values.yaml @@ -40,6 +40,8 @@ ingress: letsencrypt: # -- Email for letsencrypt. email: cloudharness@metacell.us + # -- Default regex segment for routes (used in paths like '/(pattern)'). + route_pattern: "(.*)" backup: # -- Flag to enable/disable backups. active: false @@ -89,4 +91,4 @@ proxy: requests: memory: "32Mi" limits: - memory: "64Mi" \ No newline at end of file + memory: "64Mi" From 61961bbc39b64b24c08ec6f0c4c057f2b31a5c0b Mon Sep 17 00:00:00 2001 From: Ludal Date: Sat, 28 Feb 2026 10:21:36 +0100 Subject: [PATCH 2/9] Include forward slash in route pattern regex --- applications/samples/deploy/values.yaml | 2 +- deployment-configuration/helm/templates/ingress.yaml | 4 ++-- deployment-configuration/helm/values.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/applications/samples/deploy/values.yaml b/applications/samples/deploy/values.yaml index 23886789..0d3b9648 100644 --- a/applications/samples/deploy/values.yaml +++ b/applications/samples/deploy/values.yaml @@ -7,7 +7,7 @@ harness: service: port: 8080 auto: true - route_pattern: '(?!\/metrics\/?$)\/.*' + route_pattern: '/(?!\/metrics\/?$)\/.*' use_services: - name: common deployment: diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index bfbb9466..f0f194c8 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -40,7 +40,7 @@ {{- end }} {{- end }} {{- end }} - - path: /{{ $routePattern }} + - path: {{ $routePattern }} pathType: ImplementationSpecific backend: service: @@ -54,7 +54,7 @@ {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }} {{ $app := get .root.Values.apps .service_name}} {{- $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} - - path: /proxy/{{ $app.harness.service.name }}/{{ $routePattern }} + - path: /proxy/{{ $app.harness.service.name }}{{ $routePattern }} pathType: ImplementationSpecific backend: service: diff --git a/deployment-configuration/helm/values.yaml b/deployment-configuration/helm/values.yaml index 07391f3a..8468b96a 100644 --- a/deployment-configuration/helm/values.yaml +++ b/deployment-configuration/helm/values.yaml @@ -41,7 +41,7 @@ ingress: # -- Email for letsencrypt. email: cloudharness@metacell.us # -- Default regex segment for routes (used in paths like '/(pattern)'). - route_pattern: "(.*)" + route_pattern: "/(.*)" backup: # -- Flag to enable/disable backups. active: false From 8dde96f9cc8be8d243f5d24d3a7e2d8f2bf6b5f0 Mon Sep 17 00:00:00 2001 From: Ludal Date: Sat, 28 Feb 2026 11:08:27 +0100 Subject: [PATCH 3/9] Fix indent --- applications/samples/deploy/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/samples/deploy/values.yaml b/applications/samples/deploy/values.yaml index 0d3b9648..55bcb0d4 100644 --- a/applications/samples/deploy/values.yaml +++ b/applications/samples/deploy/values.yaml @@ -7,7 +7,7 @@ harness: service: port: 8080 auto: true - route_pattern: '/(?!\/metrics\/?$)\/.*' + route_pattern: '/(?!\/metrics\/?$)\/.*' use_services: - name: common deployment: From 4238c752d84e21ea622e76ccb42ba78bdeb34c47 Mon Sep 17 00:00:00 2001 From: Ludal Date: Sat, 28 Feb 2026 11:24:44 +0100 Subject: [PATCH 4/9] Add documentation --- docs/ingress-domains-proxies.md | 36 ++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/ingress-domains-proxies.md b/docs/ingress-domains-proxies.md index 08b86f5c..349ac53f 100644 --- a/docs/ingress-domains-proxies.md +++ b/docs/ingress-domains-proxies.md @@ -68,4 +68,38 @@ proxy: Note that in the case that gatekeepers are enabled, the same configurations are applied to the gatekeepers, unless the application override them on `harness.proxy.*`. -See also the [gatekeepers documentation](./accounts.md#secure-and-enpoint-with-the-gatekeeper). \ No newline at end of file +See also the [gatekeepers documentation](./accounts.md#secure-and-enpoint-with-the-gatekeeper). + +## Route pattern configuration + +Cloud Harness allows customizing which request paths are routed to an application +via a glob-style regular expression. There are two levels where this can be set: + +- **Global**: `ingress.route_pattern` in `deployment-configuration/helm/values.yaml` (applies to all apps by default). +- **Application**: `harness.route_pattern` in an application's `values.yaml` (overrides the global value for that app). + +The Helm ingress template uses the application-level `harness.route_pattern` when present, +falling back to the global `ingress.route_pattern` otherwise. + +Example (global default in `deployment-configuration/helm/values.yaml`): + +```yaml +ingress: + # Default regex segment for routes (used in paths like '/(pattern)') + route_pattern: "/(.*)" +``` + +Example (application override in `applications//deploy/values.yaml`): + +```yaml +harness: + # route_pattern is used to build the Ingress path for the app + route_pattern: '/((?!(?:metrics)(?:/)?$).*)' # exclude only '/metrics' and '/metrics/' +``` + +Notes: +- The pattern is inserted into the generated Ingress `path` field. Make sure the regex + is valid for your ingress controller and matches the expected path syntax. +- If you only need to exclude a single exact path (for example `/metrics`), use a + negative lookahead like the example above. If you prefer a simpler global default, + leave `ingress.route_pattern` as `"/(.*)"` and override per-app when needed. From 6a7d5661dfb29fe7e1535f0822af47c38d3917f5 Mon Sep 17 00:00:00 2001 From: Ludal Date: Sun, 1 Mar 2026 12:44:22 +0100 Subject: [PATCH 5/9] Fix linting --- tools/deployment-cli-tools/tests/test_codefresh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/deployment-cli-tools/tests/test_codefresh.py b/tools/deployment-cli-tools/tests/test_codefresh.py index 5f096f33..65bd1fc2 100644 --- a/tools/deployment-cli-tools/tests/test_codefresh.py +++ b/tools/deployment-cli-tools/tests/test_codefresh.py @@ -483,7 +483,7 @@ def test_steps_ordered_by_stage_in_generated_config(): assert step_stage_indices == sorted(step_stage_indices), \ "Steps are not ordered by stage. Got stages: " + str( [step.get('stage') for step in steps.values() if step and isinstance(step, dict)] - ) + ) finally: import shutil shutil.rmtree(BUILD_MERGE_DIR, ignore_errors=True) From 3dc0062dc7b38621c2f4fc6b7334d28157f880fd Mon Sep 17 00:00:00 2001 From: Ludal Date: Sun, 1 Mar 2026 13:18:15 +0100 Subject: [PATCH 6/9] Try fix nil pointer --- deployment-configuration/helm/templates/ingress.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index f0f194c8..baa3db5a 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -2,7 +2,6 @@ {{ $domain := .root.Values.domain }} {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }} {{ $app := .app }} - {{- $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} http: paths: {{- if and $app.harness.secured $secured_gatekeepers $app.harness.uri_role_mapping }} @@ -40,7 +39,7 @@ {{- end }} {{- end }} {{- end }} - - path: {{ $routePattern }} + - path: {{ default .Values.ingress.route_pattern $app.harness.route_pattern }} pathType: ImplementationSpecific backend: service: @@ -53,7 +52,7 @@ {{ $domain := .root.Values.domain }} {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }} {{ $app := get .root.Values.apps .service_name}} - {{- $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} + {{ $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} - path: /proxy/{{ $app.harness.service.name }}{{ $routePattern }} pathType: ImplementationSpecific backend: From af4a92e5ea22828b28e5fe9843482222a1613e49 Mon Sep 17 00:00:00 2001 From: Ludal Date: Sun, 1 Mar 2026 13:41:43 +0100 Subject: [PATCH 7/9] Fix nil pointer --- deployment-configuration/helm/templates/ingress.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index baa3db5a..4f7206ce 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -39,7 +39,7 @@ {{- end }} {{- end }} {{- end }} - - path: {{ default .Values.ingress.route_pattern $app.harness.route_pattern }} + - path: {{ default .root.Values.ingress.route_pattern $app.harness.route_pattern }} pathType: ImplementationSpecific backend: service: @@ -52,7 +52,7 @@ {{ $domain := .root.Values.domain }} {{ $secured_gatekeepers := and .root.Values.secured_gatekeepers }} {{ $app := get .root.Values.apps .service_name}} - {{ $routePattern := default .Values.ingress.route_pattern $app.harness.route_pattern }} + {{ $routePattern := default .root.Values.ingress.route_pattern $app.harness.route_pattern }} - path: /proxy/{{ $app.harness.service.name }}{{ $routePattern }} pathType: ImplementationSpecific backend: From 0ae1782f7884122f0682734cd526cc4ac62f966b Mon Sep 17 00:00:00 2001 From: Ludal Date: Sun, 1 Mar 2026 15:24:13 +0100 Subject: [PATCH 8/9] Add router path matcher Traefik annotation --- deployment-configuration/helm/templates/ingress.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index 4f7206ce..ea001f7a 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -87,6 +87,7 @@ metadata: nginx.ingress.kubernetes.io/proxy-read-timeout: {{ .Values.proxy.timeout.read | quote }} nginx.ingress.kubernetes.io/proxy-send-timeout: {{ .Values.proxy.timeout.send | quote }} nginx.ingress.kubernetes.io/use-forwarded-headers: {{ .Values.proxy.forwardedHeaders | quote }} + traefik.ingress.kubernetes.io/router.pathmatcher: "PathRegexp" spec: ingressClassName: nginx rules: From 382e4c3326a605984d650552600e4866daff812d Mon Sep 17 00:00:00 2001 From: Ludal Date: Mon, 9 Mar 2026 09:23:56 +0100 Subject: [PATCH 9/9] feat: define annotations based on ingress class --- .../helm/templates/certs/letsencrypt.yaml | 2 +- .../helm/templates/ingress.yaml | 11 ++++-- .../helm/templates/traefik-middlewares.yaml | 35 +++++++++++++++++++ deployment-configuration/helm/values.yaml | 4 +++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 deployment-configuration/helm/templates/traefik-middlewares.yaml diff --git a/deployment-configuration/helm/templates/certs/letsencrypt.yaml b/deployment-configuration/helm/templates/certs/letsencrypt.yaml index be45ac34..7135e79c 100644 --- a/deployment-configuration/helm/templates/certs/letsencrypt.yaml +++ b/deployment-configuration/helm/templates/certs/letsencrypt.yaml @@ -12,5 +12,5 @@ spec: solvers: - http01: ingress: - class: nginx + class: {{ .Values.ingress.ingressClass }} {{ end }} diff --git a/deployment-configuration/helm/templates/ingress.yaml b/deployment-configuration/helm/templates/ingress.yaml index ea001f7a..b48309a4 100644 --- a/deployment-configuration/helm/templates/ingress.yaml +++ b/deployment-configuration/helm/templates/ingress.yaml @@ -70,11 +70,12 @@ kind: Ingress metadata: name: {{ .Values.ingress.name | quote }} annotations: - kubernetes.io/ingress.class: nginx # Deprecated by Kubernetes, however still required for GKE + kubernetes.io/ingress.class: {{ .Values.ingress.ingressClass }} # Deprecated by Kubernetes, however still required for GKE {{- if and (not .Values.local) $tls }} kubernetes.io/tls-acme: 'true' cert-manager.io/issuer: {{ printf "%s-%s" "letsencrypt" .Values.namespace }} {{- end }} + {{- if eq .Values.ingress.ingressClass "nginx" }} nginx.ingress.kubernetes.io/ssl-redirect: {{ (and $tls .Values.ingress.ssl_redirect) | quote }} nginx.ingress.kubernetes.io/proxy-body-size: '{{ .Values.proxy.payload.max }}m' nginx.ingress.kubernetes.io/proxy-buffer-size: '128k' @@ -87,9 +88,15 @@ metadata: nginx.ingress.kubernetes.io/proxy-read-timeout: {{ .Values.proxy.timeout.read | quote }} nginx.ingress.kubernetes.io/proxy-send-timeout: {{ .Values.proxy.timeout.send | quote }} nginx.ingress.kubernetes.io/use-forwarded-headers: {{ .Values.proxy.forwardedHeaders | quote }} + {{- else if eq .Values.ingress.ingressClass "traefik" }} traefik.ingress.kubernetes.io/router.pathmatcher: "PathRegexp" + traefik.ingress.kubernetes.io/router.middlewares: {{ printf "%s-ch-rewrite-target@kubernetescrd,%s-ch-body-size@kubernetescrd" .Values.namespace .Values.namespace }}{{ if and $tls .Values.ingress.ssl_redirect }},{{ printf "%s-ch-ssl-redirect@kubernetescrd" .Values.namespace }}{{ end }} + {{- end }} + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: - ingressClassName: nginx + ingressClassName: {{ .Values.ingress.ingressClass }} rules: {{- range $app := .Values.apps }} {{- if (and $mainapp (and $app.harness.name (eq $app.harness.name $mainapp))) }} diff --git a/deployment-configuration/helm/templates/traefik-middlewares.yaml b/deployment-configuration/helm/templates/traefik-middlewares.yaml new file mode 100644 index 00000000..42b600e2 --- /dev/null +++ b/deployment-configuration/helm/templates/traefik-middlewares.yaml @@ -0,0 +1,35 @@ +{{- if and .Values.ingress.enabled (eq .Values.ingress.ingressClass "traefik") }} +{{ $tls := not (not .Values.tls) }} +# Rewrite target: equivalent of nginx.ingress.kubernetes.io/rewrite-target: /$1 +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: ch-rewrite-target +spec: + replacePathRegex: + regex: "^/[^/]+(.*)" + replacement: "/$1" +--- +# Body size / buffering: equivalent of nginx proxy-body-size, proxy-buffer-size +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: ch-body-size +spec: + buffering: + maxRequestBodyBytes: {{ mul .Values.proxy.payload.max 1048576 }} + memRequestBodyBytes: 131072 + memResponseBodyBytes: 131072 +{{- if and $tls .Values.ingress.ssl_redirect }} +--- +# SSL redirect: equivalent of nginx.ingress.kubernetes.io/ssl-redirect +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: ch-ssl-redirect +spec: + redirectScheme: + scheme: https + permanent: true +{{- end }} +{{- end }} diff --git a/deployment-configuration/helm/values.yaml b/deployment-configuration/helm/values.yaml index 8468b96a..c92544f8 100644 --- a/deployment-configuration/helm/values.yaml +++ b/deployment-configuration/helm/values.yaml @@ -35,6 +35,10 @@ ingress: enabled: true # -- K8s Name of ingress. name: cloudharness-ingress + # -- The ingress class to use (e.g. "nginx", "traefik"). + ingressClass: nginx + # -- Additional custom annotations to add to the Ingress resource. + annotations: {} # -- Enables/disables SSL redirect. ssl_redirect: true letsencrypt: