revert(egress-proxy): drop wildcard host support entirely
The apex-vs-subdomain question, the cert/SNI mismatch when pipelock-passthrough hosts have wildcard certs, and the mirror-divergence corner cases stacked up faster than the feature earned its keep. Going back to exact-host match only. Addon (`match_route`): single pass, case-insensitive exact match. `*.foo.com` in a route table is now a literal string that won't match anything — operators that want subdomains declare them individually. Pipelock mirror (`_pipelock_safe_hosts`): silently drops hosts that don't fit pipelock's `[A-Za-z0-9_.-]+` charset (wildcards, IPv6 literals, stray chars). Previously normalised wildcards to their suffix; now just drops them, which matches egress-proxy's behavior of not matching them either. 8 wildcard test cases removed; 2 lightweight "wildcards are not supported" assertions retained as documentation. 386 unit pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -147,67 +147,13 @@ class TestMatchRoute(unittest.TestCase):
|
||||
# other-host shouldn't be matched via a "ends with" check.
|
||||
self.assertIsNone(match_route(self.ROUTES, "evil.api.github.com"))
|
||||
|
||||
|
||||
class TestMatchRouteWildcards(unittest.TestCase):
|
||||
"""Wildcard host patterns: `*.foo.com` matches any host that
|
||||
ends with `.foo.com` (subdomains, one level or more)."""
|
||||
|
||||
def test_wildcard_matches_direct_subdomain(self):
|
||||
def test_wildcard_hosts_not_supported(self):
|
||||
# `*.example.com` is treated as a literal host string by
|
||||
# the exact-only matcher. Removed from the design after
|
||||
# the apex/RFC-6125/pipelock-mirror edge cases stacked up.
|
||||
routes = (Route(host="*.example.com"),)
|
||||
r = match_route(routes, "foo.example.com")
|
||||
self.assertIsNotNone(r)
|
||||
self.assertEqual("*.example.com", r.host)
|
||||
|
||||
def test_wildcard_matches_nested_subdomain(self):
|
||||
routes = (Route(host="*.example.com"),)
|
||||
self.assertIsNotNone(match_route(routes, "a.b.example.com"))
|
||||
|
||||
def test_wildcard_matches_apex(self):
|
||||
# Allowlist semantics: `*.example.com` covers
|
||||
# `example.com` itself + every subdomain. Matches what
|
||||
# the pipelock mirror does (strips `*.example.com` →
|
||||
# `example.com`) so the two layers agree.
|
||||
routes = (Route(host="*.example.com"),)
|
||||
self.assertIsNotNone(match_route(routes, "example.com"))
|
||||
|
||||
def test_wildcard_does_not_match_overlapping_suffix(self):
|
||||
# `*.example.com` shouldn't match `barexample.com` — the
|
||||
# match requires `.` before the suffix.
|
||||
routes = (Route(host="*.example.com"),)
|
||||
self.assertIsNone(match_route(routes, "barexample.com"))
|
||||
|
||||
def test_wildcard_case_insensitive(self):
|
||||
routes = (Route(host="*.example.com"),)
|
||||
self.assertIsNotNone(match_route(routes, "FOO.Example.COM"))
|
||||
|
||||
def test_exact_match_wins_over_wildcard(self):
|
||||
# A specific route declared alongside a broader wildcard
|
||||
# should take precedence — operators stack a per-host
|
||||
# config on top of a permissive wildcard this way.
|
||||
routes = (
|
||||
Route(host="*.github.com"),
|
||||
Route(host="api.github.com", auth_scheme="Bearer",
|
||||
token_env="EGRESS_PROXY_TOKEN_0"),
|
||||
)
|
||||
r = match_route(routes, "api.github.com")
|
||||
self.assertIsNotNone(r)
|
||||
self.assertEqual("api.github.com", r.host)
|
||||
self.assertEqual("Bearer", r.auth_scheme)
|
||||
|
||||
def test_exact_wins_regardless_of_route_order(self):
|
||||
# Same as above but with wildcard declared AFTER exact —
|
||||
# exact wins because pass 1 finds it before pass 2 runs.
|
||||
routes = (
|
||||
Route(host="api.github.com", auth_scheme="Bearer",
|
||||
token_env="EGRESS_PROXY_TOKEN_0"),
|
||||
Route(host="*.github.com"),
|
||||
)
|
||||
r = match_route(routes, "api.github.com")
|
||||
self.assertEqual("api.github.com", r.host)
|
||||
|
||||
def test_no_match_falls_through(self):
|
||||
routes = (Route(host="*.example.com"),)
|
||||
self.assertIsNone(match_route(routes, "elsewhere.org"))
|
||||
self.assertIsNone(match_route(routes, "foo.example.com"))
|
||||
self.assertIsNone(match_route(routes, "example.com"))
|
||||
|
||||
|
||||
# --- decide --------------------------------------------------------------
|
||||
|
||||
@@ -197,45 +197,30 @@ class TestPipelockSafeHosts(unittest.TestCase):
|
||||
_pipelock_safe_hosts(["api.github.com", "registry.npmjs.org"]),
|
||||
)
|
||||
|
||||
def test_strips_wildcard_prefix(self):
|
||||
# `*.example.com` becomes `example.com` — pipelock pins the
|
||||
# suffix, egress-proxy keeps the wildcard on its side.
|
||||
def test_drops_wildcards(self):
|
||||
# Wildcard host matching was removed from egress-proxy too,
|
||||
# so a `*.foo.com` route is dead weight anyway; we drop it
|
||||
# entirely from the pipelock mirror so the apply doesn't
|
||||
# fail parse.
|
||||
self.assertEqual(
|
||||
["example.com", "api.github.com"],
|
||||
["api.github.com"],
|
||||
_pipelock_safe_hosts(["*.example.com", "api.github.com"]),
|
||||
)
|
||||
|
||||
def test_wildcard_strips_one_label_not_recursive(self):
|
||||
# `*.foo.bar.com` → `foo.bar.com` (one strip of `*.`).
|
||||
self.assertEqual(
|
||||
["foo.bar.com"],
|
||||
_pipelock_safe_hosts(["*.foo.bar.com"]),
|
||||
)
|
||||
|
||||
def test_drops_bare_wildcard(self):
|
||||
# `*` alone would normalise to empty; nothing useful to send
|
||||
# to pipelock.
|
||||
self.assertEqual([], _pipelock_safe_hosts(["*"]))
|
||||
|
||||
def test_strips_ipv6_literals(self):
|
||||
# Brackets aren't in pipelock's allowed charset either.
|
||||
def test_drops_ipv6_literals(self):
|
||||
self.assertEqual(
|
||||
["api.example.com"],
|
||||
_pipelock_safe_hosts(["[::1]", "api.example.com"]),
|
||||
)
|
||||
|
||||
def test_dedupes_after_normalisation(self):
|
||||
# `*.example.com` + `example.com` both yield `example.com`.
|
||||
self.assertEqual(
|
||||
["example.com"],
|
||||
_pipelock_safe_hosts(["*.example.com", "example.com"]),
|
||||
)
|
||||
|
||||
def test_preserves_order(self):
|
||||
self.assertEqual(
|
||||
["a.example", "b.example", "c.example"],
|
||||
_pipelock_safe_hosts([
|
||||
"a.example", "weird host", "b.example", "*", "c.example",
|
||||
"a.example", "*.junk", "b.example", "weird host", "c.example",
|
||||
]),
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user