From c835f93feeaf8b417d0a12f1dff2b57e01a7c5b9 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 22 May 2026 08:32:26 -0700 Subject: [PATCH] test(e2e): update multi-source-bug-class validateSourceId expectations for strict regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v0.32.8 test pinned the OLD permissive ^[a-z0-9_-]+$ behavior including the underscored case 'jarvis_memory'. The v0.38 wave (this PR's E2 + codex P1-D) tightens validateSourceId to the strict kebab regex shared with sources-ops. 'jarvis_memory' now lives in the rejected set, not the allowed set. Updated the test to assert the new contract: - Replaced 'jarvis_memory' allowed case with 'jarvis-memory' (kebab) - Added 'a' (single-char) to allowed cases - Added 'jarvis_memory', 'snake_case', '-leading', 'trailing-', and a 33-char string to the rejected cases — the v0.38 strict-regex additions Comment explains the contract shift so future readers don't see the test as flapping intent. Found by running the main E2E suite — the test file is in the canonical e2e set and would have failed CI otherwise. Co-Authored-By: Claude Opus 4.7 (1M context) --- test/e2e/multi-source-bug-class.test.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/test/e2e/multi-source-bug-class.test.ts b/test/e2e/multi-source-bug-class.test.ts index cd713f123..f106a820f 100644 --- a/test/e2e/multi-source-bug-class.test.ts +++ b/test/e2e/multi-source-bug-class.test.ts @@ -156,12 +156,20 @@ describe('multi-source bug class', () => { }); test('validateSourceId rejects path traversal (F6)', () => { - // Allowed + // v0.38 (codex P1-D + eng E2): regex TIGHTENED from permissive + // ^[a-z0-9_-]+$ to strict kebab ^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$. + // Underscores no longer allowed at the path-safety gate (matches + // what sources-ops always rejected at creation time). 'jarvis_memory' + // was a v0.32.8 permissive-regex test case; now lives in the + // rejected set. Path-traversal rejection unchanged. + // + // Allowed (strict kebab): expect(() => validateSourceId('default')).not.toThrow(); expect(() => validateSourceId('media-corpus')).not.toThrow(); - expect(() => validateSourceId('jarvis_memory')).not.toThrow(); + expect(() => validateSourceId('jarvis-memory')).not.toThrow(); expect(() => validateSourceId('abc123')).not.toThrow(); - // Rejected + expect(() => validateSourceId('a')).not.toThrow(); + // Rejected — path traversal / unsafe chars: expect(() => validateSourceId('..')).toThrow(); expect(() => validateSourceId('../etc')).toThrow(); expect(() => validateSourceId('foo/bar')).toThrow(); @@ -169,6 +177,13 @@ describe('multi-source bug class', () => { expect(() => validateSourceId('Default')).toThrow(); // uppercase expect(() => validateSourceId('.hidden')).toThrow(); expect(() => validateSourceId('')).toThrow(); + // Rejected — strict regex additions (v0.38): + expect(() => validateSourceId('jarvis_memory')).toThrow(); // underscores + expect(() => validateSourceId('snake_case')).toThrow(); + expect(() => validateSourceId('-leading')).toThrow(); // edge hyphen + expect(() => validateSourceId('trailing-')).toThrow(); + const tooLong = 'a' + 'b'.repeat(31) + 'c'; // 33 chars + expect(() => validateSourceId(tooLong)).toThrow(); }); test('reverse-write disk layout uses .sources//.md for non-default (F6)', () => {