feat: add Gateway API support (#1073)

Add full Gateway API support for exposing Gitea via HTTPRoute, TCPRoute, BackendTLSPolicy, and ClientSettingsPolicy resources.

New templates:
- `httpRoute.yaml` — renders an HTTPRoute with configurable
  parentRefs, hostnames, and rules (defaults to PathPrefix `/`)
- `tcpRoute.yaml` — renders a TCPRoute for SSH traffic
- `backendTLSPolicy.yaml` — renders a BackendTLSPolicy for
  encrypted backend connections with required validation config
- `clientSettingsPolicy.yaml` — renders an NGINX Gateway Fabric
  ClientSettingsPolicy to raise the request body size limit

Infrastructure:
- `gatewayAPI.enabled` global toggle gates all resources
- Resources grouped under `gatewayAPI.core.*` and `gatewayAPI.nginx.*`
- Helper templates extracted into dedicated `_*.tpl` files
- Service name helpers (`gitea.service.http.name`, `gitea.service.ssh.name`)
  extracted into `_services.tpl`; service templates renamed to camelCase
- `ROOT_URL`, `DOMAIN`, and `SSH_DOMAIN` auto-resolve from
  `httpRoute.hostnames[0]`; `httpRoute.tls` switches to `https`

Documentation:
- New `docs/gateway-api.md` with topology examples, BackendTLSPolicy
  setup, sectionName guidance, SSH considerations, and NGINX body
  size limit configuration
- `.github/copilot-instructions.md` with project conventions
- README parameter table auto-generated via `make readme`

Tests:
- Helm unit tests for all four new resource templates
- Config tests for hostname/TLS resolution from Gateway API values

Co-authored-by: Todd Marimon <toddmarimon@gmail.com>
This commit is contained in:
Todd Marimon
2026-07-19 16:25:28 +00:00
committed by Markus Pesch
parent 5005037dbf
commit 7747a001f7
25 changed files with 1200 additions and 40 deletions
@@ -103,3 +103,56 @@ tests:
matchRegex:
path: stringData.server
pattern: \nROOT_URL=https://route.example.com
################################################
- it: "[HTTPRoute enabled] uses first hostname for DOMAIN|SSH_DOMAIN|ROOT_URL"
template: templates/gitea/config.yaml
set:
ingress:
hosts: []
gatewayAPI:
enabled: true
core:
httpRoute:
enabled: true
hostnames:
- gw.example.com
parentRefs:
- name: shared-gateway
asserts:
- documentIndex: 0
matchRegex:
path: stringData.server
pattern: \nDOMAIN=gw.example.com
- documentIndex: 0
matchRegex:
path: stringData.server
pattern: \nSSH_DOMAIN=gw.example.com
- documentIndex: 0
matchRegex:
path: stringData.server
pattern: \nROOT_URL=http://gw.example.com
################################################
- it: "[HTTPRoute tls] switches ROOT_URL to https"
template: templates/gitea/config.yaml
set:
ingress:
hosts: []
gatewayAPI:
enabled: true
core:
httpRoute:
enabled: true
tls: true
hostnames:
- gw.example.com
parentRefs:
- name: shared-gateway
asserts:
- documentIndex: 0
matchRegex:
path: stringData.server
pattern: \nROOT_URL=https://gw.example.com
@@ -1,13 +1,13 @@
suite: ssh-svc / http-svc template (Services configuration)
suite: sshService / httpService template (Services configuration)
release:
name: gitea-unittests
namespace: testing
templates:
- templates/gitea/ssh-svc.yaml
- templates/gitea/http-svc.yaml
- templates/gitea/sshService.yaml
- templates/gitea/httpService.yaml
tests:
- it: supports adding custom labels to ssh-svc
template: templates/gitea/ssh-svc.yaml
- it: supports adding custom labels to sshService
template: templates/gitea/sshService.yaml
set:
service:
ssh:
@@ -19,7 +19,7 @@ tests:
value: "testvalue"
- it: keeps existing labels (ssh)
template: templates/gitea/ssh-svc.yaml
template: templates/gitea/sshService.yaml
set:
service:
ssh:
@@ -28,8 +28,8 @@ tests:
- exists:
path: metadata.labels["app"]
- it: supports adding custom labels to http-svc
template: templates/gitea/http-svc.yaml
- it: supports adding custom labels to httpService
template: templates/gitea/httpService.yaml
set:
service:
http:
@@ -41,7 +41,7 @@ tests:
value: "testvalue"
- it: keeps existing labels (http)
template: templates/gitea/http-svc.yaml
template: templates/gitea/httpService.yaml
set:
service:
http:
@@ -51,7 +51,7 @@ tests:
path: metadata.labels["app"]
- it: render service.ssh.loadBalancerClass if set and type is LoadBalancer
template: templates/gitea/ssh-svc.yaml
template: templates/gitea/sshService.yaml
set:
service:
ssh:
@@ -73,7 +73,7 @@ tests:
value: ["1.2.3.4/32", "5.6.7.8/32"]
- it: does not render when loadbalancer properties are set but type is not loadBalancerClass
template: templates/gitea/http-svc.yaml
template: templates/gitea/httpService.yaml
set:
service:
http:
@@ -92,7 +92,7 @@ tests:
path: spec.loadBalancerSourceRanges
- it: does not render loadBalancerClass by default even when type is LoadBalancer
template: templates/gitea/http-svc.yaml
template: templates/gitea/httpService.yaml
set:
service:
http:
@@ -107,8 +107,8 @@ tests:
- it: both ssh and http services exist
templates:
- templates/gitea/ssh-svc.yaml
- templates/gitea/http-svc.yaml
- templates/gitea/sshService.yaml
- templates/gitea/httpService.yaml
asserts:
- matchRegex:
path: metadata.name
@@ -0,0 +1,89 @@
suite: Test Gateway API backendTLSPolicy.yaml
release:
name: gitea-unittests
namespace: testing
templates:
- templates/gitea/backendTLSPolicy.yaml
tests:
- it: should not render when gatewayAPI.enabled is false
set:
gatewayAPI:
enabled: false
core:
backendTLSPolicy:
enabled: true
validation:
hostname: git.internal
caCertificateRefs:
- name: gitea-ca
group: ""
kind: ConfigMap
asserts:
- hasDocuments:
count: 0
- it: should not render when backendTLSPolicy.enabled is false
set:
gatewayAPI:
enabled: true
gatewayAPI.core.backendTLSPolicy.enabled: false
asserts:
- hasDocuments:
count: 0
- it: should render a BackendTLSPolicy targeting the http Service by default
set:
gatewayAPI:
enabled: true
core:
backendTLSPolicy:
enabled: true
validation:
hostname: git.internal
caCertificateRefs:
- name: gitea-ca
group: ""
kind: ConfigMap
asserts:
- hasDocuments:
count: 1
- isKind:
of: BackendTLSPolicy
- equal:
path: apiVersion
value: gateway.networking.k8s.io/v1
- equal:
path: metadata.name
value: gitea-unittests
- equal:
path: spec.targetRefs[0].name
value: gitea-unittests-http
- equal:
path: spec.targetRefs[0].kind
value: Service
- equal:
path: spec.validation.hostname
value: git.internal
- it: should fail when validation is missing
set:
gatewayAPI:
enabled: true
core:
backendTLSPolicy:
enabled: true
asserts:
- failedTemplate:
errorMessage: gatewayAPI.core.backendTLSPolicy.validation is required
- it: should fail when validation is an empty dict
set:
gatewayAPI:
enabled: true
core:
backendTLSPolicy:
enabled: true
validation: {}
asserts:
- failedTemplate:
errorMessage: gatewayAPI.core.backendTLSPolicy.validation is required
@@ -0,0 +1,105 @@
suite: Test Gateway API clientSettingsPolicy.yaml
release:
name: gitea-unittests
namespace: testing
templates:
- templates/gitea/clientSettingsPolicy.yaml
tests:
- it: should not render when gatewayAPI.enabled is false
set:
gatewayAPI:
enabled: false
nginx:
clientSettingsPolicies:
enabled: true
body:
maxSize: 100m
asserts:
- hasDocuments:
count: 0
- it: should not render when clientSettingsPolicies.enabled is false
set:
gatewayAPI:
enabled: true
gatewayAPI.nginx.clientSettingsPolicies.enabled: false
asserts:
- hasDocuments:
count: 0
- it: should render a ClientSettingsPolicy targeting the HTTPRoute by default
set:
gatewayAPI:
enabled: true
nginx:
clientSettingsPolicies:
enabled: true
body:
maxSize: 100m
asserts:
- hasDocuments:
count: 1
- isKind:
of: ClientSettingsPolicy
- equal:
path: apiVersion
value: gateway.nginx.org/v1alpha1
- equal:
path: metadata.name
value: gitea-unittests
- equal:
path: spec.targetRef.group
value: gateway.networking.k8s.io
- equal:
path: spec.targetRef.kind
value: HTTPRoute
- equal:
path: spec.targetRef.name
value: gitea-unittests
- equal:
path: spec.body.maxSize
value: 100m
- it: should honor a custom targetRef
set:
gatewayAPI:
enabled: true
nginx:
clientSettingsPolicies:
enabled: true
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: shared-gateway
body:
maxSize: 100m
asserts:
- equal:
path: spec.targetRef.kind
value: Gateway
- equal:
path: spec.targetRef.name
value: shared-gateway
- it: should fail when body is missing
set:
gatewayAPI:
enabled: true
nginx:
clientSettingsPolicies:
enabled: true
asserts:
- failedTemplate:
errorMessage: gatewayAPI.nginx.clientSettingsPolicies.body is required
- it: should fail when body is an empty dict
set:
gatewayAPI:
enabled: true
nginx:
clientSettingsPolicies:
enabled: true
body: {}
asserts:
- failedTemplate:
errorMessage: gatewayAPI.nginx.clientSettingsPolicies.body is required
+117
View File
@@ -0,0 +1,117 @@
suite: Test Gateway API httpRoute.yaml
release:
name: gitea-unittests
namespace: testing
templates:
- templates/gitea/httpRoute.yaml
tests:
- it: should not render when gatewayAPI.enabled is false
set:
gatewayAPI:
enabled: false
core:
httpRoute:
enabled: true
hostnames:
- git.example.com
parentRefs:
- name: shared-gateway
asserts:
- hasDocuments:
count: 0
- it: should not render when httpRoute.enabled is false
set:
gatewayAPI:
enabled: true
gatewayAPI.core.httpRoute.enabled: false
asserts:
- hasDocuments:
count: 0
- it: should render a single HTTPRoute with default rule
set:
gatewayAPI:
enabled: true
core:
httpRoute:
enabled: true
annotations:
example.io/owner: gitea
hostnames:
- git.example.com
parentRefs:
- name: shared-gateway
namespace: gateway-system
asserts:
- hasDocuments:
count: 1
- isKind:
of: HTTPRoute
- equal:
path: apiVersion
value: gateway.networking.k8s.io/v1
- equal:
path: metadata.name
value: gitea-unittests
- equal:
path: metadata.annotations["example.io/owner"]
value: gitea
- equal:
path: spec.parentRefs[0].name
value: shared-gateway
- equal:
path: spec.parentRefs[0].namespace
value: gateway-system
- equal:
path: spec.hostnames[0]
value: git.example.com
- equal:
path: spec.rules[0].matches[0].path.value
value: /
- equal:
path: spec.rules[0].backendRefs[0].group
value: ""
- equal:
path: spec.rules[0].backendRefs[0].kind
value: Service
- equal:
path: spec.rules[0].backendRefs[0].name
value: gitea-unittests-http
- equal:
path: spec.rules[0].backendRefs[0].port
value: 3000
- equal:
path: spec.rules[0].backendRefs[0].weight
value: 1
- it: should fail when parentRefs missing
set:
gatewayAPI:
enabled: true
core:
httpRoute:
enabled: true
hostnames:
- git.example.com
asserts:
- failedTemplate:
errorMessage: gatewayAPI.core.httpRoute.parentRefs is required
- it: hostname tpl rendering
set:
global:
giteaHostName: gitea.tpl.example.com
gatewayAPI:
enabled: true
core:
httpRoute:
enabled: true
hostnames:
- "{{ .Values.global.giteaHostName }}"
parentRefs:
- name: gw
asserts:
- equal:
path: spec.hostnames[0]
value: gitea.tpl.example.com
+79
View File
@@ -0,0 +1,79 @@
suite: Test Gateway API tcpRoute.yaml
release:
name: gitea-unittests
namespace: testing
templates:
- templates/gitea/tcpRoute.yaml
tests:
- it: should not render when gatewayAPI.enabled is false
set:
gatewayAPI:
enabled: false
core:
tcpRoute:
enabled: true
parentRefs:
- name: shared-gateway
asserts:
- hasDocuments:
count: 0
- it: should not render when tcpRoute.enabled is false
set:
gatewayAPI:
enabled: true
gatewayAPI.core.tcpRoute.enabled: false
asserts:
- hasDocuments:
count: 0
- it: should render a TCPRoute defaulting to the SSH service
set:
gatewayAPI:
enabled: true
core:
tcpRoute:
enabled: true
parentRefs:
- name: shared-gateway
sectionName: ssh
asserts:
- hasDocuments:
count: 1
- isKind:
of: TCPRoute
- equal:
path: apiVersion
value: gateway.networking.k8s.io/v1alpha2
- equal:
path: metadata.name
value: gitea-unittests
- equal:
path: spec.parentRefs[0].sectionName
value: ssh
- equal:
path: spec.rules[0].backendRefs[0].group
value: ""
- equal:
path: spec.rules[0].backendRefs[0].kind
value: Service
- equal:
path: spec.rules[0].backendRefs[0].name
value: gitea-unittests-ssh
- equal:
path: spec.rules[0].backendRefs[0].port
value: 22
- equal:
path: spec.rules[0].backendRefs[0].weight
value: 1
- it: should fail when parentRefs missing
set:
gatewayAPI:
enabled: true
core:
tcpRoute:
enabled: true
asserts:
- failedTemplate:
errorMessage: gatewayAPI.core.tcpRoute.parentRefs is required