// apps/desktop/tests/red/pii-redactor.usecase.test.ts // Phase 11+/CCPA: PII 마스킹 / 가명화 및 Zero Data Retention (ZDR) 오디오 메모리 와이프 테스트 import { describe, it, expect } from 'vitest' import { redactPII, rehydrateText, secureZeroBuffer, secureWipeAudioChunks, } from '@d3ro/core' describe('CCPA/CPRA & GDPR 규제 준수: PII/SPI 마스킹 및 메모리 안전성', () => { it('주민등록번호를 감지하여 마스킹한다', () => { const input = '고객님의 주민번호는 950101-1234567 입니다.' const res = redactPII(input, 'mask') expect(res.redactedText).toBe('고객님의 주민번호는 950101-******* 입니다.') expect(res.redactionCount).toBe(1) expect(res.matchedCategories).toContain('주민등록번호') }) it('신용카드번호를 마스킹한다', () => { const input = '결제 카드: 1234-5678-9012-3456 승인 요청' const res = redactPII(input, 'mask') expect(res.redactedText).toContain('1234-****-****-3456') expect(res.matchedCategories).toContain('신용카드번호') }) it('전화번호를 마스킹한다', () => { const input = '담당자 연락처: 010-9876-5432 로 연락 바랍니다.' const res = redactPII(input, 'mask') expect(res.redactedText).toBe('담당자 연락처: 010-****-5432 로 연락 바랍니다.') expect(res.matchedCategories).toContain('전화번호') }) it('이메일 주소를 마스킹한다', () => { const input = '문의 이메일: contact@d3ro.ai 입니다.' const res = redactPII(input, 'mask') expect(res.redactedText).toBe('문의 이메일: co***@d3ro.ai 입니다.') }) it('tokenize 모드로 변환 후 rehydrateText 로 안전하게 원문 복원이 가능하다', () => { const input = '대표 번호 010-1111-2222 및 이메일 test@company.com' const res = redactPII(input, 'tokenize') expect(res.redactedText).toContain('[REDACTED_PHONE_NUMBER_') expect(res.redactedText).toContain('[REDACTED_EMAIL_') const rehydrated = rehydrateText(res.redactedText, res.tokens) expect(rehydrated).toBe(input) }) it('Zero Data Retention (ZDR): secureZeroBuffer 는 버퍼 메모리를 0으로 즉시 초기화한다', () => { const buf = Buffer.from([1, 2, 3, 4, 5, 255, 128]) expect(buf[0]).toBe(1) secureZeroBuffer(buf) expect(buf.every((byte) => byte === 0)).toBe(true) }) it('secureWipeAudioChunks 는 여러 오디오 청크를 0으로 채우고 배열을 비운다', () => { const chunk1 = Buffer.from([10, 20, 30]) const chunk2 = new Float32Array([0.5, -0.5, 0.8]) const chunks = [chunk1, chunk2] secureWipeAudioChunks(chunks) expect(chunk1.every((b) => b === 0)).toBe(true) expect(chunk2.every((v) => v === 0)).toBe(true) expect(chunks.length).toBe(0) }) })