diff --git a/CHANGELOG.md b/CHANGELOG.md index c65fb463637..e4aa91230d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ Docs: https://docs.openclaw.ai - OpenAI Codex: surface browser OAuth and device-code login failures instead of treating failed logins as empty successful auth results. Refs #80363. - CLI agents: carry runtime-only current-turn sender/reply context into CLI model prompts while keeping prompt-build hook input and transcript text clean. - Control UI: keep workspace file presence checks from treating `fs-safe` stat helper failures as missing files, restoring Agents file status for existing Windows workspace files. Fixes #79953. Thanks @lovelefeng-glitch. +- Microsoft Foundry: report an explicit error when the Azure subscription prompt returns an id that is not present in the enabled subscription list, instead of continuing from an unsafe subscription assertion. (#62742) Thanks @oliviareid-svg. - fix(matrix): gate name-based allowlist resolution [AI]. (#79007) Thanks @pgondhi987. - Slack: include the bot's own root/parent message in new thread sessions so in-thread replies reach the agent with the parent text the user is responding to, instead of only `reply_to_id` metadata. Fixes #79338. Thanks @sxxtony. - Docker: keep image builds on the source pnpm workspace policy so pnpm 11 can prune production dependencies without a Docker-only workspace rewrite. diff --git a/extensions/microsoft-foundry/auth.ts b/extensions/microsoft-foundry/auth.ts index b58f6011403..691a6dde7e2 100644 --- a/extensions/microsoft-foundry/auth.ts +++ b/extensions/microsoft-foundry/auth.ts @@ -98,7 +98,11 @@ export const entraIdAuthMethod: ProviderAuthMethod = { label: `${sub.name} (${sub.id})`, })), }); - selectedSub = subs.find((sub) => sub.id === selectedId)!; + const match = subs.find((sub) => sub.id === selectedId); + if (!match) { + throw new Error(`Selected subscription not found: ${selectedId}`); + } + selectedSub = match; tenantId ??= selectedSub.tenantId; } diff --git a/extensions/microsoft-foundry/index.test.ts b/extensions/microsoft-foundry/index.test.ts index 6672da44e59..5f40df1fb6a 100644 --- a/extensions/microsoft-foundry/index.test.ts +++ b/extensions/microsoft-foundry/index.test.ts @@ -306,6 +306,56 @@ describe("microsoft-foundry plugin", () => { expect(config.auth?.order?.["microsoft-foundry"]).toEqual(["microsoft-foundry:default"]); }); + it("fails clearly when the selected Azure subscription is not in the enabled list", async () => { + const provider = registerProvider(); + execFileSyncMock.mockImplementation((_file: string, args: string[]) => { + const command = args.join(" "); + if (command === "version --output none") { + return ""; + } + if (command === "account show --output json") { + return JSON.stringify({ + id: "sub-one", + name: "Subscription One", + tenantId: "tenant-one", + state: "Enabled", + user: { name: "user@example.com" }, + }); + } + if (command === "account list --output json --all") { + return JSON.stringify([ + { + id: "sub-one", + name: "Subscription One", + tenantId: "tenant-one", + state: "Enabled", + }, + { + id: "sub-two", + name: "Subscription Two", + tenantId: "tenant-one", + state: "Enabled", + }, + ]); + } + throw new Error(`unexpected az command: ${command}`); + }); + const entraAuth = provider.auth.find((method: { id: string }) => method.id === "entra-id"); + + await expect( + entraAuth?.run({ + config: {}, + agentDir: defaultFoundryAgentDir, + opts: {}, + prompter: { + confirm: vi.fn(async () => true), + select: vi.fn(async () => "missing-subscription"), + note: vi.fn(async () => undefined), + }, + } as never), + ).rejects.toThrow("Selected subscription not found: missing-subscription"); + }); + it("preserves the model-derived base URL for Entra runtime auth refresh", async () => { const provider = registerProvider(); const prepareRuntimeAuth = requirePrepareRuntimeAuth(provider);