test(ai-chat): cover safety-critical code paths (review follow-ups P1) #3
Closed
Ghost
wants to merge 1 commits from
test/ai-chat-safety-critical-coverage into develop
pull from: test/ai-chat-safety-critical-coverage
merge into: vvzvlad:develop
vvzvlad:main
vvzvlad:fix/embeddings-reindex-progress
vvzvlad:feat/git-sync
vvzvlad:feature/offline-sync
vvzvlad:feat/184-autonomous-agent-runs
vvzvlad:refactor/193-tool-spec-registry
vvzvlad:test/244-part-b
vvzvlad:fix/255-ws-redis-adapter-leak
vvzvlad:feat/251-intentional-clear
vvzvlad:fix/252-e2e-open-handles
vvzvlad:feat/221-image-captions
vvzvlad:fix/244-dataloss-bugs
vvzvlad:develop
vvzvlad:feat/229-catalog-yaml
vvzvlad:feat/243-blob-sandbox
vvzvlad:feat/228-inline-footnotes
vvzvlad:fix/qa-ui-bugs-216-218
vvzvlad:feature/agent-roles-catalog
vvzvlad:fix/share-alias-rename
vvzvlad:fix/ai-chat-empty-render
vvzvlad:feat/191-chat-doc-binding
vvzvlad:feat/201-temporary-notes
vvzvlad:feat/198-interrupt-agent
vvzvlad:feat/ai-chat-full-history
vvzvlad:feat/199-ai-generate-title
vvzvlad:feat/205-share-aliases
vvzvlad:batch/issues-189-187-170
vvzvlad:feat/170-mcp-test-button
vvzvlad:feat/189-context-badge
vvzvlad:feat/198-interrupt-agent-send-now
vvzvlad:fix/issues-190-159
vvzvlad:fix/ai-chat-new-chat-during-stream
vvzvlad:fix/ai-chat-stream-perf
vvzvlad:batch/issues-2026-06-25
vvzvlad:feat/ai-chat-persistent-history
vvzvlad:fix/ai-chat-copy-chat-wysiwyg
vvzvlad:fix/ai-stream-reset-resilience
vvzvlad:fix/ai-stream-undici-timeout
vvzvlad:fix/footnote-review-1227-followup
vvzvlad:fix/ai-chat-token-counter-realtime
vvzvlad:docs/manual-qa-test-plan
1 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b24fc12e2b |
test(ai-chat): cover safety-critical code paths (review follow-ups P1)
Adds unit tests for five pieces of security-critical code that previously had zero coverage, closing the warning-level findings of the ai-chat multi-aspect review (docs/backlog/ai-chat-review-followups.md, priority 1). - crypto/secret-box.spec.ts (NEW): AES-256-GCM round-trip; non-determinism (two encrypts of the same input yield different blobs, both decrypt); tampered authTag / ciphertext bytes throw with the 'APP_SECRET may have changed' message; wrong APP_SECRET throws the same. Guards the only at-rest protection of provider API keys. - ai-chat/external-mcp/ssrf-guard.spec.ts (NEW): isIpAllowed blocks every forbidden class (loopback, link-local incl. metadata 169.254.169.254, private, CGNAT, ULA, unspecified, IPv4-mapped IPv6, unparseable) and allows a public IP; isUrlAllowed rejects bad scheme / invalid URL, blocks IP-literal private, and (with a mocked dns.lookup) blocks DNS-rebinding to a private address and an unresolvable host. - ai-chat/ai-chat.service.spec.ts (extended): assistantParts now covered - paired tool call -> output-available (compacted), unpaired call -> output-error with 'Tool call did not complete.' (regression guard for the MissingToolResultsError fix), broken calls skipped, step text and fallback text paths. Requires exporting assistantParts + StepLike (the only production change here, two export keywords). - ai-chat/tools/ai-chat-tools.service.spec.ts (extended): JSON-string coercion in patchNode / insertNode / updatePageJson - string parsed to object, invalid JSON throws the specific message, updatePageJson distinguishes undefined (title-only) / object / string. Guards the OpenAI tool-call compatibility fix. - database/repos/ai-chat/page-embedding.repo.spec.ts (NEW): searchByEmbedding with empty spaceIds returns [] without touching the DB (Proxy stub throws on any access). Guards the access-scoping early-return. 54 new tests, all green. No functional behaviour changed. |