mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 16:54:46 +00:00
fix(foundry): wrap malformed az token json
This commit is contained in:
@@ -53,6 +53,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Twilio voice-call: report malformed successful API JSON responses with provider-owned errors instead of leaking raw parser failures.
|
||||
- Voice-call provider APIs: report malformed successful guarded JSON responses with provider-prefixed errors instead of leaking raw parser failures.
|
||||
- Realtime transcription: report malformed provider websocket JSON frames with owned parser errors instead of leaking raw `SyntaxError` objects.
|
||||
- Microsoft Foundry: report malformed Azure CLI token JSON with owned auth errors instead of leaking raw parser failures.
|
||||
- Models config/auth: stop inferring provider env-var markers from broad `^[A-Z_][A-Z0-9_]*$` strings, and resolve config-backed provider `apiKey` values only through structured env SecretRefs (`secrets.providers[id]` / `secrets.defaults`), so unrelated env vars cannot accidentally become provider credentials. Thanks @sallyom.
|
||||
- Media fetch: skip allocating and buffering the response body for bodyless media responses (HEAD probes and 204-style empty bodies), avoiding wasted heap on streams that carry no payload. Thanks @shakkernerd.
|
||||
- CLI/onboarding: forward provider-specific auth flags (e.g. `--openai-api-key`) through the onboarding wizard so they reach provider auth methods via `ctx.opts`, letting `--openai-api-key "$OPENAI_API_KEY"` skip the redundant "use existing env var?" prompt in non-interactive harnesses. (#81669) Thanks @sjf.
|
||||
|
||||
@@ -85,7 +85,7 @@ export function isAzCliInstalled(): boolean {
|
||||
|
||||
export function getLoggedInAccount(): AzAccount | null {
|
||||
try {
|
||||
return JSON.parse(execAz(["account", "show", "--output", "json"])) as AzAccount;
|
||||
return parseAzJson(execAz(["account", "show", "--output", "json"]), "account") as AzAccount;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
@@ -93,8 +93,9 @@ export function getLoggedInAccount(): AzAccount | null {
|
||||
|
||||
export function listSubscriptions(): AzAccount[] {
|
||||
try {
|
||||
const subs = JSON.parse(
|
||||
const subs = parseAzJson(
|
||||
execAz(["account", "list", "--output", "json", "--all"]),
|
||||
"subscriptions",
|
||||
) as AzAccount[];
|
||||
return subs.filter((sub) => sub.state === "Enabled");
|
||||
} catch {
|
||||
@@ -102,6 +103,14 @@ export function listSubscriptions(): AzAccount[] {
|
||||
}
|
||||
}
|
||||
|
||||
function parseAzJson(raw: string, label: string): unknown {
|
||||
try {
|
||||
return JSON.parse(raw) as unknown;
|
||||
} catch {
|
||||
throw new Error(`Azure CLI returned malformed ${label} JSON.`);
|
||||
}
|
||||
}
|
||||
|
||||
type AccessTokenParams = {
|
||||
subscriptionId?: string;
|
||||
tenantId?: string;
|
||||
@@ -125,13 +134,16 @@ function buildAccessTokenArgs(params?: AccessTokenParams): string[] {
|
||||
}
|
||||
|
||||
export function getAccessTokenResult(params?: AccessTokenParams): AzAccessToken {
|
||||
return JSON.parse(execAz(buildAccessTokenArgs(params))) as AzAccessToken;
|
||||
return parseAzJson(execAz(buildAccessTokenArgs(params)), "access token") as AzAccessToken;
|
||||
}
|
||||
|
||||
export async function getAccessTokenResultAsync(
|
||||
params?: AccessTokenParams,
|
||||
): Promise<AzAccessToken> {
|
||||
return JSON.parse(await execAzAsync(buildAccessTokenArgs(params))) as AzAccessToken;
|
||||
return parseAzJson(
|
||||
await execAzAsync(buildAccessTokenArgs(params)),
|
||||
"access token",
|
||||
) as AzAccessToken;
|
||||
}
|
||||
|
||||
export async function azLoginDeviceCode(): Promise<void> {
|
||||
|
||||
@@ -235,6 +235,19 @@ function mockAzureCliToken(params: { accessToken: string; expiresInMs: number; d
|
||||
);
|
||||
}
|
||||
|
||||
function mockAzureCliTokenRaw(stdout: string) {
|
||||
execFileMock.mockImplementationOnce(
|
||||
(
|
||||
_file: unknown,
|
||||
_args: unknown,
|
||||
_options: unknown,
|
||||
callback: (error: Error | null, stdout: string, stderr: string) => void,
|
||||
) => {
|
||||
callback(null, stdout, "");
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function mockAzureCliLoginFailure(delayMs?: number) {
|
||||
execFileMock.mockImplementationOnce(
|
||||
(
|
||||
@@ -306,6 +319,14 @@ describe("microsoft-foundry plugin", () => {
|
||||
expect(config.auth?.order?.["microsoft-foundry"]).toEqual(["microsoft-foundry:default"]);
|
||||
});
|
||||
|
||||
it("reports malformed Azure CLI token JSON with an owned error", async () => {
|
||||
mockAzureCliTokenRaw("{not json");
|
||||
|
||||
await expect(getAccessTokenResultAsync()).rejects.toThrow(
|
||||
"Azure CLI returned malformed access token JSON.",
|
||||
);
|
||||
});
|
||||
|
||||
it("fails clearly when the selected Azure subscription is not in the enabled list", async () => {
|
||||
const provider = registerProvider();
|
||||
execFileSyncMock.mockImplementation((_file: string, args: string[]) => {
|
||||
|
||||
Reference in New Issue
Block a user