mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
Add exec allow_remote config support in web settings (#1363)
- default tools.exec.allow_remote to true when omitted in config loading - preserve allow_remote in OpenClaw config migration and API updates - expose allow_remote in the web config form with i18n strings - add backend and config tests covering the new default behavior
This commit is contained in:
@@ -48,6 +48,9 @@ func (h *Handler) handleUpdateConfig(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, fmt.Sprintf("Invalid JSON: %v", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if execAllowRemoteOmitted(body) {
|
||||
cfg.Tools.Exec.AllowRemote = config.DefaultConfig().Tools.Exec.AllowRemote
|
||||
}
|
||||
|
||||
if errs := validateConfig(&cfg); len(errs) > 0 {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -68,6 +71,20 @@ func (h *Handler) handleUpdateConfig(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
|
||||
}
|
||||
|
||||
func execAllowRemoteOmitted(body []byte) bool {
|
||||
var raw struct {
|
||||
Tools *struct {
|
||||
Exec *struct {
|
||||
AllowRemote *bool `json:"allow_remote"`
|
||||
} `json:"exec"`
|
||||
} `json:"tools"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &raw); err != nil {
|
||||
return false
|
||||
}
|
||||
return raw.Tools == nil || raw.Tools.Exec == nil || raw.Tools.Exec.AllowRemote == nil
|
||||
}
|
||||
|
||||
// handlePatchConfig partially updates the system configuration using JSON Merge Patch (RFC 7396).
|
||||
// Only the fields present in the request body will be updated; all other fields remain unchanged.
|
||||
//
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/config"
|
||||
)
|
||||
|
||||
func TestHandleUpdateConfig_PreservesExecAllowRemoteDefaultWhenOmitted(t *testing.T) {
|
||||
configPath, cleanup := setupOAuthTestEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
h := NewHandler(configPath)
|
||||
mux := http.NewServeMux()
|
||||
h.RegisterRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/config", bytes.NewBufferString(`{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"workspace": "~/.picoclaw/workspace"
|
||||
}
|
||||
},
|
||||
"model_list": [
|
||||
{
|
||||
"model_name": "custom-default",
|
||||
"model": "openai/gpt-4o",
|
||||
"api_key": "sk-default"
|
||||
}
|
||||
]
|
||||
}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
mux.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want %d, body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
|
||||
cfg, err := config.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig() error = %v", err)
|
||||
}
|
||||
if !cfg.Tools.Exec.AllowRemote {
|
||||
t.Fatal("tools.exec.allow_remote should remain true when omitted from PUT /api/config")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleUpdateConfig_DoesNotInheritDefaultModelFields(t *testing.T) {
|
||||
configPath, cleanup := setupOAuthTestEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
h := NewHandler(configPath)
|
||||
mux := http.NewServeMux()
|
||||
h.RegisterRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPut, "/api/config", bytes.NewBufferString(`{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"workspace": "~/.picoclaw/workspace"
|
||||
}
|
||||
},
|
||||
"model_list": [
|
||||
{
|
||||
"model_name": "custom-default",
|
||||
"model": "openai/gpt-4o",
|
||||
"api_key": "sk-default"
|
||||
}
|
||||
]
|
||||
}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
mux.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want %d, body=%s", rec.Code, http.StatusOK, rec.Body.String())
|
||||
}
|
||||
|
||||
cfg, err := config.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig() error = %v", err)
|
||||
}
|
||||
if got := cfg.ModelList[0].APIBase; got != "" {
|
||||
t.Fatalf("model_list[0].api_base = %q, want empty string", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user