From adeff4ef8d5bc0f8327b8e8a972be170c01e43aa Mon Sep 17 00:00:00 2001 From: "Mr.QiuW" <107580018@qq.com> Date: Thu, 9 Apr 2026 01:18:10 +0800 Subject: [PATCH] fix(opencode): handle signature writer errors --- agent/opencode/opencode.go | 39 ++++++++++++++++++--------- agent/opencode/opencode_model_test.go | 17 ++++++++++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/agent/opencode/opencode.go b/agent/opencode/opencode.go index 8268a7c..609ef58 100644 --- a/agent/opencode/opencode.go +++ b/agent/opencode/opencode.go @@ -250,26 +250,41 @@ func (a *Agent) activeProviderKeyLocked() string { func providerCacheKey(p core.ProviderConfig) string { h := sha256.New() - writeProviderSignaturePart(h, "name", p.Name) - writeProviderSignaturePart(h, "base_url", p.BaseURL) - writeProviderSignaturePart(h, "model", p.Model) - writeProviderSignaturePart(h, "api_key", p.APIKey) + mustWriteProviderSignaturePart(h, "name", p.Name) + mustWriteProviderSignaturePart(h, "base_url", p.BaseURL) + mustWriteProviderSignaturePart(h, "model", p.Model) + mustWriteProviderSignaturePart(h, "api_key", p.APIKey) keys := make([]string, 0, len(p.Env)) for k := range p.Env { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { - writeProviderSignaturePart(h, "env:"+k, p.Env[k]) + mustWriteProviderSignaturePart(h, "env:"+k, p.Env[k]) } return hex.EncodeToString(h.Sum(nil)[:16]) } -func writeProviderSignaturePart(w io.Writer, key, value string) { - io.WriteString(w, key) - io.WriteString(w, "\x00") - io.WriteString(w, value) - io.WriteString(w, "\x00") +func mustWriteProviderSignaturePart(w io.Writer, key, value string) { + if err := writeProviderSignaturePart(w, key, value); err != nil { + panic(fmt.Sprintf("write provider signature: %v", err)) + } +} + +func writeProviderSignaturePart(w io.Writer, key, value string) error { + if _, err := io.WriteString(w, key); err != nil { + return err + } + if _, err := io.WriteString(w, "\x00"); err != nil { + return err + } + if _, err := io.WriteString(w, value); err != nil { + return err + } + if _, err := io.WriteString(w, "\x00"); err != nil { + return err + } + return nil } func (a *Agent) activeProviderKey() string { @@ -292,8 +307,8 @@ func (a *Agent) modelDiscoverySnapshot() opencodeModelDiscoverySnapshot { func modelDiscoveryContextKey(snapshot opencodeModelDiscoverySnapshot) string { h := sha256.New() - writeProviderSignaturePart(h, "provider_key", snapshot.providerKey) - writeProviderSignaturePart(h, "work_dir", snapshot.workDir) + mustWriteProviderSignaturePart(h, "provider_key", snapshot.providerKey) + mustWriteProviderSignaturePart(h, "work_dir", snapshot.workDir) return hex.EncodeToString(h.Sum(nil)[:16]) } diff --git a/agent/opencode/opencode_model_test.go b/agent/opencode/opencode_model_test.go index 33c553e..3b5b178 100644 --- a/agent/opencode/opencode_model_test.go +++ b/agent/opencode/opencode_model_test.go @@ -3,6 +3,7 @@ package opencode import ( "context" "encoding/json" + "errors" "fmt" "os" "path/filepath" @@ -14,6 +15,12 @@ import ( "github.com/chenhg5/cc-connect/core" ) +type errWriter struct{} + +func (errWriter) Write(_ []byte) (int, error) { + return 0, errors.New("write failed") +} + // writeFakeModelsBin writes a temporary shell script that acts as a fake CLI. // When invoked with "models", it prints lines to stdout. // When exitCode != 0, the script exits immediately with that code. @@ -40,6 +47,16 @@ func writeFakeModelsBin(t *testing.T, lines []string, exitCode int) string { return name } +func TestWriteProviderSignaturePart_PropagatesWriterError(t *testing.T) { + err := writeProviderSignaturePart(errWriter{}, "name", "value") + if err == nil { + t.Fatal("writeProviderSignaturePart() error = nil, want write failure") + } + if !strings.Contains(err.Error(), "write failed") { + t.Fatalf("writeProviderSignaturePart() error = %v, want write failure", err) + } +} + func writePersistentModelCache(t *testing.T, cachePath string, models []core.ModelOption, updatedAt time.Time) string { t.Helper()