mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
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) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
52ee2a5c5c
commit
bc8826af56
@@ -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', () => {
|
||||
|
||||
Reference in New Issue
Block a user