142 lines
4.1 KiB
Java
142 lines
4.1 KiB
Java
package com.cloudhandson.vpdbackoffice.domain.operation;
|
|
|
|
import com.cloudhandson.vpdbackoffice.domain.masking.MaskingPolicyStatus;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Page-level health summary computed from the same DB-backed rows shown in
|
|
* operation-status.html. It intentionally does not hide the row-level evidence:
|
|
* the summary is only a triage layer for operators.
|
|
*/
|
|
public record OperationHealthSummary(
|
|
int protectedObjectCount,
|
|
int rowPolicyOkCount,
|
|
int rowPolicyWarnCount,
|
|
int rowPolicyErrorCount,
|
|
int missingHandlerCount,
|
|
int missingPolicyCount,
|
|
int invalidFunctionCount,
|
|
int unverifiedCount,
|
|
int maskingPolicyCount,
|
|
int maskingAppliedCount,
|
|
int maskingInactiveExpectedCount,
|
|
int maskingMismatchCount
|
|
) {
|
|
|
|
public static OperationHealthSummary from(
|
|
List<OperationStatusRow> rows,
|
|
List<MaskingPolicyStatus> maskingStatuses
|
|
) {
|
|
int rowPolicyOk = 0;
|
|
int rowPolicyWarn = 0;
|
|
int rowPolicyError = 0;
|
|
int missingHandler = 0;
|
|
int missingPolicy = 0;
|
|
int invalidFunction = 0;
|
|
int unverified = 0;
|
|
|
|
for (OperationStatusRow row : rows) {
|
|
switch (row.healthLevel()) {
|
|
case "OK" -> rowPolicyOk++;
|
|
case "ERROR" -> rowPolicyError++;
|
|
default -> rowPolicyWarn++;
|
|
}
|
|
if (row.handlerId() == null) {
|
|
missingHandler++;
|
|
}
|
|
if (row.policyNames() == null || row.policyNames().isBlank()) {
|
|
missingPolicy++;
|
|
}
|
|
if (row.functionStatus() != null && !"VALID".equalsIgnoreCase(row.functionStatus())) {
|
|
invalidFunction++;
|
|
}
|
|
if (row.lastProbeStatus() == null || row.lastProbeStatus().isBlank()) {
|
|
unverified++;
|
|
}
|
|
}
|
|
|
|
int maskingApplied = 0;
|
|
int maskingInactive = 0;
|
|
int maskingMismatch = 0;
|
|
for (MaskingPolicyStatus status : maskingStatuses) {
|
|
if (status.applied()) {
|
|
maskingApplied++;
|
|
} else if (status.inactiveAsExpected()) {
|
|
maskingInactive++;
|
|
} else {
|
|
maskingMismatch++;
|
|
}
|
|
}
|
|
|
|
return new OperationHealthSummary(
|
|
rows.size(),
|
|
rowPolicyOk,
|
|
rowPolicyWarn,
|
|
rowPolicyError,
|
|
missingHandler,
|
|
missingPolicy,
|
|
invalidFunction,
|
|
unverified,
|
|
maskingStatuses.size(),
|
|
maskingApplied,
|
|
maskingInactive,
|
|
maskingMismatch
|
|
);
|
|
}
|
|
|
|
public String overallLevel() {
|
|
if (rowPolicyErrorCount > 0 || invalidFunctionCount > 0 || maskingMismatchCount > 0) {
|
|
return "ERROR";
|
|
}
|
|
if (rowPolicyWarnCount > 0 || missingHandlerCount > 0 || missingPolicyCount > 0
|
|
|| unverifiedCount > 0) {
|
|
return "WARN";
|
|
}
|
|
return "OK";
|
|
}
|
|
|
|
public String overallLabel() {
|
|
return switch (overallLevel()) {
|
|
case "ERROR" -> "조치 필요";
|
|
case "WARN" -> "확인 필요";
|
|
default -> "정상";
|
|
};
|
|
}
|
|
|
|
public String overallBadgeClass() {
|
|
return switch (overallLevel()) {
|
|
case "ERROR" -> "text-bg-danger";
|
|
case "WARN" -> "text-bg-warning";
|
|
default -> "text-bg-success";
|
|
};
|
|
}
|
|
|
|
public String rowPolicySummary() {
|
|
return "정상 " + rowPolicyOkCount + " · 확인 " + rowPolicyWarnCount + " · 오류 " + rowPolicyErrorCount;
|
|
}
|
|
|
|
public String maskingSummary() {
|
|
return "적용 " + maskingAppliedCount + " · 미적용 정상 " + maskingInactiveExpectedCount
|
|
+ " · 불일치 " + maskingMismatchCount;
|
|
}
|
|
|
|
public String primaryAction() {
|
|
if (invalidFunctionCount > 0) {
|
|
return "컴파일 오류가 있는 VPD Filter를 먼저 확인하세요.";
|
|
}
|
|
if (maskingMismatchCount > 0) {
|
|
return "컬럼 마스킹 화면에서 DB ASO 정책 동기화를 확인하세요.";
|
|
}
|
|
if (missingPolicyCount > 0) {
|
|
return "보호 상태에서 행 접근 정책(VPD)을 적용하세요.";
|
|
}
|
|
if (missingHandlerCount > 0) {
|
|
return "조회 대상 또는 조회 연동에서 ORDS handler를 확인하세요.";
|
|
}
|
|
if (unverifiedCount > 0) {
|
|
return "접근 검증을 실행해 실제 결과를 확인하세요.";
|
|
}
|
|
return "현재 요약 기준으로 즉시 조치할 항목은 없습니다.";
|
|
}
|
|
}
|