Healthcare Eval Harness — 환자 안전 검증
헬스케어 애플리케이션 배포를 위한 자동화된 검증 시스템입니다. 단 하나의 CRITICAL 실패가 배포를 차단합니다. 환자 안전은 타협할 수 없습니다.
참고: 예제는 Jest를 기준 테스트 러너로 사용합니다. 명령어는 사용 중인 프레임워크(Vitest, pytest, PHPUnit 등)에 맞게 조정하세요. 테스트 카테고리와 통과 임계값은 프레임워크에 구애받지 않습니다.
사용 시기
- EMR/EHR 애플리케이션 배포 전
- CDSS 로직(약물 상호작용, 용량 검증, 점수 계산) 수정 후
- 환자 데이터를 다루는 데이터베이스 스키마 변경 후
- 인증 또는 접근 제어 수정 후
- 헬스케어 앱 CI/CD 파이프라인 구성 중
- 임상 모듈에서 병합 충돌 해결 후
작동 방식
평가 하네스는 다섯 가지 테스트 카테고리를 순서대로 실행합니다. 처음 세 가지(CDSS 정확도, PHI 노출, 데이터 무결성)는 100% 통과율이 필요한 CRITICAL 게이트이며, 단일 실패 시 배포가 차단됩니다. 나머지 두 가지(임상 워크플로우, 통합)는 95%+ 통과율이 필요한 HIGH 게이트입니다.
각 카테고리는 Jest 테스트 경로 패턴에 매핑됩니다. CI 파이프라인은 CRITICAL 게이트를 --bail(첫 번째 실패 시 중단)과 함께 실행하고, --coverage --coverageThreshold로 커버리지 임계값을 적용합니다.
평가 카테고리
1. CDSS 정확도 (CRITICAL — 100% 필수)
모든 임상 의사결정 지원 로직을 테스트합니다: 양방향 약물 상호작용 쌍, 용량 검증 규칙, 공개된 사양 대비 임상 점수 계산, 위음성 없음, 무음 실패 없음.
npx jest --testPathPattern='tests/cdss' --bail --ci --coverage
2. PHI 노출 (CRITICAL — 100% 필수)
보호된 건강 정보 유출을 테스트합니다: API 오류 응답, 콘솔 출력, URL 파라미터, 브라우저 저장소, 시설 간 격리, 인증되지 않은 접근, 서비스 역할 키 부재.
npx jest --testPathPattern='tests/security/phi' --bail --ci
3. 데이터 무결성 (CRITICAL — 100% 필수)
임상 데이터 안전을 테스트합니다: 잠긴 진료 기록, 감사 추적 항목, 캐스케이드 삭제 보호, 동시 편집 처리, 고아 레코드 없음.
npx jest --testPathPattern='tests/data-integrity' --bail --ci
4. 임상 워크플로우 (HIGH — 95%+ 필수)
종단간 흐름을 테스트합니다: 진료 기록 수명 주기, 템플릿 렌더링, 약물 세트, 약물/진단 검색, 처방전 PDF, 위험 신호 알림.
tmp_json=$(mktemp)
npx jest --testPathPattern='tests/clinical' --ci --json --outputFile="$tmp_json" || true
total=$(jq '.numTotalTests // 0' "$tmp_json")
passed=$(jq '.numPassedTests // 0' "$tmp_json")
if [ "$total" -eq 0 ]; then
echo "No clinical tests found" >&2
exit 1
fi
rate=$(echo "scale=2; $passed * 100 / $total" | bc)
echo "Clinical pass rate: ${rate}% ($passed/$total)"
5. 통합 규정 준수 (HIGH — 95%+ 필수)
외부 시스템을 테스트합니다: HL7 메시지 파싱(v2.x), FHIR 검증, 검사 결과 매핑, 잘못된 메시지 처리.
tmp_json=$(mktemp)
npx jest --testPathPattern='tests/integration' --ci --json --outputFile="$tmp_json" || true
total=$(jq '.numTotalTests // 0' "$tmp_json")
passed=$(jq '.numPassedTests // 0' "$tmp_json")
if [ "$total" -eq 0 ]; then
echo "No integration tests found" >&2
exit 1
fi
rate=$(echo "scale=2; $passed * 100 / $total" | bc)
echo "Integration pass rate: ${rate}% ($passed/$total)"
통과/실패 매트릭스
| 카테고리 | 임계값 | 실패 시 |
|---|---|---|
| CDSS 정확도 | 100% | 배포 차단 |
| PHI 노출 | 100% | 배포 차단 |
| 데이터 무결성 | 100% | 배포 차단 |
| 임상 워크플로우 | 95%+ | 경고, 검토 후 허용 |
| 통합 | 95%+ | 경고, 검토 후 허용 |
CI/CD 통합
name: Healthcare Safety Gate
on: [push, pull_request]
jobs:
safety-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
# CRITICAL gates — 100% required, bail on first failure
- name: CDSS Accuracy
run: npx jest --testPathPattern='tests/cdss' --bail --ci --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80}}'
- name: PHI Exposure Check
run: npx jest --testPathPattern='tests/security/phi' --bail --ci
- name: Data Integrity
run: npx jest --testPathPattern='tests/data-integrity' --bail --ci
# HIGH gates — 95%+ required, custom threshold check
- name: Clinical Workflows
run: |
TMP_JSON=$(mktemp)
npx jest --testPathPattern='tests/clinical' --ci --json --outputFile="$TMP_JSON" || true
TOTAL=$(jq '.numTotalTests // 0' "$TMP_JSON")
PASSED=$(jq '.numPassedTests // 0' "$TMP_JSON")
if [ "$TOTAL" -eq 0 ]; then
echo "::error::No clinical tests found"; exit 1
fi
RATE=$(echo "scale=2; $PASSED * 100 / $TOTAL" | bc)
echo "Pass rate: ${RATE}% ($PASSED/$TOTAL)"
if (( $(echo "$RATE < 95" | bc -l) )); then
echo "::warning::Clinical pass rate ${RATE}% below 95%"
fi
- name: Integration Compliance
run: |
TMP_JSON=$(mktemp)
npx jest --testPathPattern='tests/integration' --ci --json --outputFile="$TMP_JSON" || true
TOTAL=$(jq '.numTotalTests // 0' "$TMP_JSON")
PASSED=$(jq '.numPassedTests // 0' "$TMP_JSON")
if [ "$TOTAL" -eq 0 ]; then
echo "::error::No integration tests found"; exit 1
fi
RATE=$(echo "scale=2; $PASSED * 100 / $TOTAL" | bc)
echo "Pass rate: ${RATE}% ($PASSED/$TOTAL)"
if (( $(echo "$RATE < 95" | bc -l) )); then
echo "::warning::Integration pass rate ${RATE}% below 95%"
fi
안티 패턴
- "이전에 통과했으니까" CDSS 테스트를 건너뛰는 행위
- CRITICAL 임계값을 100% 미만으로 설정하는 행위
- CRITICAL 테스트 스위트에
--no-bail사용 - 통합 테스트에서 CDSS 엔진을 모킹(실제 로직을 테스트해야 함)
- 안전 게이트가 적색일 때 배포를 허용하는 행위
- CDSS 스위트에서
--coverage없이 테스트 실행
예제
예제 1: 모든 CRITICAL 게이트를 로컬에서 실행
npx jest --testPathPattern='tests/cdss' --bail --ci --coverage && \
npx jest --testPathPattern='tests/security/phi' --bail --ci && \
npx jest --testPathPattern='tests/data-integrity' --bail --ci
예제 2: HIGH 게이트 통과율 확인
tmp_json=$(mktemp)
npx jest --testPathPattern='tests/clinical' --ci --json --outputFile="$tmp_json" || true
jq '{
passed: (.numPassedTests // 0),
total: (.numTotalTests // 0),
rate: (if (.numTotalTests // 0) == 0 then 0 else ((.numPassedTests // 0) / (.numTotalTests // 1) * 100) end)
}' "$tmp_json"
# 예상 출력: { "passed": 21, "total": 22, "rate": 95.45 }
예제 3: 평가 보고서
## Healthcare Eval: 2026-03-27 [commit abc1234]
### Patient Safety: PASS
| Category | Tests | Pass | Fail | Status |
|----------|-------|------|------|--------|
| CDSS Accuracy | 39 | 39 | 0 | PASS |
| PHI Exposure | 8 | 8 | 0 | PASS |
| Data Integrity | 12 | 12 | 0 | PASS |
| Clinical Workflow | 22 | 21 | 1 | 95.5% PASS |
| Integration | 6 | 6 | 0 | PASS |
### Coverage: 84% (target: 80%+)
### Verdict: SAFE TO DEPLOY