Skip to content

Devin provider merge: detached credential rekey leaves a host-selection window (and a test-coverage note) #4503

Closed

Description

@lidge-jun

Client or integration

Direct HTTP/API client

Area

Authentication and account pool

Summary

runDevinProviderMergeStartupMigration (src/providers/devin-provider-merge-migration.ts:202, commit f7d9dba) writes the merged providers["devin"] config synchronously, then fires void rekeyProviderCredentials("devin-cli","devin") detached. getCredential is a literal slot key, so until the rekey lands — or permanently for that process if it fails (retried next boot) — resolveDevinApiServer reads an empty devin slot and falls back to the default US host. EU/FedStart tenants send their key to the wrong host in that window; GUI login status is similarly stale. The request-time TOKEN path is unaffected (resolveDevinToken uses provider.apiKey / forwarded Authorization / env, never the OAuth slot), so this is a host-selection and status-window defect, not a credential-loss defect. Collision handling refuses by design with a logged warning.

Bundled test-coverage note from the same audit: PR #4497's Pi-shape image-part regression cases cover the tool path by composition; a direct role:"tool" envelope fixture would catch a tool-branch-only regression.

Reproduction

  1. Configure a devin-cli OAuth credential for an EU/FedStart tenant on 2.52.0.
  2. Upgrade to dev @ eb81eaa and start the proxy.
  3. During the window between the config save and the detached rekey (or after a rekey failure), requests resolve the default US host instead of the tenant host.

Found by the 2.53.0 release regression audit (lane13, maintainer-downgraded from the lane's P1 claim after verifying the token path). Synthesis disposition: follow-up issue — self-healing, logged, retried on boot; not promotion blocking.

Version

dev @ eb81eaa (post-2.52.0, pre-2.53.0)

Operating system

macOS (any; codepath is platform-independent)

Provider and model

devin (OAuth, EU/FedStart tenants)

Logs or error output

[devin-provider-merge] credential rekey failed and will retry on the next start: ...

Screenshots and supporting files

N/A — evidence is source-level, cited inline.

Redacted configuration

providers.devin (merged from devin-cli)

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    OwnerAuthor

    리뷰 · 우선순위 46 / 80

    설명
    이 이슈는 방금 dev에 들어간 #4484(Devin/devin-cli 통합)의 후속이다. runDevinProviderMergeStartupMigration(src/providers/devin-provider-merge-migration.ts)는 config의 providers["devin-cli"]→devin 이동은 동기 저장하고, auth.json 슬롯 재키(rekeyProviderCredentials)만 void로 비동기 발사한다. startServer가 동기여서 await를 못 넣는 제약은 본문·주석에 이미 적혀 있다. 문제는 getCredential이 문자열 슬롯 키라는 점이다. 재키가 끝나기 전(또는 실패해 다음 부팅까지) resolveDevinApiServer(src/oauth/devin.ts)가 devin 슬롯을 비어 있다고 보고 기본 US 호스트로 떨어진다. EU/FedStart 테넌트는 그 짧은 창에 잘못된 호스트로 붙을 수 있고, GUI 로그인 상태도 한동안 어긋날 수 있다.

    다행히 요청 시 TOKEN 경로는 provider.apiKey / 전달 Authorization / env를 쓰므로 자격 증명 유실은 아니다. 호스트 선택·상태 표시 창 결함이다. 충돌 시 merge하지 않고 경고만 남기는 것도 설계대로다. 메인테이너가 2.53.0 회귀 감사(lane13)에서 P1 주장에서 내린 뒤 follow-up으로 연 이슈라, 프로모션 블로커는 아니다. 같은 메모에 #4497 Pi형 tool envelope 직접 fixture 부족도 묶여 있는데, 그건 Devin 재키와 영역이 다르다.

    현재 tip은 #4484 머지 커밋 f7d9dbad0 위에 이미 여러 캐리(#4498 암호화 agent_message, #4500 DeepSeek Flash 비전, god-file 분할 등)가 올라와 있고 package는 2.54.0이다. 이 follow-up은 그 tip 위에서 얇게 고치면 된다. deprecated alias가 남아 있는 동안은 옛 슬롯을 읽는 fallback이 안전하고, alias를 나중에 걷어낼 때 동기 rekey나 부팅 배리어로 옮기면 된다. types/config 분할과는 무관하다.

    우선순위 46은 영향 인구(EU/FedStart OAuth)가 좁고 self-heal·재시도가 있으며, 이미 머지된 #4484를 되돌릴 정도는 아니기 때문이다. 그래도 부팅 직후 첫 요청이 민감한 테넌트에는 실수가 난다.

    라인 문제
    src/providers/devin-provider-merge-migration.ts void deps.rekey(...) - config 저장 후 auth 재키가 프로세스 생명과 비동기. 실패 시 다음 부팅까지 devin 슬롯 공백.
    src/oauth/devin.ts resolveDevinApiServer - getCredential(providerId)?.apiBaseUrl만 본다. 재키 전·실패 시 US 기본값.
    심볼 별칭 devin-cli - 재키 실패 시 자격은 옛 슬롯에 남아 alias로 읽을 수는 있으나, 호스트 해석이 devin id만 보면 엇갈린다.
    심볼 #4497 tool-envelope fixture 메모 - 이 이슈 제목과 무관한 테스트 부채. 이슈를 쪼개지 않으면 트래킹이 흐려진다.

    메인테이너의 판단이 필요한 지점

    • 부팅 창을 없애려고 rekey를 동기 경로로 끌어올릴지(서버 기동 계약 변경), 아니면 resolveDevinApiServer가 재키 전 devin-cli 슬롯을 fallback으로 읽게 할지.
    • GUI 상태를 “재키 중/재시도 예정”으로 노출할지.
    • fix(chat): accept Pi and Anthropic-shaped image parts on the chat wire #4497 fixture 메모를 이 이슈에서 분리할지.

    너의 추천
    호스트 해석에 devin 비면 devin-cli 슬롯 apiBaseUrl을 읽는 얇은 fallback PR을 먼저 넣고, #4497 fixture 메모는 별도 테스트 이슈로 분리하자. 동기 await로 startServer를 막는 쪽은 마지막 수단이다.

    이 댓글은 grok-bot이 작성했습니다

  2. added 2 commits that reference this issue on Sep 14, 2026
    7a01f3f
    000c0f1
  3. lidge-jun commented on Sep 14, 2026

    @lidge-jun
    OwnerAuthor

    Fixed on dev by 000c0f1.

    The startup merge writes the devin provider row synchronously but fires the credential rekey detached, so a row could already say devin while its credential — and the EU or FedStart tenant recorded on it — still sat in the devin-cli slot. resolveDevinApiServer now follows the deprecated-alias link to that slot, so the request goes to the tenant the account is actually provisioned on instead of the US default.

    Because this is credential and host-selection code it went through an explicit security review, which failed the first version for a real reason: the fallback originally fired whenever the literal credential had no usable apiBaseUrl, which also covers a credential that exists with a missing or off-allowlist host. Since the rekey refuses an occupied destination slot, both slots can hold credentials for two different accounts, and in that state a request would have kept one account's bearer while taking the other account's tenant host. The merged version consults alias slots only when the literal slot holds no credential at all, and a regression test pins exactly that pair.

    The test-coverage note in this issue is addressed by the cases added in tests/providers/devin-adapter.test.ts and tests/providers/devin-login.test.ts.

  4. added a commit that references this issue on Sep 17, 2026
    d96a1e4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions