134 lines
4.6 KiB
Go
134 lines
4.6 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"infinite-canvas/backend/internal/model"
|
|
)
|
|
|
|
func TestDesktopLocalChannelModeRejectsPublicAcrossProductionDispatch(t *testing.T) {
|
|
open := &Service{runtimeCapabilities: RuntimeCapabilities{desktopLocalChannels: true}}
|
|
requested := true
|
|
const publicBaseURL = "https://8.8.8.8"
|
|
|
|
if _, err := open.channelFromRequest(ChannelRequest{Name: "Public", BaseURL: publicBaseURL, AllowLocalChannel: &requested}, model.ModelChannel{Scope: model.ChannelScopeSystem}); err == nil {
|
|
t.Fatal("saving allowLocalChannel=true with a public Base URL must fail")
|
|
}
|
|
if _, err := ValidateCustomRelayChannelURL(publicBaseURL+"/v1/models", publicBaseURL, true, true); err == nil {
|
|
t.Fatal("custom relay allowLocalChannel=true must not fall back to the public relay policy")
|
|
}
|
|
if _, err := open.resolveProviderConfig(providerConfig{BaseURL: publicBaseURL, AllowLocalChannel: true}); err == nil {
|
|
t.Fatal("generation provider allowLocalChannel=true must reject a public Base URL before dispatch")
|
|
}
|
|
}
|
|
|
|
func TestDesktopLocalChannelModeOwnsOutboundPolicy(t *testing.T) {
|
|
t.Setenv("CANVAS_ALLOW_PRIVATE_UPSTREAMS", "true")
|
|
t.Setenv("CANVAS_ALLOWED_PRIVATE_UPSTREAM_HOSTS", "127.0.0.1,localhost,192.168.1.20,169.254.169.254")
|
|
open := &Service{runtimeCapabilities: RuntimeCapabilities{desktopLocalChannels: true}}
|
|
closed := &Service{}
|
|
|
|
for _, rawURL := range []string{
|
|
"https://8.8.8.8/v1/models",
|
|
"http://192.168.1.20:8000/v1/models",
|
|
"http://169.254.169.254/latest/meta-data",
|
|
"http://127.0.0.2:8000/v1/models",
|
|
"http://localhost.:8000/v1/models",
|
|
"http://[::1]:8000/v1/models",
|
|
} {
|
|
if _, err := open.validateChannelOutboundURL(rawURL, true, false); err == nil {
|
|
t.Fatalf("allowLocalChannel=true must reject non-exact-loopback URL %q", rawURL)
|
|
}
|
|
}
|
|
|
|
for _, rawURL := range []string{
|
|
"http://127.0.0.1:8000/v1/models",
|
|
"http://localhost:8000/v1/models",
|
|
} {
|
|
for _, customRelay := range []bool{false, true} {
|
|
_, err := open.validateChannelOutboundURL(rawURL, false, customRelay)
|
|
if err == nil || !strings.Contains(err.Error(), "不允许访问本机、内网或链路本地地址") {
|
|
t.Fatalf("allowLocalChannel=false must reject exact loopback %q with canonical error, customRelay=%v: %v", rawURL, customRelay, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, customRelay := range []bool{false, true} {
|
|
if _, err := open.validateChannelOutboundURL("https://8.8.8.8/v1/models", false, customRelay); err != nil {
|
|
t.Fatalf("ordinary public channel must keep the existing outbound policy, customRelay=%v: %v", customRelay, err)
|
|
}
|
|
}
|
|
|
|
for _, rawURL := range []string{
|
|
"http://127.0.0.1:8000/v1/models",
|
|
"https://8.8.8.8/v1/models",
|
|
} {
|
|
if _, err := closed.validateChannelOutboundURL(rawURL, true, false); err == nil {
|
|
t.Fatalf("server capability=false must reject requested local mode for %q", rawURL)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGoURLParserDesktopLoopbackPortBoundary(t *testing.T) {
|
|
tests := []struct {
|
|
rawURL string
|
|
wantErr bool
|
|
wantHost string
|
|
wantPort string
|
|
}{
|
|
{rawURL: "http://localhost:", wantHost: "localhost", wantPort: ""},
|
|
{rawURL: "http://localhost:0", wantHost: "localhost", wantPort: "0"},
|
|
{rawURL: "http://localhost:65536", wantHost: "localhost", wantPort: "65536"},
|
|
{rawURL: "http://localhost:abc", wantErr: true},
|
|
}
|
|
for _, test := range tests {
|
|
parsed, err := url.Parse(test.rawURL)
|
|
if test.wantErr {
|
|
if err == nil {
|
|
t.Fatalf("url.Parse(%q) error=nil, want parser error", test.rawURL)
|
|
}
|
|
continue
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("url.Parse(%q) error=%v", test.rawURL, err)
|
|
}
|
|
if parsed.Hostname() != test.wantHost || parsed.Port() != test.wantPort {
|
|
t.Fatalf("url.Parse(%q) hostname=%q port=%q", test.rawURL, parsed.Hostname(), parsed.Port())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDesktopLoopbackPolicyValidatesPortSyntaxAndRange(t *testing.T) {
|
|
policy := desktopLoopbackOutboundPolicy(func(context.Context, string) ([]net.IP, error) {
|
|
return []net.IP{net.ParseIP("127.0.0.1")}, nil
|
|
})
|
|
|
|
for _, rawURL := range []string{
|
|
"http://localhost",
|
|
"http://localhost:1/v1/models",
|
|
"http://127.0.0.1:65535/v1/models",
|
|
} {
|
|
if _, err := validateOutboundURLWithPolicy(rawURL, policy); err != nil {
|
|
t.Fatalf("strict local URL %q must be accepted: %v", rawURL, err)
|
|
}
|
|
}
|
|
|
|
for _, rawURL := range []string{
|
|
"http://localhost:/v1/models",
|
|
"http://localhost:0/v1/models",
|
|
"http://localhost:65536/v1/models",
|
|
"http://localhost:abc/v1/models",
|
|
"http://localhost:+1/v1/models",
|
|
"http://localhost:-1/v1/models",
|
|
"http://localhost:0x50/v1/models",
|
|
} {
|
|
if _, err := validateOutboundURLWithPolicy(rawURL, policy); err == nil {
|
|
t.Fatalf("strict local URL %q must reject invalid port syntax/range", rawURL)
|
|
}
|
|
}
|
|
}
|