d3ro-voice/apps/desktop/tests/red/pii-redactor.usecase.test.ts
Yun Chan 708e20f747
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
2026-08-20 11:12:05 +09:00

68 lines
2.8 KiB
TypeScript

// 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)
})
})