diff --git a/plugins/ai-psychosis/tests/privacy.test.mjs b/plugins/ai-psychosis/tests/privacy.test.mjs index 240dae5..a68fd8b 100644 --- a/plugins/ai-psychosis/tests/privacy.test.mjs +++ b/plugins/ai-psychosis/tests/privacy.test.mjs @@ -63,4 +63,87 @@ describe('privacy', () => { `Matched phrase "${matchedPhrase}" leaked — pattern name or trigger phrase written to disk` ); }); + + // v1.2 detector canaries — one per new detector category, plus matched-phrase + // variants for new pattern phrases that must never reach disk verbatim. + + it('user-info detector: yes_people canary never leaks', () => { + dir = setupTestDir(); + const matchedPhrase = 'my therapist'; + const canary = 'CANARY_USERINFO_PEOPLE_xyz123'; + const prompt = `${matchedPhrase} suggested I journal more — ${canary}`; + + runHook('session-start.mjs', { session_id: 'pv12a', cwd: '/tmp' }, dir); + runHook('prompt-analyzer.mjs', { session_id: 'pv12a', prompt }, dir); + runHook('tool-tracker.mjs', { session_id: 'pv12a', tool_name: 'Edit' }, dir); + runHook('session-end.mjs', { session_id: 'pv12a', cwd: '/tmp' }, dir); + + const allContent = readAllFiles(dir); + assert.ok(!allContent.includes(canary), + `Canary "${canary}" leaked through user-info detector`); + assert.ok(!allContent.toLowerCase().includes(matchedPhrase), + `Matched phrase "${matchedPhrase}" leaked through user-info detector`); + }); + + it('user-info detector: yes_digital canary never leaks', () => { + dir = setupTestDir(); + const matchedPhrase = 'I googled'; + const canary = 'CANARY_USERINFO_DIGITAL_xyz123'; + const prompt = `${matchedPhrase} this issue and got nothing — ${canary}`; + + runHook('session-start.mjs', { session_id: 'pv12b', cwd: '/tmp' }, dir); + runHook('prompt-analyzer.mjs', { session_id: 'pv12b', prompt }, dir); + runHook('session-end.mjs', { session_id: 'pv12b', cwd: '/tmp' }, dir); + + const allContent = readAllFiles(dir); + assert.ok(!allContent.includes(canary)); + assert.ok(!allContent.toLowerCase().includes(matchedPhrase.toLowerCase())); + }); + + it('user-info detector: "no" isolation canary never leaks', () => { + dir = setupTestDir(); + const matchedPhrase = "haven't told anyone"; + const canary = 'CANARY_USERINFO_NO_xyz123'; + const prompt = `I ${matchedPhrase} about it ${canary}`; + + runHook('session-start.mjs', { session_id: 'pv12c', cwd: '/tmp' }, dir); + runHook('prompt-analyzer.mjs', { session_id: 'pv12c', prompt }, dir); + runHook('session-end.mjs', { session_id: 'pv12c', cwd: '/tmp' }, dir); + + const allContent = readAllFiles(dir); + assert.ok(!allContent.includes(canary)); + assert.ok(!allContent.toLowerCase().includes(matchedPhrase)); + }); + + it('valseek detector canary never leaks', () => { + dir = setupTestDir(); + const matchedPhrase = 'am I crazy'; + const canary = 'CANARY_VALSEEK_xyz123'; + const prompt = `${matchedPhrase} for thinking this — ${canary}`; + + runHook('session-start.mjs', { session_id: 'pv12d', cwd: '/tmp' }, dir); + runHook('prompt-analyzer.mjs', { session_id: 'pv12d', prompt }, dir); + runHook('session-end.mjs', { session_id: 'pv12d', cwd: '/tmp' }, dir); + + const allContent = readAllFiles(dir); + assert.ok(!allContent.includes(canary)); + assert.ok(!allContent.toLowerCase().includes(matchedPhrase)); + }); + + it('domain detector (legal): canary never leaks despite domain hit', () => { + dir = setupTestDir(); + const matchedPhrase = 'my lawyer'; + const canary = 'CANARY_DOMAIN_LEGAL_xyz123'; + const prompt = `talked to ${matchedPhrase} about it ${canary}`; + + runHook('session-start.mjs', { session_id: 'pv12e', cwd: '/tmp' }, dir); + runHook('prompt-analyzer.mjs', { session_id: 'pv12e', prompt }, dir); + runHook('session-end.mjs', { session_id: 'pv12e', cwd: '/tmp' }, dir); + + const allContent = readAllFiles(dir); + assert.ok(!allContent.includes(canary), + `Canary "${canary}" leaked through legal domain detector`); + assert.ok(!allContent.toLowerCase().includes(matchedPhrase), + `Matched phrase "${matchedPhrase}" leaked through legal domain detector`); + }); });