Keep the stored AI key on the endpoint it was stored for
PATCH /settings/ai refused nothing when the base URL or provider changed with a key stored, so a session could point base_url at another server and have POST /settings/ai/verify send it the key. Both changes are now refused while a key is stored: remove the key, change the endpoint, then store the new key. A preset without a fixed base URL takes a key only when its base URL passes secureurl.Check, so the key never crosses the network in plain text. Maestro task: 176b2a30-6e90-4339-b430-5b8967b2fd32 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -194,15 +194,19 @@ func TestAISettingsAPI(t *testing.T) {
|
||||
t.Errorf("POST reset-prompt = %d %v", rec.Code, body)
|
||||
}
|
||||
|
||||
// Pointing the key at another server voids its verification.
|
||||
rec, body = call(http.MethodPatch, aiPath, `{"base_url":"https://llm.example/v1"}`)
|
||||
if rec.Code != http.StatusOK || body["key_verified_at"] != nil || body["api_key_last4"] != "7d21" {
|
||||
t.Errorf("PATCH base_url = %d %v", rec.Code, body)
|
||||
// The stored key is never pointed at another server or provider.
|
||||
for _, patch := range []string{`{"base_url":"https://attacker.example/v1"}`, `{"provider":"openai","base_url":""}`} {
|
||||
if rec, body := call(http.MethodPatch, aiPath, patch); rec.Code != http.StatusBadRequest || errorCode(body) != "invalid_settings" {
|
||||
t.Errorf("PATCH %s with a key stored = %d %v, want 400 invalid_settings", patch, rec.Code, body)
|
||||
}
|
||||
}
|
||||
|
||||
if rec, body := call(http.MethodPut, aiKeyPath, `{"api_key":""}`); rec.Code != http.StatusOK || body["api_key_last4"] != nil {
|
||||
if rec, body := call(http.MethodPut, aiKeyPath, `{"api_key":""}`); rec.Code != http.StatusOK || body["api_key_last4"] != nil || body["key_verified_at"] != nil {
|
||||
t.Errorf("PUT empty key = %d %v", rec.Code, body)
|
||||
}
|
||||
rec, body = call(http.MethodPatch, aiPath, `{"base_url":"https://llm.example/v1"}`)
|
||||
if rec.Code != http.StatusOK || body["base_url"] != "https://llm.example/v1" {
|
||||
t.Errorf("PATCH base_url without a key = %d %v", rec.Code, body)
|
||||
}
|
||||
|
||||
if len(bodies) < 30 {
|
||||
t.Fatalf("scanned only %d response bodies", len(bodies))
|
||||
|
||||
Reference in New Issue
Block a user