Skip to content

v1.7.2-beta.2

Pre-release
Pre-release

Choose a tag to compare

@inureyes inureyes released this 11 May 02:02

Claude Code router-settings tab lands with the model_aliases + web_search RouterConfigYaml extensions, a /v1/messages Verify probe, OpenAI Codex OAuth device-code login, and agent-profile defense-in-depth hardening.

Backend.AI GO v1.7.2-beta.2

14 commits since v1.7.2-beta.1. (13210 lines added, 397 lines deleted)

New Features

  • Claude Code router-settings tab in Settings → API. Four cards (Endpoint, Quick Setup, Model Aliases, Web Search) compose the new tab between Providers and Mesh. The tab is fully wired through RouterConfigYaml extensions so continuum-router can rewrite hard-coded claude-haiku-4-5-20251001 / claude-sonnet-4-6 / claude-opus-4-7 model names to locally served models and (optionally) inject Serper / Brave / Exa search results into agent prompts (,,, epic).
  • RouterConfigYaml extended with model_aliases (ModelAliasesConfig) and web_search (WebSearchConfig) fields, both optional and skip_serializing_if = "Option::is_none" so existing configs round-trip unchanged. ModelAliasesConfig maps size-class slots (haiku, sonnet, opus, reasoning, default) plus an exact HashMap. WebSearchConfig mirrors the continuum-router web_search schema (provider, api_key, timeout, result caps, inject policy) and includes a custom Debug impl that redacts api_key. DTO-validation tests pin the wire shape against the router spec .
  • routerSettingsStore extended with TypeScript mirrors of the Claude Code router fields. Four new Zustand actions — setModelAlias, setExactAliasEntry, updateWebSearch, applyClaudeCodeDefaults — manage the optional model_aliases and web_search sub-trees with tombstone semantics (drops the parent key when the last field is cleared). Two selector hooks: useModelAliases, useWebSearch. ActiveTab union extended with "claude-code" .
  • ClaudeCodeEndpointCard ships with read-only ANTHROPIC_BASE_URL (derived from bind_address via deriveAnthropicBaseUrl), ANTHROPIC_API_KEY (password input with reveal toggle), and ANTHROPIC_MODEL (Select populated from loaded models and model_aliases.default). "Copy as export" and "Copy as .env" buttons land the three env-vars as shell-ready snippets. A Verify button issues a /v1/messages probe through the canonical API adapter; router::service::verify_anthropic_endpoint (shared by both Tauri command and REST handler) classifies outcomes into connection_refused, timeout, auth, model_not_found, schema_mismatch, or other so the UI renders a localized hint .
  • OpenAI ChatGPT (Codex OAuth) provider with device-code login flow. CodexOAuthLoginDialog runs the device-code dance; codexOAuthService is the transport-agnostic shim for start/poll/cancel/revoke. Per-provider token store is written to <app_data_dir>/router/auth/<id>.json. Full Tauri + REST parity on the four Codex OAuth commands .
  • Locale fan-out for the Claude Code Settings tab across en, ko, ja, zh-CN, zh-TW, es — 28 keys under settings.apiSettings.claudeCode.* cover Endpoint, Quick Setup, Model Aliases, and Web Search cards plus inline help text and error messages. A locale-parity.test.ts (16 cases) enforces structural parity. User docs shipped at docs/en/api-server/claude-code.md and docs/ko/api-server/claude-code.md .
  • Interim notice that web search API keys entered in the Claude Code → Web Search card are stored separately from those in the Providers panel. Rendered below the api_key input in WebSearchCard.tsx with claude-code-section__hint styling and a corresponding !!! note "Storage separation" admonition in both English and Korean docs. Both surfaces cross-reference (the planned consolidation fix) .

Improvements

  • router::service module is the single source of truth for router_config.yaml read/write logic. read_router_config_from_file, save_router_config_preserving_backends, and reset_router_config_to_default are called by both the Tauri command and the REST handler so validation, backend-list preservation, and 0o600 permission enforcement live in exactly one place. ServiceError discriminates Validation from Io/Serde so the REST handler maps validation failures to 400 without duplicating that decision in the transport layer .
  • Quick Setup card writes haiku/sonnet/opus/default slots in a single fan-out and immediately persists. Model Aliases card surfaces per-slot <Select> rows for primary aliases plus an advanced reveal for reasoning and exact mappings using the CorsOriginsEditor visual pattern. Web Search card exposes provider dropdown, masked api_key with explicit reveal toggle, and eight advanced tuning fields. A card-level Save bar with HotReloadBadge confirmation sits below the cards; Save is gated on getWebSearchValidationKey so web_search enabled without an api_key blocks persistence .
  • All interactive elements in the new Claude Code tab use src/components/common/ primitives (no raw <button>, <select>, or <input type="checkbox">); two pure helpers in utils.tsgetWebSearchValidationKey and buildClaudeCodeModelOptions — are the single source of truth for the blocking rule and option construction; both are unit-tested. 10 component tests, 2 regression tests in ApiSettingsPage.test.tsx, and 10 new util tests .

Bug Fixes

  • cargo test --test api_parity was failing on main because five transport pairs were missing from PARITY_MAPPINGS: the four Codex OAuth commands/endpoints (start_codex_oauth_login, poll_codex_oauth_login, cancel_codex_oauth_login, revoke_codex_oauth_tokens) and the verify-probe pair (verify_anthropic_endpoint / POST /router/verify-anthropic-endpoint). Both transports already existed and shared their service function; only the parity manifest was missing the rows .
  • cargo test --test security_regression was also failing on main from the same omission. The four codex-oauth REST routes were absent from ROUTE_MANIFEST in management_api/route_scope.rs — added with settings_write scope (mirrors the surrounding /providers/* mutation routes). oauth.rs added to HANDLER_FILES_WITHOUT_EXPLICIT_SCOPE_ALLOWLIST (, follow-up).
  • router::service::tests::backends_are_preserved_across_saves no longer fails to compile after the continuum-router v1.6.2 bump introduced BackendConfig::auth: Option<BackendAuthConfig>; the test fixture now sets auth: None like every other field ( drive-by).
  • Delete action hidden for built-in agent profiles in AgentProfileCard (marketplace grid), matching the existing gate in AgentProfileEditor. store::create now unconditionally strips is_builtin = false so a caller cannot promote a newly created profile to built-in status .
  • store::update preserves is_builtin from disk, preventing a REST/Tauri caller from unmarking a canonical built-in profile and bypassing the delete-protection guard. Forcing false in update would allow PUT {canonical-builtin-id} with is_builtin: false followed by a successful DELETE because the BuiltinCannotBeDeleted guard is a conjunction of profile.is_builtin && is_canonical_builtin_id(id) .

CI/CD Improvements

None.

Technical Details

  • Single source of truth between Tauri commands and REST endpoints for all new transports: router::service::verify_anthropic_endpoint, router::service::{read_router_config_from_file, save_router_config_preserving_backends, reset_router_config_to_default}, and the four providers::oauth::codex::* service functions. Both transports are thin wrappers per .claude/rules/api-parity.md.
  • ?tab=claude-code deep-link works via the validTabs allowlist already extended in.

Dependencies

  • Update continuum-router to v1.6.2 (picks up BackendConfig::auth: Option<BackendAuthConfig>).

Breaking Changes

None.

Known Issues

  • Web search API keys entered in Claude Code → Web Search are stored separately from those in the Providers panel; consolidation is tracked in.

Security

  • agent_profile store::update defense-in-depth hardening (three changes, defaulting to Option A from the issue): (1) Self::validate_id(id)? is now the first statement of update, mirroring get and delete and rejecting path-traversal / null-byte / overlong IDs before any disk access; (2) the redundant upfront path.exists check is removed in favour of using read_profile_file as both the existence probe and the source-of-truth read for is_builtin (any I/O NotFound is mapped to AgentProfileError::NotFound(id)); (3) a new AgentProfileError::BuiltinCannotBeModified variant blocks content mutation on canonical built-in templates (UUID v5 IDs from templates::get_builtin_templates). Without this guard a direct REST/Tauri caller could rewrite "Code Assistant"'s system_prompt (prompt-injection vector), elevate enabled_tools, or swap preferred_model_id. The new error maps to HTTP 400 in management_api/handlers/agent_profiles.rs, matching the existing BuiltinCannotBeDeleted mapping .
  • Four SSRF defenses on the verify endpoint: scheme allowlist (http/https only), cloud-metadata host block (169.254.169.254 / GCP / Azure / Alibaba + full 169.254.0.0/16 link-local range), 64 KiB response body cap, and api_key scrub on all error_detail surfaces — REST callers supplying a cloud-metadata URL receive a 400 .
  • Claude Code settings hardening — `` reviews and locks down the new Claude Code tab surfaces (defense-in-depth on the api_key handling and validation paths added in /).

Full Changelog