diff --git a/docs/03-tools-system.md b/docs/03-tools-system.md index 727f68e8..49fd1b6d 100644 --- a/docs/03-tools-system.md +++ b/docs/03-tools-system.md @@ -820,19 +820,39 @@ func (t *MyTool) Execute(ctx context.Context, params MyParams) (*Result, error) } ``` +### web_search Configuration + +**Overview:** web_search is tenant-scoped only (as of v3.2, issue #952). Config is edited exclusively via `/tools/builtin/web_search` UI (or `/v1/tools/builtin/web_search/tenant-config` HTTP API for automation). + +**Key behaviors:** +- Supports provider chain: Exa, Tavily, Brave, DuckDuckGo +- Tenant admins specify `provider_order` to prioritize which providers to try (in order) +- Per-provider `enabled` flag gates usage; unknown providers are silently skipped +- **DuckDuckGo is always appended as the last-resort fallback regardless of tenant `enabled` setting — tenant admins cannot fully disable web_search.** +- API keys stored in `config_secrets` table (encrypted, tenant-scoped); never in `settings` JSON +- Defaults to DuckDuckGo only if no other provider keys are configured + +**Configuration path (old, removed):** `config.Tools.Web.*` in `config.json5` — no longer supported. Use UI only. + +**Migration:** Inline API keys from `config.json5` and legacy `builtin_tool_tenant_configs.settings` blobs are auto-migrated to `config_secrets` on first server startup (data hook 055). + ### Schema Contracts #### web_search (tenant override shape) ```json { - "provider_order": ["exa", "tavily", "brave", "duckduckgo"], - "exa": { "enabled": true, "max_results": 10 }, - "tavily": { "enabled": true, "max_results": 5 }, + "provider_order": ["brave", "exa"], "brave": { "enabled": true, "max_results": 5 }, - "duckduckgo": { "enabled": true, "max_results": 10 } + "exa": { "enabled": false }, + "duckduckgo": { "enabled": false } } ``` +**Fields:** +- `provider_order`: List of provider names in preference order (unknown names silently ignored). Optional. +- Per-provider object: `enabled` (bool, optional) + `max_results` (int, optional). If `enabled: false`, provider is skipped even if API key exists. DuckDuckGo `enabled: false` is ignored (always-on). +- Secrets (API keys): Configure via `/v1/tools/builtin/web_search/tenant-config` PUT endpoint, not in this settings blob + #### web_fetch (tenant override shape) ```json { diff --git a/docs/17-changelog.md b/docs/17-changelog.md index 16db25f4..351b7354 100644 --- a/docs/17-changelog.md +++ b/docs/17-changelog.md @@ -4,6 +4,23 @@ All notable changes to GoClaw Gateway are documented here. Format follows [Keep --- +### web_search now tenant-scoped only (2026-04-18) + +Completes issue #952: moved `web_search` configuration to tenant-exclusive settings. Global `config.Tools.Web.*` path in `config.json5` is no longer supported. All configuration is now per-tenant via `/tools/builtin/web_search` UI or `/v1/tools/builtin/web_search/tenant-config` HTTP API. + +#### Breaking + +- `config.json5` path `tools.web.*` removed (no longer parsed). Migration hook auto-migrates inline keys to `config_secrets` on startup. +- Builtin tool tenant config is tenant-scoped; per-agent overrides reserved for future. + +#### Non-breaking + +- DuckDuckGo remains always-on as last-resort fallback (free, no API key required) +- Existing secrets auto-migrated from legacy `builtin_tool_tenant_configs.settings` JSON blobs to encrypted `config_secrets` rows (idempotent hook 055) +- Tenant isolation verified: two tenants with different Brave/Exa keys get independent chains with no cross-tenant leakage + +--- + ### Secure CLI grant enforcement — registered binaries now hard-deny ungranted exec (2026-04-17) Closes a credential-scope bypass: an agent with no `secure_cli_agent_grants` row for a registered binary could still invoke it via shell fallthrough (`gh ...`, `sh -c 'gh ...'`) and pick up inherited env (`$GH_TOKEN`) or on-disk OAuth state (`~/.config/gh`). Registration is now an authorization boundary, not only a credential-injection hint.