feat(platform): 开发环境 - 新增 Docker 热更新并完善私网上游指引 (#122)
* feat(platform): 开发环境 - 新增 Docker 热更新开发配置 * docs(platform): 开发环境 - 记录 Fork 分支同步流程 * fix(platform): 开发环境 - 避让端口冲突并持久化构建缓存 * fix(platform): 模型渠道 - 改进私网上游配置指引 * docs(platform): 开发环境 - 本机升级流程仅保留在本地手册 * feat(security): 自定义渠道 - 允许白名单主机使用 HTTP 中转 --------- Co-authored-by: sqy941013 <sqy941013@users.noreply.github.com>
This commit is contained in:
1 parent
50d8c2854a
commit
5e93fa7704
10 files changed
+173
-13
No files matched your search
@@ -62,8 +62,8 @@ func ValidateOutboundURL(rawURL string) (*url.URL, error) {
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
// 用户自定义渠道必须使用更严格的出口策略:只允许 HTTPS,不接受 URL 凭据,
|
||||
// 仅部署者精确配置的主机可以路由到私网。
|
||||
// 用户自定义渠道必须使用更严格的出口策略:不接受 URL 凭据,且仅部署者精确配置的
|
||||
// 主机可以路由到私网或使用会明文传输 API Key 的 HTTP。
|
||||
func ValidateCustomRelayURL(rawURL string) (*url.URL, error) {
|
||||
if len(strings.TrimSpace(rawURL)) > 4096 {
|
||||
return nil, BadAuthRequest("自定义渠道地址过长")
|
||||
@@ -72,8 +72,12 @@ func ValidateCustomRelayURL(rawURL string) (*url.URL, error) {
|
||||
if err != nil || parsed.Hostname() == "" || !parsed.IsAbs() {
|
||||
return nil, BadAuthRequest("自定义渠道地址无效")
|
||||
}
|
||||
if parsed.Scheme != "https" {
|
||||
return nil, BadAuthRequest("自定义渠道中转只支持 HTTPS")
|
||||
scheme := strings.ToLower(parsed.Scheme)
|
||||
if scheme != "https" && scheme != "http" {
|
||||
return nil, BadAuthRequest("自定义渠道地址只支持 http/https")
|
||||
}
|
||||
if scheme == "http" && !allowedPrivateUpstreamHost(parsed.Hostname()) {
|
||||
return nil, BadAuthRequest("自定义渠道 HTTP 仅允许访问已配置的可信上游主机")
|
||||
}
|
||||
if parsed.User != nil {
|
||||
return nil, BadAuthRequest("自定义渠道地址不允许包含认证信息")
|
||||
|
||||
@@ -105,18 +105,23 @@ func TestAllowedPrivateUpstreamHostUsesExactCaseInsensitiveMatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCustomRelayURLUsesHTTPSAndExactPrivateAllowlist(t *testing.T) {
|
||||
func TestValidateCustomRelayURLAllowsHTTPOnlyForExactPrivateAllowlist(t *testing.T) {
|
||||
t.Setenv("CANVAS_ALLOW_PRIVATE_UPSTREAMS", "true")
|
||||
t.Setenv("CANVAS_ALLOWED_PRIVATE_UPSTREAM_HOSTS", "")
|
||||
if _, err := ValidateCustomRelayURL("http://127.0.0.1:8080/v1/models"); err == nil {
|
||||
t.Fatal("ValidateCustomRelayURL() should reject HTTP")
|
||||
t.Fatal("ValidateCustomRelayURL() should reject HTTP without an exact host allowlist")
|
||||
}
|
||||
if _, err := ValidateCustomRelayURL("https://127.0.0.1:8080/v1/models"); err == nil {
|
||||
t.Fatal("ValidateCustomRelayURL() should ignore the global private upstream override")
|
||||
}
|
||||
t.Setenv("CANVAS_ALLOWED_PRIVATE_UPSTREAM_HOSTS", "127.0.0.1")
|
||||
if _, err := ValidateCustomRelayURL("https://127.0.0.1:8080/v1/models"); err != nil {
|
||||
t.Fatalf("ValidateCustomRelayURL() error = %v", err)
|
||||
for _, rawURL := range []string{
|
||||
"http://127.0.0.1:8080/v1/models",
|
||||
"https://127.0.0.1:8080/v1/models",
|
||||
} {
|
||||
if _, err := ValidateCustomRelayURL(rawURL); err != nil {
|
||||
t.Fatalf("ValidateCustomRelayURL(%q) error = %v", rawURL, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user