fix: restore auth fallback ordering
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
### Fixes
|
### Fixes
|
||||||
- Onboarding: resolve CLI entrypoint when running via `npx` so gateway daemon install works without a build step.
|
- Onboarding: resolve CLI entrypoint when running via `npx` so gateway daemon install works without a build step.
|
||||||
- CLI: auto-migrate legacy config entries on command start (same behavior as gateway startup).
|
- CLI: auto-migrate legacy config entries on command start (same behavior as gateway startup).
|
||||||
|
- Auth: prioritize OAuth profiles but fall back to API keys when refresh fails; stored profiles now load without explicit auth order.
|
||||||
- Linux: auto-attempt lingering during onboarding (try without sudo, fallback to sudo) and prompt on install/restart to keep the gateway alive after logout/idle. Thanks @tobiasbischoff for PR #237.
|
- Linux: auto-attempt lingering during onboarding (try without sudo, fallback to sudo) and prompt on install/restart to keep the gateway alive after logout/idle. Thanks @tobiasbischoff for PR #237.
|
||||||
- TUI: migrate key handling to the updated pi-tui Key matcher API.
|
- TUI: migrate key handling to the updated pi-tui Key matcher API.
|
||||||
- Logging: redact sensitive tokens in verbose tool summaries by default (configurable patterns).
|
- Logging: redact sensitive tokens in verbose tool summaries by default (configurable patterns).
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ describe("resolveAuthProfileOrder", () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
it("returns empty order without explicit config", () => {
|
it("uses stored profiles when no config exists", () => {
|
||||||
const order = resolveAuthProfileOrder({
|
const order = resolveAuthProfileOrder({
|
||||||
store,
|
store,
|
||||||
provider: "anthropic",
|
provider: "anthropic",
|
||||||
});
|
});
|
||||||
expect(order).toEqual([]);
|
expect(order).toEqual(["anthropic:default", "anthropic:work"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prioritizes preferred profiles", () => {
|
it("prioritizes preferred profiles", () => {
|
||||||
@@ -80,4 +80,29 @@ describe("resolveAuthProfileOrder", () => {
|
|||||||
});
|
});
|
||||||
expect(order).toEqual(["anthropic:work", "anthropic:default"]);
|
expect(order).toEqual(["anthropic:work", "anthropic:default"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("prioritizes oauth profiles when order missing", () => {
|
||||||
|
const mixedStore: AuthProfileStore = {
|
||||||
|
version: 1,
|
||||||
|
profiles: {
|
||||||
|
"anthropic:default": {
|
||||||
|
type: "api_key",
|
||||||
|
provider: "anthropic",
|
||||||
|
key: "sk-default",
|
||||||
|
},
|
||||||
|
"anthropic:oauth": {
|
||||||
|
type: "oauth",
|
||||||
|
provider: "anthropic",
|
||||||
|
access: "access-token",
|
||||||
|
refresh: "refresh-token",
|
||||||
|
expires: Date.now() + 60_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const order = resolveAuthProfileOrder({
|
||||||
|
store: mixedStore,
|
||||||
|
provider: "anthropic",
|
||||||
|
});
|
||||||
|
expect(order).toEqual(["anthropic:oauth", "anthropic:default"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -258,10 +258,16 @@ export function resolveAuthProfileOrder(params: {
|
|||||||
.map(([profileId]) => profileId)
|
.map(([profileId]) => profileId)
|
||||||
: [];
|
: [];
|
||||||
const lastGood = store.lastGood?.[provider];
|
const lastGood = store.lastGood?.[provider];
|
||||||
const order =
|
const baseOrder =
|
||||||
configuredOrder ??
|
configuredOrder ??
|
||||||
(explicitProfiles.length > 0 ? explicitProfiles : undefined);
|
(explicitProfiles.length > 0
|
||||||
if (!order) return [];
|
? explicitProfiles
|
||||||
|
: listProfilesForProvider(store, provider));
|
||||||
|
if (baseOrder.length === 0) return [];
|
||||||
|
const order =
|
||||||
|
configuredOrder && configuredOrder.length > 0
|
||||||
|
? baseOrder
|
||||||
|
: orderProfilesByMode(baseOrder, store);
|
||||||
|
|
||||||
const filtered = order.filter((profileId) => {
|
const filtered = order.filter((profileId) => {
|
||||||
const cred = store.profiles[profileId];
|
const cred = store.profiles[profileId];
|
||||||
@@ -288,6 +294,20 @@ export function resolveAuthProfileOrder(params: {
|
|||||||
return deduped;
|
return deduped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function orderProfilesByMode(
|
||||||
|
order: string[],
|
||||||
|
store: AuthProfileStore,
|
||||||
|
): string[] {
|
||||||
|
const scored = order.map((profileId) => {
|
||||||
|
const type = store.profiles[profileId]?.type;
|
||||||
|
const score = type === "oauth" ? 0 : type === "api_key" ? 1 : 2;
|
||||||
|
return { profileId, score };
|
||||||
|
});
|
||||||
|
return scored
|
||||||
|
.sort((a, b) => a.score - b.score)
|
||||||
|
.map((entry) => entry.profileId);
|
||||||
|
}
|
||||||
|
|
||||||
export async function resolveApiKeyForProfile(params: {
|
export async function resolveApiKeyForProfile(params: {
|
||||||
cfg?: ClawdbotConfig;
|
cfg?: ClawdbotConfig;
|
||||||
store: AuthProfileStore;
|
store: AuthProfileStore;
|
||||||
|
|||||||
@@ -374,8 +374,11 @@ export async function compactEmbeddedPiSession(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const apiKey = await getApiKeyForModel(model, authStorage);
|
const apiKey = await getApiKeyForModel({
|
||||||
authStorage.setRuntimeApiKey(model.provider, apiKey);
|
model,
|
||||||
|
cfg: params.config,
|
||||||
|
});
|
||||||
|
authStorage.setRuntimeApiKey(model.provider, apiKey.apiKey);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
@@ -108,7 +108,9 @@ describe("sendMessageDiscord", () => {
|
|||||||
|
|
||||||
it("adds missing permission hints on 50013", async () => {
|
it("adds missing permission hints on 50013", async () => {
|
||||||
const { rest, postMock, getMock } = makeRest();
|
const { rest, postMock, getMock } = makeRest();
|
||||||
const perms = new PermissionsBitField([PermissionsBitField.Flags.ViewChannel]);
|
const perms = new PermissionsBitField([
|
||||||
|
PermissionsBitField.Flags.ViewChannel,
|
||||||
|
]);
|
||||||
const apiError = Object.assign(new Error("Missing Permissions"), {
|
const apiError = Object.assign(new Error("Missing Permissions"), {
|
||||||
code: 50013,
|
code: 50013,
|
||||||
status: 403,
|
status: 403,
|
||||||
|
|||||||
Reference in New Issue
Block a user