Repository navigation
Conversation
… keys cheaper-inference#15242 put POST /api/providers/{validate,import,bulk} on the loopback-only list because the Devin CLI key fallback in webProvidersB.ts spawns a fixed binary. Those routes are also how the dashboard verifies, saves and bulk-adds an API key, so behind a tunnel (Cloudflare, Tailscale Funnel...) every admin got `403 LOCAL_ONLY: This endpoint requires localhost access` on "Verify", on saving a key in the single tab (it validates first) and on bulk add. A new provider key could not be added at all from a remote dashboard. The spawn is the only side effect, and cheaper-inference#15766 already gates it at its call site: validateProviderApiKey takes allowLocalSpawn and the Devin validator skips the CLI fallback when it is false. /api/providers, /api/providers/{id}/test and /test-batch pass it from getRequestPeerLocality(request). These three routes never did, because the path lock stood in for it. - remove /api/providers/(validate|import|bulk) from LOCAL_ONLY_API_PATTERNS and the matching x-loopback-only marks in docs/openapi.yaml; - pass allowLocalSpawn: getRequestPeerLocality(request) !== "remote" from the three routes, the same convention as the other callers, so a remote caller still can never spawn a process. Reproduced with tunnel-style forwarding headers (X-Forwarded-For + CF-Connecting-IP): validate and bulk answered 403 LOCAL_ONLY before, and reach the auth check after. The Devin spawn gate itself stays covered by devin-cli-fallback-spawn-local-only-15159.test.ts.
Collaborator
|
Hi @bufftop25 — closing this pull request to clear the open queue. The branch |
Collaborator
|
Hi @bufftop25 — reopening this pull request. The close was a mistake, and it is back in the merge queue. The branch |
6 of 7 tasks
Collaborator
|
Thanks @bufftop25. This is covered on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Behind a tunnel, the dashboard cannot verify or add a provider API key:
POST /api/providers/{validate,import,bulk}answer403 LOCAL_ONLY: This endpoint requires localhost access, so "Verify", saving in the single tab (it validates first) and bulk add all fail for every remote admin.#15242 added the three paths to
LOCAL_ONLY_API_PATTERNSbecause the Devin CLI key fallback spawns a fixed binary. #15766 later gated that same spawn at its call site (allowLocalSpawn, from the peer locality) and wired it intoPOST /api/providers,/api/providers/{id}/testand/test-batch, but not into these three routes, because the path lock stood in for it. The path lock is now redundant for the spawn and breaks key management for remote dashboards.This is not limited to custom providers: the lock is by path, so verifying or adding a key for any API-key provider (
openai,anthropic,groq,openrouter, custom nodes) is refused behind a tunnel./api/providers/(validate|import|bulk)fromLOCAL_ONLY_API_PATTERNSand the matchingx-loopback-onlymarks indocs/openapi.yaml.allowLocalSpawn: getRequestPeerLocality(request) !== "remote"from the three routes, the same convention as the existing callers. A remote caller still can never trigger the spawn.Related Issues
check:ai-attributionstep; none touch these files).Validation
npm run lint(eslint with the project suppressions: clean on the touched files)release/v3.8.52@ 4ea24a2); focused checks rerun afterwardAlso run locally:
typecheck:core,check:file-size,check-openapi-security-tiers,check-openapi-routes,check-route-guard-membership(0 new gaps),check:ai-attributionon the commit message.Tests Added Or Updated
tests/unit/authz/route-guard-providers-spawn-local-only.test.ts: the old assertion (the three paths ARE local-only) is replaced by "they are NOT path-locked", plus a new test that each route derivesallowLocalSpawnfromgetRequestPeerLocality(request) !== "remote". With the source change reverted, both new tests fail; with it they pass.tests/unit/devin-cli-fallback-spawn-local-only-15159.test.ts(existing, unchanged) keeps covering the spawn gate itself with a real marker-file spawn.Coverage Notes
validateDevinCloudAgentProvider) already has behavioural coverage; the new tests pin that the routes feed it.Reviewer Notes
/api/providers/{id}/modelsis already handled. A non-local caller still gets the HTTP verdict only and never reachesspawn.isLocalOnlyPathno longer says "local-only" for these paths, so anything relying on that classification for them should be reviewed.check-route-guard-membershipreports 0 new gaps.X-Forwarded-For+CF-Connecting-IP) against the built image: before,validateandbulkanswered 403LOCAL_ONLY; after, they reach the auth check. With an access token the same calls reach the validator and return its verdict.