learning_ai_notes/backend/src/lib/encryption-coverage.test.ts

135 lines
5.2 KiB
TypeScript

import { beforeEach, describe, expect, it } from 'vitest';
import { isEncryptedField } from '@bytelyst/field-encrypt';
import { getCollection } from './datastore.js';
import { _resetEncryptor } from './field-encrypt.js';
import { resetMemoryDatastore } from '../test-helpers.js';
import { createNoteArtifact, getNoteArtifact } from '../modules/note-artifacts/repository.js';
import type { NoteArtifactDoc } from '../modules/note-artifacts/types.js';
import { createPromptTemplate, getPromptTemplate } from '../modules/note-prompts/repository.js';
import type { PromptTemplateDoc } from '../modules/note-prompts/types.js';
import {
createNoteAgentAction,
getNoteAgentAction,
updateNoteAgentAction,
} from '../modules/note-agent-actions/repository.js';
import type { NoteAgentActionDoc } from '../modules/note-agent-actions/types.js';
describe('field encryption coverage', () => {
beforeEach(() => {
resetMemoryDatastore();
_resetEncryptor();
});
it('encrypts sensitive artifact metadata while returning plaintext to callers', async () => {
const created = await createNoteArtifact({
id: 'artifact-1',
productId: 'notelett',
workspaceId: 'ws-1',
userId: 'user-1',
noteId: 'note-1',
artifactType: 'summary',
title: 'Private summary',
description: 'Sensitive extracted summary',
blobPath: 'notelett/user-1/private-summary.md',
contentType: 'text/markdown',
createdAt: '2026-05-05T00:00:00.000Z',
createdBy: 'user-1',
updatedAt: '2026-05-05T00:00:00.000Z',
updatedBy: 'user-1',
});
expect(created.title).toBe('Private summary');
expect(created.description).toBe('Sensitive extracted summary');
const raw = await getCollection<NoteArtifactDoc>('note_artifacts', '/workspaceId').findById('artifact-1', 'ws-1');
expect(isEncryptedField(raw?.title)).toBe(true);
expect(isEncryptedField(raw?.description)).toBe(true);
expect(isEncryptedField(raw?.blobPath)).toBe(true);
const fetched = await getNoteArtifact('artifact-1', 'ws-1');
expect(fetched).toMatchObject({
title: 'Private summary',
description: 'Sensitive extracted summary',
blobPath: 'notelett/user-1/private-summary.md',
});
});
it('encrypts custom prompt content while preserving slug lookup', async () => {
const created = await createPromptTemplate('user-1', {
slug: 'private-template',
name: 'Private Template',
description: 'Internal reasoning instructions',
systemPrompt: 'Use confidential house style.',
userPromptTemplate: 'Rewrite {{note}} for leadership.',
inputType: 'text',
outputType: 'new_note',
category: 'transform',
requiresApproval: true,
});
expect(created.systemPrompt).toBe('Use confidential house style.');
expect(created.userPromptTemplate).toBe('Rewrite {{note}} for leadership.');
const raw = await getCollection<PromptTemplateDoc>('note_prompts', '/userId').findById(created.id, 'user-1');
expect(raw?.slug).toBe('private-template');
expect(isEncryptedField(raw?.description)).toBe(true);
expect(isEncryptedField(raw?.systemPrompt)).toBe(true);
expect(isEncryptedField(raw?.userPromptTemplate)).toBe(true);
const fetched = await getPromptTemplate(created.id, 'user-1');
expect(fetched).toMatchObject({
slug: 'private-template',
description: 'Internal reasoning instructions',
systemPrompt: 'Use confidential house style.',
userPromptTemplate: 'Rewrite {{note}} for leadership.',
});
});
it('encrypts agent action details and review notes while preserving query metadata', async () => {
await createNoteAgentAction({
id: 'action-1',
productId: 'notelett',
workspaceId: 'ws-1',
userId: 'user-1',
noteId: 'note-1',
actorId: 'agent-1',
actorType: 'agent',
toolName: 'notes.notes.update',
actionType: 'update',
state: 'proposed',
reason: 'Agent proposed a sensitive rewrite',
beforeSummary: 'Original private note',
afterSummary: 'Rewritten private note',
idempotencyKey: 'idem-1',
correlationId: 'corr-1',
createdAt: '2026-05-05T00:00:00.000Z',
createdBy: 'user-1',
updatedAt: '2026-05-05T00:00:00.000Z',
updatedBy: 'user-1',
});
await updateNoteAgentAction('action-1', 'ws-1', {
state: 'approved',
reviewNote: 'Approved after private review',
updatedAt: '2026-05-05T01:00:00.000Z',
updatedBy: 'user-1',
});
const raw = await getCollection<NoteAgentActionDoc>('note_agent_actions', '/workspaceId').findById('action-1', 'ws-1');
expect(raw?.toolName).toBe('notes.notes.update');
expect(raw?.idempotencyKey).toBe('idem-1');
expect(isEncryptedField(raw?.reason)).toBe(true);
expect(isEncryptedField(raw?.beforeSummary)).toBe(true);
expect(isEncryptedField(raw?.afterSummary)).toBe(true);
expect(isEncryptedField(raw?.reviewNote)).toBe(true);
const fetched = await getNoteAgentAction('action-1', 'ws-1');
expect(fetched).toMatchObject({
reason: 'Agent proposed a sensitive rewrite',
beforeSummary: 'Original private note',
afterSummary: 'Rewritten private note',
reviewNote: 'Approved after private review',
});
});
});