From af5aaa40c51134172103d6b62a35a09ae7285718 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:14:33 +0000 Subject: [PATCH 1/3] Initial plan From 0a1adc74e4b2b9f95462cfa7dec071decc45fad6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:25:04 +0000 Subject: [PATCH 2/3] fix(vscode): throw when getAuthorizationToken has no accessToken Fixes review comment r3597382245 on PR #9406: - getAuthorizationToken now throws an error when accessToken is undefined/empty instead of returning '******' - Remove redundant optional chaining on the return statement - Add test file verifying the function throws (instead of the previous unsafe assertion toBe('******') on line 46) --- .../__test__/getAuthorizationToken.test.ts | 143 ++++++++++++++++++ .../utils/codeless/getAuthorizationToken.ts | 5 +- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts diff --git a/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts b/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts new file mode 100644 index 00000000000..e35e0f113b4 --- /dev/null +++ b/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts @@ -0,0 +1,143 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { getAuthorizationToken, getAuthorizationTokenFromNode, getCloudHost } from '../getAuthorizationToken'; + +// The module-level mock for '@microsoft/vscode-azext-azureauth/out/src/getSessionFromVSCode' +// is aliased via vitest.config.ts to '__mocks__/vscode-azext-azureauth.ts'. +// We import and spy on it to control return values per test. +import * as azureAuth from '@microsoft/vscode-azext-azureauth/out/src/getSessionFromVSCode'; +import * as vscode from 'vscode'; + +vi.mock('@microsoft/vscode-azext-azureauth', () => ({ + getConfiguredAzureEnv: vi.fn(() => ({ + managementEndpointUrl: 'https://management.azure.com', + })), +})); + +describe('getAuthorizationToken', () => { + beforeEach(() => { + vi.restoreAllMocks(); + // Mock vscode.workspace.getConfiguration to return a config with get() + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: vi.fn(() => false), + } as any); + }); + + it('should return a Bearer token when session has an accessToken', async () => { + vi.spyOn(azureAuth, 'getSessionFromVSCode').mockResolvedValue({ + accessToken: 'test-token-123', + id: 'session-1', + account: { id: 'account-1', label: 'Test' }, + scopes: [], + } as any); + + const token = await getAuthorizationToken('test-tenant'); + expect(token).toBe('Bearer test-token-123'); + }); + + it('should throw when session returns no accessToken', async () => { + vi.spyOn(azureAuth, 'getSessionFromVSCode').mockResolvedValue({ + id: 'session-1', + account: { id: 'account-1', label: 'Test' }, + scopes: [], + } as any); + + await expect(getAuthorizationToken()).rejects.toThrow(); + }); + + it('should propagate errors when session acquisition fails', async () => { + vi.spyOn(azureAuth, 'getSessionFromVSCode').mockRejectedValue(new Error('Auth session expired')); + + await expect(getAuthorizationToken()).rejects.toThrow('Auth session expired'); + }); + + it('should pass tenantId to getSessionFromVSCode', async () => { + const spy = vi.spyOn(azureAuth, 'getSessionFromVSCode').mockResolvedValue({ + accessToken: 'tenant-token', + id: 'session-1', + account: { id: 'account-1', label: 'Test' }, + scopes: [], + } as any); + + await getAuthorizationToken('specific-tenant-id'); + expect(spy).toHaveBeenCalledWith(undefined, 'specific-tenant-id', expect.any(Object)); + }); +}); + +describe('getAuthorizationTokenFromNode', () => { + beforeEach(() => { + vi.restoreAllMocks(); + vi.mocked(vscode.workspace.getConfiguration).mockReturnValue({ + get: vi.fn(() => false), + } as any); + }); + + it('should throw when node is null/undefined', async () => { + await expect(getAuthorizationTokenFromNode(null as any)).rejects.toThrow(); + }); + + it('should throw when node has no subscription', async () => { + const node = {} as any; + await expect(getAuthorizationTokenFromNode(node)).rejects.toThrow(); + }); + + it('should return Bearer token from node subscription credentials', async () => { + const node = { + subscription: { + tenantId: 'tenant-1', + credentials: { + getToken: vi.fn().mockResolvedValue({ token: 'node-token-abc' }), + }, + }, + } as any; + + const token = await getAuthorizationTokenFromNode(node); + expect(token).toBe('Bearer node-token-abc'); + }); + + it('should fall back to getAuthorizationToken when credentials.getToken returns null', async () => { + vi.spyOn(azureAuth, 'getSessionFromVSCode').mockResolvedValue({ + accessToken: 'fallback-token', + id: 'session-1', + account: { id: 'account-1', label: 'Test' }, + scopes: [], + } as any); + + const node = { + subscription: { + tenantId: 'tenant-1', + credentials: { + getToken: vi.fn().mockResolvedValue(null), + }, + }, + } as any; + + const token = await getAuthorizationTokenFromNode(node); + expect(token).toBe('Bearer fallback-token'); + }); + + it('should fall back to getAuthorizationToken when no credentials exist', async () => { + vi.spyOn(azureAuth, 'getSessionFromVSCode').mockResolvedValue({ + accessToken: 'fallback-token-2', + id: 'session-1', + account: { id: 'account-1', label: 'Test' }, + scopes: [], + } as any); + + const node = { + subscription: { + tenantId: 'tenant-2', + credentials: undefined, + }, + } as any; + + const token = await getAuthorizationTokenFromNode(node); + expect(token).toBe('Bearer fallback-token-2'); + }); +}); + +describe('getCloudHost', () => { + it('should return the managementEndpointUrl from configured environment', async () => { + const host = await getCloudHost(); + expect(host).toBe('https://management.azure.com'); + }); +}); diff --git a/apps/vs-code-designer/src/app/utils/codeless/getAuthorizationToken.ts b/apps/vs-code-designer/src/app/utils/codeless/getAuthorizationToken.ts index f581c4ad3a5..bebac41bee1 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/getAuthorizationToken.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/getAuthorizationToken.ts @@ -18,7 +18,10 @@ export async function getAuthData(tenantId?: string): Promise { const authData = await getAuthData(tenantId); - return `Bearer ${authData?.accessToken}`; + if (!authData?.accessToken) { + throw new Error(localize('noAccessToken', 'No access token available. Please sign in to Azure.')); + } + return `Bearer ${authData.accessToken}`; } /** From 886a97165091d0803ff1ea21a7e3eb300d43f984 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:25:44 +0000 Subject: [PATCH 3/3] fix(vscode): verify specific error message in no-accessToken test --- .../app/utils/codeless/__test__/getAuthorizationToken.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts b/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts index e35e0f113b4..5cb4f0521d9 100644 --- a/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts +++ b/apps/vs-code-designer/src/app/utils/codeless/__test__/getAuthorizationToken.test.ts @@ -41,7 +41,7 @@ describe('getAuthorizationToken', () => { scopes: [], } as any); - await expect(getAuthorizationToken()).rejects.toThrow(); + await expect(getAuthorizationToken()).rejects.toThrow('No access token available'); }); it('should propagate errors when session acquisition fails', async () => {