diff --git a/lana/src/commands/RetrieveLogFile.ts b/lana/src/commands/RetrieveLogFile.ts index 3757edba..29ab25e0 100644 --- a/lana/src/commands/RetrieveLogFile.ts +++ b/lana/src/commands/RetrieveLogFile.ts @@ -65,6 +65,7 @@ export class RetrieveLogFile { if (logFileId) { const logUri = this.getLogFileUri(Uri.parse(wsFolder.uri), logFileId); const logBody = await getLogBody(logFileId); + RetrieveLogFile.assertRetrievedLog(logFileId, logBody); try { await writeFile(logUri, logBody); @@ -163,4 +164,13 @@ export class RetrieveLogFile { // Utils.joinPath works on both desktop (file://) and web (vscode-vfs://, memfs://). return Utils.joinPath(wsUri, '.sfdx', 'tools', 'debug', 'logs', `${fileId}.log`); } + + private static assertRetrievedLog(logId: string, logBody: string): void { + if (/^accessdenied(?:access denied)?$/i.test(logBody.trim())) { + throw new Error( + `Salesforce denied access to the body of Apex log ${logId}. ` + + 'Verify that the authenticated user can access ApexLog records and their bodies.', + ); + } + } } diff --git a/lana/src/commands/__tests__/RetrieveLogFile.test.ts b/lana/src/commands/__tests__/RetrieveLogFile.test.ts index 77a4bed0..b5196d11 100644 --- a/lana/src/commands/__tests__/RetrieveLogFile.test.ts +++ b/lana/src/commands/__tests__/RetrieveLogFile.test.ts @@ -615,6 +615,34 @@ describe('RetrieveLogFile', () => { }); describe('safeCommand error handling', () => { + it('reports when Salesforce denies access to the selected log body', async () => { + mockListLogs.mockResolvedValue([ + { + Id: 'denied-log', + LogUser: { Name: 'User' }, + Operation: 'Op', + LogLength: 1024, + DurationMilliseconds: 100, + StartTime: '2024-01-01T00:00:00.000Z', + Status: 'Success', + }, + ]); + mockQuickPickPick.mockResolvedValue([{ logId: 'denied-log' }]); + mockGetLogBody.mockResolvedValue('AccessDeniedAccess Denied'); + + const mockContext = createMockContext(); + RetrieveLogFile.apply(mockContext as unknown as import('../../Context.js').Context); + + const lastCall = mockRegisterCommand.mock.calls[mockRegisterCommand.mock.calls.length - 1]; + await lastCall[1](); + + expect(mockContext.display.showErrorMessage).toHaveBeenCalledWith( + 'Error loading logfile: Salesforce denied access to the body of Apex log denied-log. ' + + 'Verify that the authenticated user can access ApexLog records and their bodies.', + ); + expect(mockCreateView).not.toHaveBeenCalled(); + }); + it('should catch Error and display error message', async () => { const mockContext = createMockContext(); RetrieveLogFile.apply(mockContext as unknown as import('../../Context.js').Context);