개발자 계정으로 환자 선택을 누르면 "전산실 소속만 가능합니다"가 떴다. PatientPreviewPolicy 가 ModifyPolicy.CanModify 를 그대로 호출하고 있었기 때문이다. ## 근거를 다시 읽었다 레거시가 부서로 가리는 툴은 TK_MODIFY 하나뿐이다(frmSheetDesigner.vb:1030-1060). TK_ExportXML / TK_ImportXML 은 MSYS 계정 문이고, TK_PREVIEW 에는 가시성 조건이 하나도 걸려 있지 않다 — 서식생성기를 열 수 있으면 쓸 수 있다. 즉 이 제약은 레거시에서 옮긴 것이 아니라 내가 "무게가 비슷하다"고 판단해 붙인 것이다. 사용자가 정한 것도 아니었다 — 환자 접근에 대한 결정은 "전체 검색 + 감사 로그"였고 부서 제한은 거기에 없다. ## 두 일의 무게가 실제로 다르다 수정은 지금 쓰이는 서식을 제자리에서 바꿔 병원 전체에 즉시 영향을 준다. 미리보기는 이미 그 사람이 볼 수 있는 기록을 읽기만 한다. 그리고 이 문은 막아서 더 위험해지는 쪽이었다. 서식을 만드는 사람이 자기 서식을 검증할 수 없으면 값이 틀린 서식이 그대로 운영에 올라간다. 태그가 정확한 값을 뽑는지 확인하는 것이 이 기능을 만든 이유였는데 그 확인을 만든 사람에게서 빼앗고 있었다. ## 바꾼 것 CanPreviewPatient 는 인증만 요구한다 — 미인증이면 감사 로그에 남길 주체가 없고 주체 없는 환자 조회는 남기면 안 되는 일이다. 그것이 유일한 조건이다. 병원·부서 인자는 받아 두고 쓰지 않는다. 병원별 규칙이 생기면 호출부를 고치지 않고 여기서 받을 수 있어야 한다. 안전장치는 막는 것이 아니라 감사 로그다. 그래서 테스트도 무게를 옮겼다 — 클래스 주석의 "감사와 권한이 유일한 장치"를 "감사 로그가 유일한 장치"로 고쳤고, 감사 한 줄의 모양(주체가 있는가·이름이 새지 않는가)이 가장 중요한 판정이 된다. ## 대조군 '수정_권한은_그대로_좁게_남는다' 를 새로 넣었다. 미리보기를 연 것이 수정까지 연 것이 되면 안 되고, 이 대조가 없으면 위 완화가 조용히 ModifyPolicy 까지 번져도 알 수 없다. 게이트: dotnet test 313/313 (미리보기 판정 1건 → 2건으로 갈라짐) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
72 lines
3.4 KiB
C#
72 lines
3.4 KiB
C#
using SheetMe.Core.Catalog;
|
|
|
|
namespace SheetMe.Core.Tests;
|
|
|
|
/// <summary>
|
|
/// 환자 미리보기 접근 규칙 고정.
|
|
///
|
|
/// 레거시는 인가코드가 소스에 평문이고, 검색 범위 무제한이고, 감사 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 부서로_막지_않는다()
|
|
{
|
|
// 처음에는 수정 권한(ModifyPolicy)을 그대로 갖다 썼다. 그건 레거시에 없는 제약이었다 —
|
|
// 레거시가 부서로 가리는 툴은 TK_MODIFY 하나뿐이고 TK_PREVIEW 에는 문이 없다
|
|
// (frmSheetDesigner.vb:1030-1060). 서식을 만드는 사람이 자기 서식을 검증할 수 없으면
|
|
// 값이 틀린 서식이 그대로 운영에 올라간다.
|
|
foreach (var dep in new[] { "EDPS", "NURS", "SALO", "MEDI", "" })
|
|
{
|
|
Assert.IsTrue(PatientPreviewPolicy.CanPreviewPatient("ABC", dep, "011825", string.Empty),
|
|
$"부서 '{dep}' 로 막혔다");
|
|
}
|
|
// 수정에만 걸리던 갈래도 미리보기에는 걸리지 않는다
|
|
Assert.IsTrue(PatientPreviewPolicy.CanPreviewPatient("XYZ", "NURS", "011825", "20250501"));
|
|
Assert.IsTrue(PatientPreviewPolicy.CanPreviewPatient("HANKOOK", "NURS", "011825", string.Empty));
|
|
}
|
|
|
|
[TestMethod]
|
|
public void 수정_권한은_그대로_좁게_남는다()
|
|
{
|
|
// 미리보기를 연 것이 수정까지 연 것이 되면 안 된다 — 수정은 지금 쓰이는 서식을
|
|
// 제자리에서 바꿔 병원 전체에 즉시 영향을 준다. 이 대조가 없으면 위 완화가
|
|
// 조용히 ModifyPolicy 까지 번져도 알 수 없다.
|
|
Assert.IsFalse(ModifyPolicy.CanModify("ABC", "NURS", "011825", string.Empty));
|
|
Assert.IsTrue(ModifyPolicy.CanModify("ABC", "EDPS", "011825", string.Empty));
|
|
}
|
|
|
|
[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
|
|
}
|