mirror of
https://github.com/patriceckhart/zot.git
synced 2026-06-27 05:46:34 +02:00
Merge pull request #35 from s3rj1k/main
Add --insecure flag to skip TLS verification Co-authored-by: s3rj1k <evasive.gyron@gmail.com>
This commit is contained in:
commit
e0ca3fdd3e
6 changed files with 138 additions and 0 deletions
|
|
@ -74,6 +74,9 @@ type Args struct {
|
|||
// skill discovery, including built-ins.
|
||||
WithSkills bool
|
||||
|
||||
// InsecureTLS skips TLS verification for custom inference endpoints.
|
||||
InsecureTLS bool
|
||||
|
||||
// NoYolo turns on per-tool confirmation. Before each tool
|
||||
// invocation the TUI prompts the user with the tool name + args
|
||||
// and waits for an explicit yes/no. The user can also pick
|
||||
|
|
@ -190,6 +193,8 @@ func ParseArgs(in []string) (Args, error) {
|
|||
case "--with-skills", "--with-skill":
|
||||
// Deprecated no-op: user skills are loaded by default.
|
||||
a.WithSkills = true
|
||||
case "--insecure":
|
||||
a.InsecureTLS = true
|
||||
case "--no-yolo":
|
||||
a.NoYolo = true
|
||||
case "--reasoning":
|
||||
|
|
@ -373,6 +378,7 @@ func PrintHelp(version string) {
|
|||
row{"--model ID", "model id (see --list-models)"},
|
||||
row{"--api-key KEY", "api key for this run (env / auth.json fallback)"},
|
||||
row{"--base-url URL", "override provider api base url"},
|
||||
row{"--insecure", "skip TLS certificate verification (for self-signed-cert endpoints)"},
|
||||
row{"--reasoning off|minimum|low|medium|high|maximum", "set thinking level on supported models"},
|
||||
row{"--temperature N", "sampling temperature, 0 to 2 (omit for provider default)"},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -420,6 +420,11 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
|
|||
args.BaseURL = "http://localhost:11434"
|
||||
}
|
||||
|
||||
provider.InsecureSkipVerify = (args.InsecureTLS || cfg.Insecure) && args.BaseURL != ""
|
||||
if provider.InsecureSkipVerify {
|
||||
provider.ApplyInsecureTLS()
|
||||
}
|
||||
|
||||
// If the model has a base URL, credentials are optional (local
|
||||
// models like ollama don't need real API keys).
|
||||
if resolvedModel.BaseURL != "" && credErr != nil {
|
||||
|
|
|
|||
|
|
@ -211,3 +211,62 @@ func TestCanonicalProviderAliasesAreKnown(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveInsecureOnlyWithCustomBaseURL(t *testing.T) {
|
||||
orig := provider.InsecureSkipVerify
|
||||
t.Cleanup(func() { provider.InsecureSkipVerify = orig })
|
||||
|
||||
t.Setenv("ZOT_HOME", t.TempDir())
|
||||
t.Setenv("OPENAI_API_KEY", "test-key")
|
||||
|
||||
// no --base-url: must stay false even with --insecure.
|
||||
provider.InsecureSkipVerify = false
|
||||
_, err := Resolve(Args{Provider: "openai", InsecureTLS: true}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve: %v", err)
|
||||
}
|
||||
if provider.InsecureSkipVerify {
|
||||
t.Fatal("InsecureSkipVerify must not be set without a custom base URL")
|
||||
}
|
||||
|
||||
// --base-url + --insecure: must be true.
|
||||
provider.InsecureSkipVerify = false
|
||||
_, err = Resolve(Args{Provider: "openai", InsecureTLS: true, BaseURL: "https://my-llm.internal/v1"}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve: %v", err)
|
||||
}
|
||||
if !provider.InsecureSkipVerify {
|
||||
t.Fatal("InsecureSkipVerify must be set with --insecure and --base-url")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveInsecureFromConfig(t *testing.T) {
|
||||
orig := provider.InsecureSkipVerify
|
||||
t.Cleanup(func() { provider.InsecureSkipVerify = orig })
|
||||
|
||||
t.Setenv("ZOT_HOME", t.TempDir())
|
||||
t.Setenv("OPENAI_API_KEY", "test-key")
|
||||
if err := SaveConfig(Config{Provider: "openai", Insecure: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// no --base-url: must stay false.
|
||||
provider.InsecureSkipVerify = false
|
||||
_, err := Resolve(Args{Provider: "openai"}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve: %v", err)
|
||||
}
|
||||
if provider.InsecureSkipVerify {
|
||||
t.Fatal("InsecureSkipVerify must not be set without a custom base URL")
|
||||
}
|
||||
|
||||
// --base-url: must be true.
|
||||
provider.InsecureSkipVerify = false
|
||||
_, err = Resolve(Args{Provider: "openai", BaseURL: "https://my-llm.internal/v1"}, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Resolve: %v", err)
|
||||
}
|
||||
if !provider.InsecureSkipVerify {
|
||||
t.Fatal("InsecureSkipVerify must be set when config insecure=true and --base-url is provided")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ type Config struct {
|
|||
// which is on; false shows ignored entries. Toggle from /settings.
|
||||
RespectGitignore *bool `json:"respect_gitignore,omitempty"`
|
||||
|
||||
// Insecure skips TLS verification for custom inference endpoints.
|
||||
Insecure bool `json:"insecure,omitempty"`
|
||||
|
||||
// LastChangelogShown is the version whose release-notes
|
||||
// dialog the user has already seen. When the running binary's
|
||||
// version differs, the next interactive run shows the
|
||||
|
|
|
|||
16
packages/provider/httpclient.go
Normal file
16
packages/provider/httpclient.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// InsecureSkipVerify disables TLS cert verification for inference connections.
|
||||
var InsecureSkipVerify bool
|
||||
|
||||
// ApplyInsecureTLS replaces http.DefaultTransport to skip TLS cert verification.
|
||||
func ApplyInsecureTLS() {
|
||||
http.DefaultTransport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, //nolint:gosec
|
||||
}
|
||||
}
|
||||
49
packages/provider/httpclient_test.go
Normal file
49
packages/provider/httpclient_test.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package provider
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestApplyInsecureTLSSetsDefaultTransport(t *testing.T) {
|
||||
orig := http.DefaultTransport
|
||||
t.Cleanup(func() { http.DefaultTransport = orig })
|
||||
|
||||
ApplyInsecureTLS()
|
||||
|
||||
tr, ok := http.DefaultTransport.(*http.Transport)
|
||||
if !ok {
|
||||
t.Fatalf("expected *http.Transport, got %T", http.DefaultTransport)
|
||||
}
|
||||
if tr.TLSClientConfig == nil || !tr.TLSClientConfig.InsecureSkipVerify {
|
||||
t.Fatal("expected InsecureSkipVerify=true in TLS config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsecureClientReachesTLSServer(t *testing.T) {
|
||||
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
orig := http.DefaultTransport
|
||||
t.Cleanup(func() { http.DefaultTransport = orig })
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
if _, err := client.Get(srv.URL); err == nil {
|
||||
t.Fatal("expected TLS error with default transport, got nil")
|
||||
}
|
||||
|
||||
ApplyInsecureTLS()
|
||||
|
||||
resp, err := client.Get(srv.URL)
|
||||
if err != nil {
|
||||
t.Fatalf("request failed after ApplyInsecureTLS: %v", err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("status=%d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue