fix(microsoft-foundry): replace unsafe non-null assertion in subscription lookup (#62742)

subs.find() can return undefined if the selected subscription ID does not match any enabled subscription. Replace the unsafe non-null assertion with an explicit guard and descriptive error.

Co-authored-by: oliviareid-svg <oliviareid@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
oliviareid-svg
2026-05-11 16:59:34 +08:00
committed by GitHub
parent 1bf6bd33b5
commit 337f1b2a42
3 changed files with 56 additions and 1 deletions

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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);