Devin provider merge: detached credential rekey leaves a host-selection window (and a test-coverage note) #4503
Description
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
- Configure a devin-cli OAuth credential for an EU/FedStart tenant on 2.52.0.
- Upgrade to dev @ eb81eaa and start the proxy.
- 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
lidge-jun commentedon Sep 13, 2026
리뷰 · 우선순위 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.tsvoid deps.rekey(...)- config 저장 후 auth 재키가 프로세스 생명과 비동기. 실패 시 다음 부팅까지devin슬롯 공백.src/oauth/devin.tsresolveDevinApiServer-getCredential(providerId)?.apiBaseUrl만 본다. 재키 전·실패 시 US 기본값.심볼 별칭
devin-cli- 재키 실패 시 자격은 옛 슬롯에 남아 alias로 읽을 수는 있으나, 호스트 해석이devinid만 보면 엇갈린다.심볼 #4497 tool-envelope fixture 메모 - 이 이슈 제목과 무관한 테스트 부채. 이슈를 쪼개지 않으면 트래킹이 흐려진다.
메인테이너의 판단이 필요한 지점
resolveDevinApiServer가 재키 전devin-cli슬롯을 fallback으로 읽게 할지.너의 추천
호스트 해석에
devin비면devin-cli슬롯apiBaseUrl을 읽는 얇은 fallback PR을 먼저 넣고, #4497 fixture 메모는 별도 테스트 이슈로 분리하자. 동기 await로 startServer를 막는 쪽은 마지막 수단이다.이 댓글은 grok-bot이 작성했습니다
fix(providers): close the Devin rekey host window and diagnose Antigr…
fix(providers): close the Devin rekey host window and diagnose Antigr…
lidge-jun commentedon Sep 14, 2026
Fixed on
devby 000c0f1.The startup merge writes the
devinprovider row synchronously but fires the credential rekey detached, so a row could already saydevinwhile its credential — and the EU or FedStart tenant recorded on it — still sat in thedevin-clislot.resolveDevinApiServernow 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.tsandtests/providers/devin-login.test.ts.fix(providers): close the Devin rekey host window and diagnose Antigr…