fix(test): pin SSE sanitizer wiring to the v1.51 createSseEndpoint helper

The two `wiring invariants` tests grepped server.ts for
`JSON.stringify(entry, sanitizeReplacer)` and
`JSON.stringify(event, sanitizeReplacer)` — patterns that lived inline
in /activity/stream and /inspector/events before the v1.51 refactor
moved both endpoints behind createSseEndpoint. Sanitization still
happens (the helper applies it inside its send() and live-event
callback), but the static-grep was pinned to the old wiring and started
failing on Windows free-tests after the refactor landed.

Updated to check the new contract:
- /activity/stream + /inspector/events route through createSseEndpoint
  (regex match of the route handler block ending in the helper call).
- sse-helpers.ts contains JSON.stringify + sanitizeReplacer + imports
  stripLoneSurrogates from ./sanitize (catches drift to a private copy).
- server.ts retains its own sanitizeReplacer for non-SSE egress paths
  (handleCommandInternal); the two replacers coexist by design.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan 2026-05-27 08:52:17 -07:00
parent e425a63a07
commit 163f9e3d19
No known key found for this signature in database
GPG Key ID: C1F69E85C74EFE1D
1 changed files with 35 additions and 7 deletions

View File

@ -113,17 +113,45 @@ describe('sanitizeLoneSurrogates — wiring invariants', () => {
expect(SERVER_SRC).toContain('result: sanitizeLoneSurrogates(cr.result)');
});
test('SSE activity feed sanitizes outbound frames via sanitizeReplacer', () => {
// Replacer must run DURING stringify; post-stringify regex is ineffective
// because JSON.stringify converts \uD800 → "\\ud800" before our regex sees it.
expect(SERVER_SRC).toContain('JSON.stringify(entry, sanitizeReplacer)');
test('SSE activity feed routes outbound frames through createSseEndpoint', () => {
// v1.51 refactor: /activity/stream no longer inlines its own
// ReadableStream/sanitizer wiring; it routes through createSseEndpoint
// which applies sanitizeReplacer to every JSON.stringify. The grep
// pins both halves of the contract: the endpoint uses the helper,
// and the helper does the sanitization.
const activityBlock = SERVER_SRC.match(
/if \(url\.pathname === '\/activity\/stream'\)[\s\S]*?createSseEndpoint\(/,
);
expect(activityBlock).not.toBeNull();
});
test('SSE inspector stream sanitizes outbound frames via sanitizeReplacer', () => {
expect(SERVER_SRC).toContain('JSON.stringify(event, sanitizeReplacer)');
test('SSE inspector stream routes outbound frames through createSseEndpoint', () => {
// Same v1.51 refactor invariant for /inspector/events.
const inspectorBlock = SERVER_SRC.match(
/if \(url\.pathname === '\/inspector\/events'[\s\S]*?createSseEndpoint\(/,
);
expect(inspectorBlock).not.toBeNull();
});
test('sanitizeReplacer is a function defined in server.ts', () => {
test('createSseEndpoint applies sanitizeReplacer to every JSON.stringify', () => {
// The helper is the single source of truth for SSE sanitization now.
// If a future refactor moves stringify off the replacer (e.g. someone
// adds a fast-path encode), this test fails and the surrogate-escape
// class regresses across every SSE endpoint at once.
const helperPath = path.resolve(import.meta.dir, '..', 'src', 'sse-helpers.ts');
const helperSrc = fs.readFileSync(helperPath, 'utf-8');
expect(helperSrc).toContain('JSON.stringify(');
expect(helperSrc).toContain('sanitizeReplacer');
// The sanitizer itself uses stripLoneSurrogates (the shared utility in
// sanitize.ts) — not a private copy. Re-confirms the helper is wired
// to the canonical sanitizer, not a drift'd duplicate.
expect(helperSrc).toContain("import { stripLoneSurrogates } from './sanitize'");
});
test('sanitizeReplacer is a function defined in server.ts (for non-SSE egress)', () => {
// server.ts keeps its own sanitizeReplacer for the non-SSE JSON egress
// paths (handleCommandInternal etc.). The SSE path uses sse-helpers.ts's
// own sanitizeReplacer; both must exist independently.
expect(SERVER_SRC).toContain('function sanitizeReplacer(');
});
});