test(15-02): add failing tests for phishing pattern matcher + content hash
- Covers all 8 locked DETECT-01 patterns individually, negative case, case-insensitivity, and content-hash stability/change/null-normalization
This commit is contained in:
parent
6dffb7b358
commit
0e7daf9a6a
1 changed files with 106 additions and 0 deletions
106
lib/services/phishing-detector.test.ts
Normal file
106
lib/services/phishing-detector.test.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
KNOWN_PHISHING_PATTERNS,
|
||||
matchesPhishingPatterns,
|
||||
computePhishingContentHash,
|
||||
} from './phishing-detector';
|
||||
|
||||
describe('KNOWN_PHISHING_PATTERNS', () => {
|
||||
it('has exactly 8 locked patterns', () => {
|
||||
expect(KNOWN_PHISHING_PATTERNS).toHaveLength(8);
|
||||
});
|
||||
});
|
||||
|
||||
describe('matchesPhishingPatterns', () => {
|
||||
it('flags a title containing "Phishing Report"', () => {
|
||||
const result = matchesPhishingPatterns('Fwd: Phishing Report', null);
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Phishing Report');
|
||||
});
|
||||
|
||||
it('flags a title containing "Spam Alert"', () => {
|
||||
const result = matchesPhishingPatterns('Spam Alert - user reported', null);
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Spam Alert');
|
||||
});
|
||||
|
||||
it('flags a title containing "Phishing Alert - Email Security Report"', () => {
|
||||
const result = matchesPhishingPatterns('Phishing Alert - Email Security Report', null);
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Phishing Alert - Email Security Report');
|
||||
});
|
||||
|
||||
it('flags a description containing "KnowBe4 Phish Alert Report"', () => {
|
||||
const result = matchesPhishingPatterns(null, 'This is a KnowBe4 Phish Alert Report for review');
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('KnowBe4 Phish Alert Report');
|
||||
});
|
||||
|
||||
it('flags a description containing "Source: KnowBe4 Phish Alert Button"', () => {
|
||||
const result = matchesPhishingPatterns(null, 'Source: KnowBe4 Phish Alert Button');
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Source: KnowBe4 Phish Alert Button');
|
||||
});
|
||||
|
||||
it('flags a description containing "userSubmissionsReportMessage"', () => {
|
||||
const result = matchesPhishingPatterns(null, 'Generated by userSubmissionsReportMessage flow');
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('userSubmissionsReportMessage');
|
||||
});
|
||||
|
||||
it('flags a description containing "reported message destinations"', () => {
|
||||
const result = matchesPhishingPatterns(null, 'See reported message destinations below');
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('reported message destinations');
|
||||
});
|
||||
|
||||
it('flags a description containing "Microsoft directly"', () => {
|
||||
const result = matchesPhishingPatterns(null, 'This message was reported to Microsoft directly');
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Microsoft directly');
|
||||
});
|
||||
|
||||
it('does not flag a ticket with none of the patterns', () => {
|
||||
const result = matchesPhishingPatterns('Re: order confirmation', 'please review invoice');
|
||||
expect(result.flagged).toBe(false);
|
||||
expect(result.matched).toEqual([]);
|
||||
});
|
||||
|
||||
it('matches case-insensitively', () => {
|
||||
const result = matchesPhishingPatterns('SPAM ALERT from user', null);
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Spam Alert');
|
||||
});
|
||||
|
||||
it('returns only the patterns actually present in matched[]', () => {
|
||||
const result = matchesPhishingPatterns('Phishing Report', 'unrelated body text');
|
||||
expect(result.matched).toEqual(['Phishing Report']);
|
||||
});
|
||||
|
||||
it('checks both title and description for a match', () => {
|
||||
const result = matchesPhishingPatterns('Unrelated subject', 'Spam Alert triggered');
|
||||
expect(result.flagged).toBe(true);
|
||||
expect(result.matched).toContain('Spam Alert');
|
||||
});
|
||||
});
|
||||
|
||||
describe('computePhishingContentHash', () => {
|
||||
it('is stable for identical title+description', () => {
|
||||
expect(computePhishingContentHash('t', 'd')).toBe(computePhishingContentHash('t', 'd'));
|
||||
});
|
||||
|
||||
it('changes when the title changes', () => {
|
||||
expect(computePhishingContentHash('t', 'd')).not.toBe(computePhishingContentHash('t2', 'd'));
|
||||
});
|
||||
|
||||
it('changes when the description changes', () => {
|
||||
expect(computePhishingContentHash('t', 'd')).not.toBe(computePhishingContentHash('t', 'd2'));
|
||||
});
|
||||
|
||||
it('is defined and stable when description is null', () => {
|
||||
const hash1 = computePhishingContentHash('t', null);
|
||||
const hash2 = computePhishingContentHash('t', null);
|
||||
expect(hash1).toBeTruthy();
|
||||
expect(hash1).toBe(hash2);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue