@@ -25,6 +25,7 @@ import {
2525 setEnvFlags ,
2626} from '@sim/testing'
2727import { sleep } from '@sim/utils/helpers'
28+ import { DrizzleQueryError } from 'drizzle-orm/errors'
2829import { afterAll , afterEach , beforeAll , beforeEach , describe , expect , it , vi } from 'vitest'
2930import type { BillingAttributionSnapshot } from '@/lib/billing/core/billing-attribution'
3031import { projectToolResultForCopilot } from '@/lib/copilot/request/tools/resolved-secret-result'
@@ -54,6 +55,7 @@ const {
5455 mockGenerateInternalDelegationToken,
5556 mockGenerateInternalToken,
5657 mockResolveWorkspaceFileReference,
58+ mockAssertPermissionsAllowed,
5759} = vi . hoisted ( ( ) => ( {
5860 mockGetBYOKKey : vi . fn ( ) ,
5961 mockGetToolAsync : vi . fn ( ) ,
@@ -71,6 +73,7 @@ const {
7173 mockGenerateInternalDelegationToken : vi . fn ( ) ,
7274 mockGenerateInternalToken : vi . fn ( ) ,
7375 mockResolveWorkspaceFileReference : vi . fn ( ) ,
76+ mockAssertPermissionsAllowed : vi . fn ( ) ,
7477} ) )
7578
7679const mockSecureFetchWithPinnedIP = inputValidationMockFns . mockSecureFetchWithPinnedIP
@@ -94,7 +97,7 @@ vi.mock('@/lib/core/security/encryption', () => ({
9497} ) )
9598
9699vi . mock ( '@/ee/access-control/utils/permission-check' , ( ) => ( {
97- assertPermissionsAllowed : vi . fn ( ) . mockResolvedValue ( undefined ) ,
100+ assertPermissionsAllowed : mockAssertPermissionsAllowed ,
98101 validateBlockType : vi . fn ( ) . mockResolvedValue ( undefined ) ,
99102 validateMcpToolsAllowed : vi . fn ( ) . mockResolvedValue ( undefined ) ,
100103 validateCustomToolsAllowed : vi . fn ( ) . mockResolvedValue ( undefined ) ,
@@ -460,6 +463,7 @@ vi.spyOn(getQueryClientModule, 'getQueryClient').mockImplementation(createMockQu
460463
461464beforeEach ( ( ) => {
462465 vi . spyOn ( getQueryClientModule , 'getQueryClient' ) . mockImplementation ( createMockQueryClient )
466+ mockAssertPermissionsAllowed . mockResolvedValue ( undefined )
463467 mockGenerateInternalDelegationToken . mockResolvedValue ( 'executor-token' )
464468 mockRunWorkflowTool . mockResolvedValue ( { success : true , output : { } } )
465469 // Suites below call vi.resetAllMocks(), which wipes the shared env/urls mock
@@ -692,6 +696,53 @@ describe('executeTool Function', () => {
692696 tools . function_execute = originalFunctionTool
693697 } )
694698
699+ it ( 'logs database query diagnostics without exposing query details to the caller' , async ( ) => {
700+ const driverError = Object . assign ( new Error ( 'read ECONNRESET' ) , {
701+ code : 'ECONNRESET' ,
702+ errno : 'ECONNRESET' ,
703+ syscall : 'read' ,
704+ } )
705+ const databaseError = new DrizzleQueryError (
706+ 'select "id" from "workspace" where "workspace"."id" = $1 limit $2' ,
707+ [ 'workspace-secret-id' , 1 ] ,
708+ driverError
709+ )
710+ mockAssertPermissionsAllowed . mockRejectedValueOnce ( databaseError )
711+ mockToolsLogger . error . mockClear ( )
712+
713+ const result = await executeTool (
714+ 'function_execute' ,
715+ { code : 'return 1' } ,
716+ { executionContext : createToolExecutionContext ( { userId : 'user-123' } ) }
717+ )
718+
719+ expect ( result . success ) . toBe ( false )
720+ expect ( result . error ) . toBe (
721+ 'An internal error occurred while executing the tool. Please try again.'
722+ )
723+ expect ( JSON . stringify ( result ) ) . not . toContain ( 'Failed query' )
724+ expect ( JSON . stringify ( result ) ) . not . toContain ( 'workspace-secret-id' )
725+ expect ( global . fetch ) . not . toHaveBeenCalled ( )
726+
727+ const loggedError = mockToolsLogger . error . mock . calls . at ( - 1 ) ?. [ 1 ]
728+ expect ( loggedError ) . toEqual (
729+ expect . objectContaining ( {
730+ cause : expect . objectContaining ( {
731+ name : 'Error' ,
732+ message : 'read ECONNRESET' ,
733+ code : 'ECONNRESET' ,
734+ errno : 'ECONNRESET' ,
735+ syscall : 'read' ,
736+ causeChain : expect . arrayContaining ( [
737+ expect . stringContaining ( 'params: [redacted]' ) ,
738+ 'Error: read ECONNRESET' ,
739+ ] ) ,
740+ } ) ,
741+ } )
742+ )
743+ expect ( JSON . stringify ( loggedError ) ) . not . toContain ( 'workspace-secret-id' )
744+ } )
745+
695746 it ( 'should call internal routes directly' , async ( ) => {
696747 const originalFunctionTool = { ...tools . function_execute }
697748 tools . function_execute = {
0 commit comments