환자 미리보기 접근 규칙을 먼저 세운다 — 레거시에서 옮기지 않을 것들

미리보기 레거시 호환 계획의 A3 첫 조각. DB 조회는 조사 중이라 규칙과 감사부터 세운다.

<b>레거시에서 옮기지 않는 것이 요점이다.</b>
  · 폼이 뜰 때마다 인가코드를 InputBox 로 묻는데 <b>통과값 3개가 소스에 평문</b>이다
    (frmSheetDesigner.vb:913)
  · 환자를 검색조건 없이 <b>운영 전체</b>에서 찾는다(:636)
  · 누가 어느 환자를 열었는지 <b>남기지 않는다</b>(감사 0건)
셋을 그대로 옮기면 신규 앱이 최악을 물려받는다.

검색 범위는 레거시와 같게 두기로 했다(전체 검색 + 감사 로그).
그래서 <b>남기는 쪽</b>이 안전장치의 본체다 — 조회를 막지 않는 대신 흔적을 남긴다.
AppLog.Audit 은 FIXED 레벨이라 어느 로그 설정에서도 남는다.

권한 축은 ModifyPolicy 와 같은 것을 쓴다. 환자 기록을 보는 일은
지금 쓰이는 서식을 제자리에서 고치는 일과 무게가 다르지 않다.
미인증이면 막는다 — 주체가 없으면 감사에 남길 것이 없고, 남길 수 없는 조회는 하지 않는다.

<b>감사 한 줄에 환자 이름은 넣지 않는다.</b> 내원번호로 되짚을 수 있고,
로그는 오래 남고 접근 통제가 DB 보다 느슨하다. 검사로 못 박았다.

게이트: 테스트 303/303(신규 4), --edit-smoke 0실패,
--db-render P062 md5 8d683835f5d81e7bb41c79071d6bf954 동일.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-18 10:09:10 +09:00
co-authored by Claude Opus 5
parent 5072acb518
commit e9d8f7356e
2 changed files with 103 additions and 0 deletions
@@ -0,0 +1,54 @@
using SheetMe.Core.Catalog;
namespace SheetMe.Core.Tests;
/// <summary>
/// 환자 미리보기 접근 규칙 고정.
///
/// 이 표가 느슨해지면 서식을 만드는 사람 누구나 <b>운영 환자 기록</b>을 열 수 있다.
/// 레거시가 그 상태였다 — 인가코드가 소스에 평문이고, 검색 범위 무제한이고, 감사 0건이다.
/// 검색 범위는 레거시와 같게 두기로 했으므로 <b>감사와 권한</b>이 유일한 장치다.
/// </summary>
[TestClass]
public sealed class PatientPreviewPolicyTests
{
#region Methods
[TestMethod]
public void _볼_수_없다()
{
// 주체가 없으면 감사 로그에 남길 것이 없다 — 남길 수 없는 조회는 하지 않는다.
Assert.IsFalse(PatientPreviewPolicy.CanPreviewPatient("ABC", "EDPS", string.Empty, string.Empty));
StringAssert.Contains(
PatientPreviewPolicy.DenyReason("ABC", string.Empty, string.Empty), "HIS 사용자");
}
[TestMethod]
public void _권한과_같은_축을_쓴다()
{
// 환자 기록을 보는 일은 지금 쓰이는 서식을 제자리에서 고치는 일과 무게가 다르지 않다.
Assert.IsTrue(PatientPreviewPolicy.CanPreviewPatient("ABC", "EDPS", "011825", string.Empty));
Assert.IsFalse(PatientPreviewPolicy.CanPreviewPatient("ABC", "NURS", "011825", string.Empty));
Assert.IsTrue(PatientPreviewPolicy.CanPreviewPatient("HANKOOK", "SALO", "011825", string.Empty));
Assert.IsFalse(PatientPreviewPolicy.CanPreviewPatient("XYZ", "EDPS", "011825", "20250501"));
}
[TestMethod]
public void _한_줄에_주체와_내원이_들어간다()
{
var line = PatientPreviewPolicy.AuditLine("011825", "C12345");
StringAssert.Contains(line, "011825");
StringAssert.Contains(line, "C12345");
StringAssert.Contains(line, "환자 미리보기");
}
[TestMethod]
public void _한_줄에_환자_이름은_넣지_않는다()
{
// 내원번호로 되짚을 수 있다. 로그 파일에 이름을 흘릴 이유가 없다 —
// 로그는 오래 남고 접근 통제가 DB 보다 느슨하다.
var line = PatientPreviewPolicy.AuditLine("011825", "C12345");
Assert.IsFalse(line.Contains("이름", StringComparison.Ordinal));
Assert.AreEqual(2, line.Split('=').Length - 1, $"항목이 둘(사용자·내원)이어야 한다: {line}");
}
#endregion
}