mcp connection
This commit is contained in:
134
go-api/internal/config/trustedproxies_test.go
Normal file
134
go-api/internal/config/trustedproxies_test.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package config
|
||||
|
||||
// HTTP_TRUSTED_PROXIES parsing.
|
||||
//
|
||||
// The setting decides whether a client-supplied header is believed, so the
|
||||
// tests worth having are about what happens when it is WRONG: unset, empty,
|
||||
// mistyped. Every one of those must end in "trust nothing", because the
|
||||
// alternative — trusting something the operator did not write — is the whole
|
||||
// risk this setting carries.
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTrustedProxiesUnsetTrustsNothing(t *testing.T) {
|
||||
for _, raw := range []string{"", " ", ",", " , , "} {
|
||||
got, err := parseTrustedProxies(raw)
|
||||
if err != nil {
|
||||
t.Errorf("parseTrustedProxies(%q): unexpected error %v", raw, err)
|
||||
}
|
||||
if len(got) != 0 {
|
||||
t.Errorf("parseTrustedProxies(%q) = %v, want empty — an unset value must trust nothing", raw, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrustedProxiesParsesCIDRsAndBareAddresses(t *testing.T) {
|
||||
got, err := parseTrustedProxies(" 10.0.0.0/8 , 172.17.0.1 , fd00::/8 , ::1 ")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want := []string{"10.0.0.0/8", "172.17.0.1/32", "fd00::/8", "::1/128"}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("parsed %d entries (%v), want %d", len(got), got, len(want))
|
||||
}
|
||||
for i, w := range want {
|
||||
if got[i].String() != w {
|
||||
t.Errorf("entry %d = %q, want %q", i, got[i].String(), w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A bare address must become a single-host block that contains that host and
|
||||
// nothing else — the operator wrote one proxy, not a network.
|
||||
func TestTrustedProxyBareAddressIsOneHost(t *testing.T) {
|
||||
got, err := parseTrustedProxies("172.17.0.1")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !got[0].Contains(netip.MustParseAddr("172.17.0.1")) {
|
||||
t.Error("the host itself is not in its own single-host block")
|
||||
}
|
||||
if got[0].Contains(netip.MustParseAddr("172.17.0.2")) {
|
||||
t.Error("a bare address was widened beyond one host")
|
||||
}
|
||||
}
|
||||
|
||||
// A block written with host bits set is common and easy to misread. Masking it
|
||||
// at parse time makes it mean what its author meant; unmasked, netip.Prefix
|
||||
// .Contains reports false for everything.
|
||||
func TestTrustedProxyCIDRWithHostBitsIsMasked(t *testing.T) {
|
||||
got, err := parseTrustedProxies("10.1.2.3/8")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if want := "10.0.0.0/8"; got[0].String() != want {
|
||||
t.Fatalf("got %q, want %q", got[0].String(), want)
|
||||
}
|
||||
if !got[0].Contains(netip.MustParseAddr("10.9.9.9")) {
|
||||
t.Error("the masked block does not contain an address inside it")
|
||||
}
|
||||
}
|
||||
|
||||
// An IPv4-mapped address names an IPv4 host, and must match the peer address
|
||||
// Go reports for an IPv4 connection.
|
||||
func TestTrustedProxyIPv4MappedIsUnmapped(t *testing.T) {
|
||||
got, err := parseTrustedProxies("::ffff:10.0.0.1")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !got[0].Contains(netip.MustParseAddr("10.0.0.1")) {
|
||||
t.Errorf("%q does not contain 10.0.0.1", got[0].String())
|
||||
}
|
||||
}
|
||||
|
||||
// Malformed entries stop startup. Skipping one would leave the deployment
|
||||
// trusting a shorter list than the operator wrote, and the consequence — every
|
||||
// user sharing one rate-limit bucket — is silent.
|
||||
func TestTrustedProxiesRejectMalformedEntries(t *testing.T) {
|
||||
for _, raw := range []string{
|
||||
"banana",
|
||||
"10.0.0.0/33",
|
||||
"10.0.0.0/8, banana",
|
||||
"300.1.2.3",
|
||||
"10.0.0.1:8080",
|
||||
"*",
|
||||
"https://proxy.internal",
|
||||
"fd00::/200",
|
||||
} {
|
||||
if _, err := parseTrustedProxies(raw); err == nil {
|
||||
t.Errorf("parseTrustedProxies(%q) was accepted; it must refuse and stop startup", raw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The error has to name the entry and show the shape expected, because it is
|
||||
// read by an operator at 3am with a container that will not boot.
|
||||
func TestTrustedProxiesErrorNamesTheEntry(t *testing.T) {
|
||||
_, err := parseTrustedProxies("10.0.0.0/8, banana")
|
||||
if err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
for _, want := range []string{"HTTP_TRUSTED_PROXIES", "banana"} {
|
||||
if !contains(err.Error(), want) {
|
||||
t.Errorf("error %q does not mention %q", err.Error(), want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func contains(haystack, needle string) bool {
|
||||
return len(haystack) >= len(needle) && (haystack == needle ||
|
||||
len(needle) == 0 || indexOf(haystack, needle) >= 0)
|
||||
}
|
||||
|
||||
func indexOf(haystack, needle string) int {
|
||||
for i := 0; i+len(needle) <= len(haystack); i++ {
|
||||
if haystack[i:i+len(needle)] == needle {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
Reference in New Issue
Block a user