Skip to content

test(e2e): reproduce #219 hostname-less listener collision#221

Open
ecv wants to merge 1 commit into
mainfrom
test/issue-219-repro-e2e
Open

test(e2e): reproduce #219 hostname-less listener collision#221
ecv wants to merge 1 commit into
mainfrom
test/issue-219-repro-e2e

Conversation

@ecv

@ecv ecv commented Jun 24, 2026

Copy link
Copy Markdown

Summary

End-to-end reproduction of #219 — a tenant Gateway whose listeners use the default ports/protocols (80/HTTP, 443/HTTPS) without a hostname is rejected at admission with the misleading upstream CEL message:

Combination of port, protocol and hostname must be unique for each listener

Root cause (per the issue): NSO's mutating webhook unconditionally injects hostname-less default-http (80/HTTP) and default-https (443/HTTPS) listeners. A tenant listener on those ports with no hostname produces a duplicate (port, protocol, hostname=∅) tuple, and the upstream CRD CEL rejects the whole object before NSO's own validating webhook can surface a clear reason.

This PR adds only the repro test — no production code changes. The fix lives in #220.

Test

test/e2e/gateway-listener-hostname-collision/chainsaw-test.yaml — pure admission-time reproduction on the control-plane (nso-standard) cluster; no downstream/edge wiring needed. Drives the failure exactly as the issue did, via kubectl apply --dry-run=server (runs the mutating webhook + CRD CEL without persisting).

Probes mirror the issue's investigation matrix:

Probe Listeners Expected
B (decisive) 1 — 80/HTTP, no hostname ❌ rejected must be unique
A 2 — 80/HTTP + 443/HTTPS, no hostname ❌ rejected must be unique
D (control) 1 — 80/HTTP, with hostname ✅ accepted

Probe B is decisive: a single tenant listener cannot collide with itself, so its rejection isolates the injected-default tuple collision as the cause. Probe D is the positive control — a distinguishing hostname is admitted.

Validation done

  • chainsaw lint (v0.2.15, the pinned version) → The document is valid.
  • Not executed against live clusters — this environment has no Docker/kind. Against unfixed code (main / this branch) all three probes pass and the bug reproduces.

Interaction with the fix (#220)

Once #220 merges, NSO's defaulting webhook rejects probes A/B first with a clear hostname-required message instead of the opaque "must be unique". The expected grep string in each probe will then need updating to the clear message — to be done as part of merging #220.

Refs

🤖 Generated with Claude Code

Add a chainsaw e2e test that reproduces issue #219: a tenant Gateway
whose listeners use 80/HTTP or 443/HTTPS without a hostname is rejected
at admission with the misleading upstream CEL message "Combination of
port, protocol and hostname must be unique for each listener".

The test is a pure admission-time reproduction on the control-plane
cluster (no downstream wiring), driving the failure exactly as the issue
did via kubectl apply --dry-run=server. Probes mirror the issue matrix:

  B (decisive) 1 listener  80/HTTP  no hostname  -> rejected
  A            2 listeners 80+443   no hostname  -> rejected
  D (control)  1 listener  80/HTTP  hostname     -> accepted

Probe B is decisive: a single listener cannot collide with itself, so
its rejection isolates the injected default-listener tuple collision as
the cause. Probe D confirms a distinguishing hostname is admitted.

Once #220 merges, NSO's defaulting webhook rejects A/B first with a clear
hostname-required message, so the expected message here will change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant