docs: add plan for sanitizing listener names
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# Execution: Sanitize listener names derived from certificate DNS names
|
||||
|
||||
Plan: `docs/plans/2026-10-08-2046-listener-name-sanitize.md`
|
||||
|
||||
- [x] Step 0 — Save and commit the plan
|
||||
- [ ] Step 1 — Regression tests first
|
||||
- [ ] Step 2 — Fix
|
||||
- [ ] Step 3 — Docs
|
||||
- [ ] Step 4 — Ship
|
||||
@@ -0,0 +1,111 @@
|
||||
# Plan: Sanitize listener names derived from certificate DNS names
|
||||
|
||||
**Created:** 2026-10-08 20:46 CEST
|
||||
|
||||
## Context
|
||||
|
||||
The operator in the home-lab cluster fails every reconcile of
|
||||
`kube-system/wildcard-home-hrajfrisbee`:
|
||||
|
||||
```
|
||||
spec.listeners[4].name: Invalid value: "auto-wildcard-home-hrajfrisbee-*-home-hrajfrisbee-cz":
|
||||
should match '^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$'
|
||||
```
|
||||
|
||||
`listenerNameFor` (`internal/gateway/patch.go:137`) only replaces dots in the DNS
|
||||
name, so `*.home.hrajfrisbee.cz` puts a `*` into the listener name. Gateway API
|
||||
listener names are `SectionName`: lowercase alphanumerics, `-` and `.`, each
|
||||
dot-separated label starting and ending alphanumeric, max 253 chars. Because the
|
||||
patch replaces the whole listeners array, this one name blocks every other
|
||||
certificate on `cilium-gateway` too.
|
||||
|
||||
Outcome: any DNS name cert-manager accepts yields a valid listener name, and names
|
||||
that are valid today do not change (no listener churn on existing Gateways).
|
||||
|
||||
Lands on `feat/house-conventions` (decided), in the same MR as the conventions port.
|
||||
|
||||
## Design
|
||||
|
||||
Only the DNS-name part is rewritten; the listener `Hostname` keeps the original
|
||||
value (`*.home.hrajfrisbee.cz` is a valid Gateway hostname).
|
||||
|
||||
`listenerNameFor(prefix, certName, dnsName)` in `internal/gateway/patch.go`:
|
||||
|
||||
1. Sanitize the DNS name with a new unexported `sanitizeDNSName`:
|
||||
- lowercase;
|
||||
- a leading `*` label becomes `wildcard` (`*.example.com` → `wildcard-example-com`);
|
||||
- `.` becomes `-` (as today);
|
||||
- any other character outside `[a-z0-9-]` becomes `-`;
|
||||
- trim leading and trailing `-`.
|
||||
2. Name is `prefix + certName + "-" + sanitized`, as today.
|
||||
3. If longer than 253: cut to 244, trim trailing `-` and `.`, append `-` plus the
|
||||
first 8 hex chars of the SHA-256 of the untruncated name. This replaces the
|
||||
current blind `name[:253]`, which can end in `-` (invalid) and makes long names
|
||||
collide.
|
||||
|
||||
Result for the failing cert:
|
||||
`auto-wildcard-home-hrajfrisbee-wildcard-home-hrajfrisbee-cz`.
|
||||
|
||||
Not changed here (stay on the backlog): collisions between distinct inputs that
|
||||
sanitize to the same name (e.g. `*.x.com` and `wildcard.x.com` in one cert, or the
|
||||
same cert name in two namespaces), uppercase in the listener `Hostname`, and the
|
||||
other items in `docs/reviews/`.
|
||||
|
||||
## Steps
|
||||
|
||||
### Step 0 — Save and commit the plan
|
||||
|
||||
Copy to `docs/plans/2026-10-08-2046-listener-name-sanitize.md`, create the paired
|
||||
execution log, commit alone.
|
||||
|
||||
### Step 1 — Regression tests first
|
||||
|
||||
In `internal/gateway/patch_test.go`, extend `TestListenerNameFor_sanitizesDots`
|
||||
(rename to `TestListenerNameFor_validSectionName`) with cases, each asserting the
|
||||
exact name and that it matches the `SectionName` pattern and length:
|
||||
|
||||
- `*.home.hrajfrisbee.cz` with cert `wildcard-home-hrajfrisbee` (the production case);
|
||||
- uppercase DNS name;
|
||||
- a character outside the allowed set;
|
||||
- a name over 253 chars: result is ≤ 253, valid, ends with the hash suffix, and two
|
||||
long inputs sharing a 253-char prefix produce different names;
|
||||
- existing plain names unchanged (already in the table).
|
||||
|
||||
Add a wildcard case to `TestBuildListenersFromCertificates_names` and assert in
|
||||
`_listenerFields` style that the hostname stays `*.example.com`. Run and confirm the
|
||||
new cases fail before the fix.
|
||||
|
||||
### Step 2 — Fix
|
||||
|
||||
Implement the design in `internal/gateway/patch.go` (stdlib only: `strings`,
|
||||
`crypto/sha256`, `encoding/hex`). Update the function comment.
|
||||
|
||||
### Step 3 — Docs
|
||||
|
||||
- `CLAUDE.md`: Gotchas — drop the wildcard half of "a single bad listener blocks the
|
||||
whole Gateway" (collisions remain); Architecture — describe the name as sanitized.
|
||||
- `docs/flows.md` §7 and §10 item 7: wildcard and truncation rows updated.
|
||||
- `docs/reviews/…-house-conventions.md` is not touched (it predates this).
|
||||
|
||||
### Step 4 — Ship
|
||||
|
||||
`make check` and `go test -race ./...`, then `/ship` (pushes
|
||||
`feat/house-conventions`) and open the MR with `tea pr create`. Tick Step 7 of the
|
||||
conventions execution log in the same commit.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
go test -race -run 'TestListenerNameFor|TestBuildListeners' -v ./internal/gateway/
|
||||
make check
|
||||
```
|
||||
|
||||
Live, after you merge the MR:
|
||||
|
||||
1. `/release` → tag `v0.1.0`; CI builds and moves `:latest`.
|
||||
2. `kubectl -n gateway-cert-operator-system rollout restart deploy/gateway-cert-operator`
|
||||
(the Deployment pins `:latest`, so it does not roll on its own).
|
||||
3. The "Reconciler error" for `wildcard-home-hrajfrisbee` stops, and
|
||||
`kubectl -n kube-system get gateway cilium-gateway -o jsonpath='{.spec.listeners[*].name}'`
|
||||
lists `auto-wildcard-home-hrajfrisbee-wildcard-home-hrajfrisbee-cz`.
|
||||
4. Then the CHANGELOG entries for both the conventions port and this fix.
|
||||
Reference in New Issue
Block a user