From bc8826af5614424f7742de74ac782f17f7b7848e Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Mon, 10 Aug 2026 11:03:24 -0700 Subject: [PATCH] test(provenance): cover the enforced branch of the agent memory surface (#6497) The agent's stored-memory read was the only durable-provenance check site with no test of its enforced path, and the only one whose control flow was restructured by hand. Pin both directions against the shape that failed in production: an unrecorded memory reads through and reports, and the same memory refuses once the memory surface is closed. Co-authored-by: Claude Opus 5 (1M context) --- .../executor/handlers/agent/memory.test.ts | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/apps/sim/executor/handlers/agent/memory.test.ts b/apps/sim/executor/handlers/agent/memory.test.ts index a345073fc8..e59a4c260b 100644 --- a/apps/sim/executor/handlers/agent/memory.test.ts +++ b/apps/sim/executor/handlers/agent/memory.test.ts @@ -1,9 +1,18 @@ import { loggerMock } from '@sim/testing' import { beforeEach, describe, expect, it, vi } from 'vitest' -const { mockDecryptSecret, mockRedactObjectStrings } = vi.hoisted(() => ({ - mockDecryptSecret: vi.fn(), - mockRedactObjectStrings: vi.fn(async (value: unknown) => value), +const { mockDecryptSecret, mockRedactObjectStrings, mockIsEnforced, mockReportUnrecorded } = + vi.hoisted(() => ({ + mockDecryptSecret: vi.fn(), + mockRedactObjectStrings: vi.fn(async (value: unknown) => value), + mockIsEnforced: vi.fn(() => false), + mockReportUnrecorded: vi.fn(), + })) + +vi.mock('@/lib/execution/durable-secret-provenance-enforcement', () => ({ + DURABLE_SECRET_PROVENANCE_SURFACES: ['memory', 'table-row', 'knowledge'], + isDurableSecretProvenanceEnforced: mockIsEnforced, + reportUnrecordedDurableProvenance: mockReportUnrecorded, })) vi.mock('@/lib/core/security/encryption', () => ({ @@ -35,6 +44,7 @@ describe('Memory', () => { beforeEach(() => { vi.clearAllMocks() + mockIsEnforced.mockReturnValue(false) mockDecryptSecret.mockImplementation(async (encryptedValue: string) => ({ decrypted: `decrypted:${encryptedValue}`, })) @@ -503,6 +513,48 @@ describe('Memory', () => { expect(messages).toEqual([retainedPublicMessage]) expect(mockDecryptSecret).not.toHaveBeenCalled() }) + + /** Trace 2's shape: a stored memory a previous run could not vouch for. */ + it('reads a memory with unrecorded provenance while the surface stays open', async () => { + const registry = new ResolvedSecretTraceRegistry([], { + userId: 'user-1', + workspaceId: 'workspace-1', + }) + vi.spyOn(memoryService as any, 'fetchMemory').mockResolvedValueOnce({ + messages: [{ role: 'user', content: 'how do i see my tickets?' }], + provenance: { status: 'unknown' }, + }) + + const messages = await memoryService.fetchMemoryMessages( + createContext(registry) as never, + inputs + ) + + expect(messages).toEqual([{ role: 'user', content: 'how do i see my tickets?' }]) + expect(registry.isPermanentlyIncomplete()).toBe(false) + expect(mockReportUnrecorded).toHaveBeenCalledWith({ + surface: 'memory', + cause: 'stored-memory-provenance-unknown', + workspaceId: 'workspace-1', + }) + }) + + it('refuses that same memory once the memory surface is closed', async () => { + mockIsEnforced.mockReturnValue(true) + const registry = new ResolvedSecretTraceRegistry([], { + userId: 'user-1', + workspaceId: 'workspace-1', + }) + vi.spyOn(memoryService as any, 'fetchMemory').mockResolvedValueOnce({ + messages: [{ role: 'user', content: 'how do i see my tickets?' }], + provenance: { status: 'unknown' }, + }) + + await expect( + memoryService.fetchMemoryMessages(createContext(registry) as never, inputs) + ).rejects.toThrow() + expect(mockReportUnrecorded).not.toHaveBeenCalled() + }) }) describe('secret-safe diagnostics', () => {