rag_query reuses the store resolved during authorization instead of a
second registry lookup, merges registry data store-wins so callers
cannot override a managed store's provider or credentials, and logs ids
instead of the merged config, which can carry resolved credentials.
aquery forwards only allowlisted retrieval_config keys to vector store
search, keeping caller-supplied connection overrides like api_base and
api_key away from the search call
_generic_api_call_with_fallbacks requires a model, so sync
vector_store_search and vector_store_create raised a TypeError whenever
the call carried no model. Model-less calls now go directly to the SDK
function, with the router injected for search, matching the async
wrapper's behavior
* test(e2e/ui): cover creating, testing and deleting a guardrail
The Guardrails page had no browser coverage. The RC checklist covers it by
hand against a live Presidio, which is why it has always been skipped in CI.
These drive the LiteLLM content filter instead, which runs inside the proxy,
so the whole flow is exercised without a third-party moderation service. The
create test does not stop at the table row: it sends a prompt carrying the
keyword it just banned and asserts the gateway refuses it, then sends a clean
prompt through the same guardrail and asserts it is served.
* test(e2e/ui): delete the guardrails these tests create
Review caught the fixtures being left behind. Guardrails are database rows
that show up in the table and in the playground's list, so a run that leaves
them changes what the next run sees.
Also trims the comments that restated what the helpers already say.
* test(e2e/ui): fail the run when guardrail teardown does not delete
Review caught the afterEach discarding the DELETE response, so a failed
cleanup finished quietly and left the guardrail for the next run to trip on.
* test(e2e/ui): wait for a new guardrail to reach the request path
The wizard test drove one chat completion immediately after creating the
guardrail and required a 400. A trace from the deployed stack shows the
record is stored correctly (blocked_words, action BLOCK, block_on_violation)
and the call six seconds later is still served unguarded, so the first
request can land before the proxy picks the guardrail up.
Polls the same call to the same 400 instead, which keeps the assertion and
lets the refresh land. If it never blocks, this stays red, which is what we
want it to say.
---------
Co-authored-by: Claude <noreply@anthropic.com>
* test(e2e/ui): cover the Budgets page create, edit and delete flows
The Budgets page had no browser coverage at all, so an admin creating or
editing a spend cap through the UI was only exercised by hand at RC time.
Each test reads the budget back from /budget/list, a different route from
the one the table renders, so a row that only exists in the table's cache
does not pass. The edit test pins the rate limits an unrelated spend-cap
edit has no business touching.
* test(e2e/ui): trim comments that restate the test steps
Review flagged the explanatory comments as restating ordinary setup rather
than explaining anything. Keeps the two that carry the regression rationale
for an assertion and drops the rest.
---------
Co-authored-by: Claude <noreply@anthropic.com>
The restored code seeded two mutable lists, which trips LIT002 now that
the type-discipline budget has ratcheted past what they cost
Build both in one shot as tuples and widen the parameter to Sequence so
the single caller still type checks. No behavior change, both are only
ever read
The pure revert restored `getattr(llm_router, "search_tools")`, whose
two-argument constant-attribute form ruff flags as B009, and the
strict-rule budget has since ratcheted below what that costs
Passing an explicit `None` default keeps behavior identical, the
preceding `hasattr` guard already proves the attribute is there, while
staying inside the budget
This reverts commit 65a46a5f32 (#38113)
That change made two edits that combine into a hard failure for SDK
users. It dropped the null-router guard in
_select_search_tool_from_router, so a missing router now yields an empty
search_tools list instead of returning early, and it turned the no-match
case in _select_search_tool_from_list from a debug-logged fallback into
a raised ValueError. It also added a call site in
async_pre_call_deployment_hook that invokes the selection purely for the
side effect of raising, discarding the return value
Used together, any SDK caller that sets search_tool_name and sends a web
search tool now raises "Configured search tool '<name>' was not found"
on every request. There is no way to satisfy the check off the proxy,
because search_tools is only ever populated from the proxy router, so
the SDK path cannot register one
tests/pass_through_unit_tests/test_websearch_interception_e2e.py caught
this, but #38113 only updated the handler unit tests, so the break
landed on staging
Reverting restores the previous behavior while we work out a fix that
keeps the stricter validation on the proxy path, where a silently
substituted search provider is the real problem worth rejecting, without
turning the SDK path into an unconditional error
Updates browserslist for GHSA-73wf-gq98-2v4g and GHSA-c83g-rgw3-j3cx, both CVSS 7.5. The vulnerabilities are fixed in 4.28.7; bump to 4.28.8, published 2026-08-08.
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The invite-dialog test only read data-orientation, so a regression inside
the shared field variants could restore the full-width bar and still pass.
Assert the classes that carry the layout, cover the two SSO call sites the
fix also changed, and pin the vertical/horizontal contract on the primitive.
bg-none only clears background-image, so the buttons fell back to the
browser's default button background instead of the transparent one the
inline style had.
key_edit_view opened a select and then clicked the option it found by
title text or by raw text. Both queries match the moment the option
enters the DOM, which is one render before the popup finishes entering.
Until then the positioner still carries an inline pointer-events: none,
and user-event refuses to click through it.
That is a race, and a fast machine loses it. Five of the file's 84 tests
failed on every local run while CI stayed green, which is the worst shape
for a test to have: it is only ever red on the machine of whoever is
trying to change the code.
tests/test-utils.tsx already ships chooseSelectOption for exactly this.
It finds the option by role and waits for the positioner to release
pointer events before clicking. The five call sites now use it, and the
helper takes the direct user-event API as well as a setup() instance so
callers do not have to restructure to use it.
Five consecutive full-file runs pass where every previous run failed.
Also finishes this file's screen queries, which brings
prefer-screen-queries to its target of 18.
The page painted every surface, border and text color inline with a
fixed light palette (#202124, #5f6368, #dadce0, #f8f9fa, #fff), so in
dark mode it drew dark text on hardcoded white cards.
Move the whole component to the foreground/muted/border/card/info
tokens, which already resolve for both themes.
The pure helpers express the same regression: the save-side drop must
leave the alias in place, and two registries must expand it to their
own ids. The full validate path is already covered by the
persists-verbatim test and the live e2e test.
A single-instance run cannot reproduce the two-region setup, but the
regression is fully visible in one: the alias must survive to /key/info
unrewritten, and the alias-granted key must still list the server's
tools. The broken write path stored the resolved server id instead.
Since PR #29128, key create/update/regenerate resolved every
object_permission.mcp_servers entry against the saving instance's
DB + config registry and persisted the resolved server ids. For
config-loaded servers the id is derived from a hash of the regional
URL, so in a shared-database multi-region deployment the rewrite baked
one region's ids into the row and every other region denied the key.
Grants written before v1.88.0 kept the raw alias and kept working,
which is why only newly provisioned keys broke.
Keep the validation and the stale-entry drop (the LIT-3278 fix), but
persist the caller's original identifiers for everything that resolves.
Read-time expand_permission_list already maps a name to each region's
local server id.