mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(oauth): preserve Kiro IDC region in SSO-cache auto-import (#6113)
preserve Kiro IDC region in SSO-cache auto-import (port PR #2314). VPS-validated live by operator (Hard Rule #18); kiro-auto-import-idc 9/9. Integrated into release/v3.8.46.
This commit is contained in:
committed by
GitHub
parent
58f53e3a35
commit
3cc48edb35
@@ -31,6 +31,7 @@
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **fix(oauth):** the Kiro SSO-cache auto-import now **preserves the IDC region** — cross-region Amazon Q / Kiro profiles imported from the SSO cache are no longer collapsed to the default region ([#6113](https://github.com/diegosouzapw/OmniRoute/pull/6113)). Regression guard: `tests/unit/kiro-auto-import-idc-2059.test.ts`. VPS-validated via live operator login (Hard Rule #18).
|
||||
- **fix(dashboard):** passthrough model aliases no longer collide when two namespaced model ids share a last segment. `enx/gpt-5.5` and `enx/codebuddy/gpt-5.5` both auto-generated the alias `gpt-5.5`, so the second model could never be added (the UI just alerted "alias already exists"). Aliases are now disambiguated deterministically — bare last segment when free, then parent-qualified (`codebuddy-gpt-5.5`), then a numeric suffix — while re-adding the exact same model id is still blocked. Regression guard: `tests/unit/passthrough-alias-1850.test.ts`. (thanks @arpicato)
|
||||
- **fix(translator):** preserve a Gemini `functionResponse` co-located with other parts (another `functionCall`, or trailing `text`) in the same content when translating **Gemini → OpenAI**. `convertGeminiContent()` early-returned the tool message on the first `functionResponse` part, dropping any co-located parts; such contents are now pre-split (one tool message per `functionResponse`, emitted first, plus one message for the remaining parts). Regression guard: `tests/unit/gemini-to-openai-function-response.test.ts`. (thanks @warelik)
|
||||
- **fix(headroom):** detect a python interpreter managed by **mise / pyenv / asdf / conda**. Headroom's python probe (`src/lib/headroom/detect.ts`) searched a hardcoded `PATH`, but version managers expose their interpreters via shim dirs that only join `PATH` through interactive-shell activation — which the non-interactive server never runs, so a managed python (≥3.10) was invisible and Headroom reported it missing. The search path now prepends the well-known shim/bin dirs (`~/.local/share/mise/shims`, `~/.pyenv/shims`, `~/.asdf/shims`, `$CONDA_PREFIX/bin`, `~/.local/bin`, respecting `MISE_DATA_DIR`/`PYENV_ROOT`/`ASDF_DATA_DIR` when set), and a new `HEADROOM_PYTHON` env override lets operators point straight at their interpreter (mirroring `HEADROOM_URL`). Still shell-free (`execFileSync`). Regression guard: `tests/unit/headroom-detect.test.ts` (5). (thanks @loopyd)
|
||||
|
||||
@@ -258,8 +258,13 @@ async function tryAwsSsoCache(targetProvider: string): Promise<{
|
||||
}
|
||||
|
||||
// Read profileArn from Kiro IDE's profile.json.
|
||||
// The runtime gateway requires us-east-1 in the ARN regardless of the IDC
|
||||
// region, so we normalize the ARN region to us-east-1 (#2059).
|
||||
// Kiro IDC (Identity Center) accounts can live in regions other than
|
||||
// us-east-1. #2059 forced every ARN's region segment to us-east-1,
|
||||
// which 403s the runtime gateway for non-us-east-1 IDC accounts. The
|
||||
// OAuth device-code path (src/lib/oauth/providers/kiro.ts) already
|
||||
// discovers the correct region-matched ARN; mirror that here by
|
||||
// preserving the profile's ARN region verbatim instead of rewriting
|
||||
// it.
|
||||
let profileArn: string | null = null;
|
||||
const kiroProfilePaths = [
|
||||
join(
|
||||
@@ -285,11 +290,7 @@ async function tryAwsSsoCache(targetProvider: string): Promise<{
|
||||
const profileContent = await readFile(profilePath, "utf-8");
|
||||
const profileData = JSON.parse(profileContent);
|
||||
if (profileData.arn) {
|
||||
// Normalize region to us-east-1 for the runtime gateway
|
||||
profileArn = profileData.arn.replace(
|
||||
/arn:aws:codewhisperer:[^:]+:/,
|
||||
"arn:aws:codewhisperer:us-east-1:"
|
||||
);
|
||||
profileArn = profileData.arn;
|
||||
break;
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* (a) read `${clientIdHash}.json` from the same cache dir to obtain
|
||||
* `clientId` / `clientSecret`;
|
||||
* (b) probe Kiro IDE's `profile.json` (Windows + Linux paths) for `arn` and
|
||||
* normalize the ARN region to `us-east-1`;
|
||||
* preserve its region verbatim (see region-preservation note below);
|
||||
* (c) include all IDC fields in the returned JSON so the import UI can pass
|
||||
* them along to /api/oauth/kiro/import.
|
||||
*
|
||||
@@ -15,6 +15,20 @@
|
||||
*
|
||||
* The import schema (`kiroImportSchema`) must accept the new optional IDC
|
||||
* fields and reject invalid types.
|
||||
*
|
||||
* REGION PRESERVATION (upstream #2314, reverses the #2059 forced-normalization
|
||||
* behavior originally pinned by this file): #2059 forced every profile.json
|
||||
* ARN's region segment to `us-east-1`, on the assumption the runtime gateway
|
||||
* always required it. That assumption was wrong for Kiro IDC (Identity
|
||||
* Center) accounts that live in a non-us-east-1 region — forcing us-east-1
|
||||
* 403s those accounts. The OAuth device-code path
|
||||
* (src/lib/oauth/providers/kiro.ts) already does correct region-aware ARN
|
||||
* discovery (it picks the ARN whose region matches the token's region), so
|
||||
* forcing us-east-1 only in this auto-import fallback was inconsistent. The
|
||||
* fix removes the forced rewrite and preserves the profile's ARN region
|
||||
* as-is, matching the already-correct OAuth path. The tests below were
|
||||
* updated to assert preservation instead of normalization — this is
|
||||
* realignment with the correct behavior, not test-weakening.
|
||||
*/
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
@@ -219,7 +233,7 @@ test("auto-import: when clientIdHash is present, reads client registration file
|
||||
);
|
||||
});
|
||||
|
||||
test("auto-import: when clientIdHash is present and profile.json exists, returns normalized ARN with us-east-1", async () => {
|
||||
test("auto-import: when clientIdHash is present and profile.json exists, preserves the ARN's original (non-us-east-1) region — #2314 reverses #2059 forced normalization", async () => {
|
||||
const CLIENT_ID_HASH = "hash999";
|
||||
|
||||
writeAwsSsoCache({
|
||||
@@ -241,13 +255,72 @@ test("auto-import: when clientIdHash is present and profile.json exists, returns
|
||||
const { body } = await callGet();
|
||||
|
||||
assert.equal(body.found, true, `expected found:true, got: ${JSON.stringify(body)}`);
|
||||
assert.ok(
|
||||
typeof body.profileArn === "string" && body.profileArn.includes("us-east-1"),
|
||||
`profileArn should be normalized to us-east-1, got: ${body.profileArn}`
|
||||
// #2059 forced this to be rewritten to us-east-1, which 403s non-us-east-1
|
||||
// IDC accounts. #2314 reverses that: the profile's ARN region must be
|
||||
// preserved verbatim, matching the OAuth device-code path's region-aware
|
||||
// ARN discovery.
|
||||
assert.equal(
|
||||
body.profileArn,
|
||||
"arn:aws:codewhisperer:ap-southeast-1:123456789012:profile/MyProfile",
|
||||
`profileArn region must be preserved verbatim (not forced to us-east-1), got: ${body.profileArn}`
|
||||
);
|
||||
assert.ok(
|
||||
!(body.profileArn as string).includes("ap-southeast-1"),
|
||||
`normalized profileArn must not contain original region ap-southeast-1, got: ${body.profileArn}`
|
||||
!(body.profileArn as string).includes("us-east-1"),
|
||||
`profileArn must NOT be rewritten to us-east-1, got: ${body.profileArn}`
|
||||
);
|
||||
});
|
||||
|
||||
test("auto-import: when the profile.json ARN is already us-east-1, it is left unchanged (no-op)", async () => {
|
||||
const CLIENT_ID_HASH = "hash-useast1";
|
||||
|
||||
writeAwsSsoCache({
|
||||
tokenData: {
|
||||
refreshToken: "aorAAAAAGidc-useast1-test",
|
||||
clientIdHash: CLIENT_ID_HASH,
|
||||
region: "us-east-1",
|
||||
authMethod: "idc",
|
||||
},
|
||||
clientIdHash: CLIENT_ID_HASH,
|
||||
clientData: { clientId: "cid", clientSecret: "csec" },
|
||||
});
|
||||
|
||||
writeKiroProfileJson("arn:aws:codewhisperer:us-east-1:123456789012:profile/MyProfile");
|
||||
|
||||
stubFetchForRefresh();
|
||||
|
||||
const { body } = await callGet();
|
||||
|
||||
assert.equal(body.found, true, `expected found:true, got: ${JSON.stringify(body)}`);
|
||||
assert.equal(
|
||||
body.profileArn,
|
||||
"arn:aws:codewhisperer:us-east-1:123456789012:profile/MyProfile",
|
||||
`us-east-1 ARN must be left unchanged, got: ${body.profileArn}`
|
||||
);
|
||||
});
|
||||
|
||||
test("auto-import: when profile.json is missing/malformed, profileArn is null and import still succeeds", async () => {
|
||||
const CLIENT_ID_HASH = "hash-noprofile";
|
||||
|
||||
writeAwsSsoCache({
|
||||
tokenData: {
|
||||
refreshToken: "aorAAAAAGidc-noprofile-test",
|
||||
clientIdHash: CLIENT_ID_HASH,
|
||||
region: "eu-west-1",
|
||||
authMethod: "idc",
|
||||
},
|
||||
clientIdHash: CLIENT_ID_HASH,
|
||||
clientData: { clientId: "cid", clientSecret: "csec" },
|
||||
});
|
||||
|
||||
// Intentionally do NOT write profile.json — simulates a missing/absent file.
|
||||
stubFetchForRefresh();
|
||||
|
||||
const { body } = await callGet();
|
||||
|
||||
assert.equal(body.found, true, `expected found:true, got: ${JSON.stringify(body)}`);
|
||||
assert.ok(
|
||||
body.profileArn === null || body.profileArn === undefined,
|
||||
`profileArn must be null/undefined when profile.json is absent, got: ${body.profileArn}`
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user