Keep the stored AI key on the endpoint it was stored for
CI / ci (push) Successful in 1m59s
CI / ci (pull_request) Successful in 1m59s

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:
2026-10-06 08:52:01 -04:00
co-authored by Claude Opus 5.5
parent 60a92ec78f
commit 94632e0950
4 changed files with 112 additions and 35 deletions
+5 -3
View File
@@ -157,11 +157,13 @@ automatic** (D-021).
`api_key_last4` and `key_verified_at`. PATCH requires a preset name as
provider, temperature 0–1 in 0.1 steps, a non-empty model and a
system_prompt of at most 8000 characters; a fixed-URL preset's base_url
must be empty or its own. Changing provider or base_url clears
`key_verified_at`.
must be empty or its own. Provider and base_url cannot change while a
key is stored (remove the key first), so a stored key is never sent to
an endpoint it was not stored for.
`PUT /api/v1/settings/ai/api-key` takes `{api_key}` (write-only, at least
8 characters, sealed with the secret box; an empty string removes it) and
clears `key_verified_at`. `POST /api/v1/settings/ai/verify` calls
clears `key_verified_at`; a preset without a fixed base_url takes a key
only when its base_url passes `secureurl.Check`. `POST /api/v1/settings/ai/verify` calls
`Provider.Verify` and records `key_verified_at`;
`GET /api/v1/settings/ai/models` returns `{models: [{id, display_name}]}`
live from the provider. Both work before a model is chosen