test(ai-chat): safety-critical coverage + a11y + pure refactors

Unit tests for the safety-critical paths: crypto secret-box (round-trip,
tamper detection, wrong key), the SSRF guard (blocked ranges + DNS-rebinding),
the ai-chat tools service, the page-embedding repo, and the
assistant-parts/serialization helpers. Those server helpers (assistantParts,
rowToUiMessage, serializeSteps) are exported ONLY for the tests — no runtime
change.

Also: keyboard a11y on the chat history header and conversation rows
(role/tabIndex/Enter+Space), and DRY refactors that move shared logic into one
place (isToolPart -> tool-parts util; buildInitialValues in the MCP form).

The behaviour-changing edits that previously rode along in this commit are
split out into the following two commits, per review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-20 17:58:44 +03:00
committed by vvzvlad
parent c8af637654
commit f1980cf425
13 changed files with 571 additions and 236 deletions

View File

@@ -0,0 +1,26 @@
import { PageEmbeddingRepo } from './page-embedding.repo';
import type { KyselyDB } from '../../types/kysely.types';
/**
* Unit test for the pure access-scoping branch of searchByEmbedding: when the
* caller has NO accessible spaces (`spaceIds` empty), the method must early-
* return [] WITHOUT touching the database. We inject a db whose query builder
* throws if invoked, so any DB access fails the test.
*
* NOTE: the dimension-mixing case (filter by model_dimensions) needs a live
* pgvector-enabled Postgres and is intentionally NOT covered here — it requires
* a real DB and is out of scope for this pure unit test.
*/
describe('PageEmbeddingRepo.searchByEmbedding', () => {
it('early-returns [] for empty spaceIds without any DB call', async () => {
const throwingDb = {
selectFrom: () => {
throw new Error('DB should not be queried for empty spaceIds');
},
} as unknown as KyselyDB;
const repo = new PageEmbeddingRepo(throwingDb);
const result = await repo.searchByEmbedding('ws-1', [0.1, 0.2, 0.3], [], 10);
expect(result).toEqual([]);
});
});