@@ -23,8 +23,8 @@ class MaskingPolicySynchronizerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void kbContractsPremiumPolicyIsManagedByBackoffice() {
|
||||
assertThat(MaskingPolicySynchronizer.managedPolicyName("KB_CONTRACTS"))
|
||||
.isEqualTo("KB_CONTRACT_PREMIUM_REDACT");
|
||||
void smilegateSalesTransactionPolicyIsManagedByBackoffice() {
|
||||
assertThat(MaskingPolicySynchronizer.managedPolicyName("COMN_SALES_TXN"))
|
||||
.isEqualTo("SG_SALES_TXN_REDACT");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import org.junit.jupiter.api.Test;
|
||||
class McpSseServiceTest {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final SelectAiAgentOrdsService selectAiAgentOrdsService = new CapturingSelectAiAgentOrdsService();
|
||||
private final SmilegateSelectAiService selectAiService = new CapturingSmilegateSelectAiService();
|
||||
private final McpSseService service = new McpSseService(
|
||||
selectAiAgentOrdsService,
|
||||
selectAiService,
|
||||
objectMapper
|
||||
);
|
||||
|
||||
@@ -22,12 +22,12 @@ class McpSseServiceTest {
|
||||
var tools = response.path("result").path("tools");
|
||||
assertThat(tools).hasSize(1);
|
||||
var selectAi = tools.get(0);
|
||||
assertThat(selectAi.path("name").asText()).isEqualTo("ords.query.kb_select_ai_vpd");
|
||||
assertThat(selectAi.path("name").asText()).isEqualTo("oracle.select_ai.smilegate_game_text2sql");
|
||||
assertThat(selectAi.path("inputSchema").path("required"))
|
||||
.extracting(node -> node.asText())
|
||||
.contains("prompt");
|
||||
assertThat(selectAi.path("inputSchema").path("properties").has("bearerToken")).isFalse();
|
||||
assertThat(selectAi.path("inputSchema").path("properties").has("limit")).isTrue();
|
||||
assertThat(selectAi.path("inputSchema").path("properties").has("limit")).isFalse();
|
||||
assertThat(selectAi.path("inputSchema").path("properties").has("conversationId")).isFalse();
|
||||
}
|
||||
|
||||
@@ -35,31 +35,29 @@ class McpSseServiceTest {
|
||||
void callsVpdSelectAiThroughOrdsService() {
|
||||
ObjectNode request = request(2, "tools/call");
|
||||
ObjectNode params = (ObjectNode) request.putObject("params");
|
||||
params.put("name", "ords.query.kb_select_ai_vpd");
|
||||
params.put("name", "oracle.select_ai.smilegate_game_text2sql");
|
||||
ObjectNode arguments = params.putObject("arguments");
|
||||
arguments.put("prompt", "고객 수를 조회해 줘");
|
||||
arguments.put("limit", 25);
|
||||
arguments.put("prompt", "카제나 AU를 조회해 줘");
|
||||
|
||||
ObjectNode response = service.handle("default", request, "user-bearer");
|
||||
|
||||
CapturingSelectAiAgentOrdsService agentService =
|
||||
(CapturingSelectAiAgentOrdsService) selectAiAgentOrdsService;
|
||||
CapturingSmilegateSelectAiService agentService =
|
||||
(CapturingSmilegateSelectAiService) selectAiService;
|
||||
assertThat(agentService.bearerToken).isEqualTo("user-bearer");
|
||||
assertThat(agentService.prompt).isEqualTo("고객 수를 조회해 줘");
|
||||
assertThat(agentService.limit).isEqualTo(25);
|
||||
assertThat(agentService.prompt).isEqualTo("카제나 AU를 조회해 줘");
|
||||
assertThat(response.path("error").isMissingNode()).isTrue();
|
||||
assertThat(response.path("result").path("isError").asBoolean()).isFalse();
|
||||
assertThat(response.path("result").path("content").get(0).path("text").asText())
|
||||
.contains("KB_AIDP_SELECTAI_GPT54_MINI_FULLMETA_PROFILE_V1")
|
||||
.contains("SELECT COUNT(*) FROM KB_CUSTOMERS");
|
||||
.contains("SGMP_POC_HAIKU45")
|
||||
.contains("SELECT 1 FROM DUAL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsToolLevelDeniedResultWhenVpdTokenIsMissing() {
|
||||
ObjectNode request = request(3, "tools/call");
|
||||
ObjectNode params = (ObjectNode) request.putObject("params");
|
||||
params.put("name", "ords.query.kb_select_ai_vpd");
|
||||
params.putObject("arguments").put("prompt", "고객 수를 조회해 줘");
|
||||
params.put("name", "oracle.select_ai.smilegate_game_text2sql");
|
||||
params.putObject("arguments").put("prompt", "카제나 AU를 조회해 줘");
|
||||
|
||||
ObjectNode response = service.handle("default", request, "");
|
||||
|
||||
@@ -78,24 +76,22 @@ class McpSseServiceTest {
|
||||
return request;
|
||||
}
|
||||
|
||||
private static final class CapturingSelectAiAgentOrdsService extends SelectAiAgentOrdsService {
|
||||
private static final class CapturingSmilegateSelectAiService extends SmilegateSelectAiService {
|
||||
|
||||
private String bearerToken;
|
||||
private String prompt;
|
||||
private int limit;
|
||||
|
||||
private CapturingSelectAiAgentOrdsService() {
|
||||
super(null, null, new ObjectMapper());
|
||||
private CapturingSmilegateSelectAiService() {
|
||||
super(null, null, null, new ObjectMapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode run(String bearerToken, String prompt, int limit) {
|
||||
public JsonNode generateShowSql(String bearerToken, String prompt) {
|
||||
this.bearerToken = bearerToken;
|
||||
this.prompt = prompt;
|
||||
this.limit = limit;
|
||||
return new ObjectMapper().createObjectNode()
|
||||
.put("profile", "KB_AIDP_SELECTAI_GPT54_MINI_FULLMETA_PROFILE_V1")
|
||||
.put("generatedSql", "SELECT COUNT(*) FROM KB_CUSTOMERS");
|
||||
.put("profile", "SGMP_POC_HAIKU45")
|
||||
.put("generatedSql", "SELECT 1 FROM DUAL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,13 @@ class SecuritySqlScriptServiceTest {
|
||||
assertThat(service.list())
|
||||
.extracting(item -> item.fileName())
|
||||
.containsExactly(
|
||||
"62_kb_aso_masking_backoffice_metadata.sql",
|
||||
"63_kb_aso_masking_rule_runtime.sql",
|
||||
"64_kb_aso_masking_default_column_rules.sql",
|
||||
"65_kb_select_ai_vpd_query_api.sql",
|
||||
"66_kb_select_ai_vpd_query_ords.sql"
|
||||
"70_sg_tool_user.sql",
|
||||
"71_sg_identity_administration.sql"
|
||||
);
|
||||
|
||||
assertThat(service.find("select-ai-vpd-ords").source())
|
||||
.contains("POST /ords/cb-ords/kb-select-ai-vpd/query")
|
||||
.contains("Authorization: Bearer <VPD token>");
|
||||
assertThat(service.find("smilegate-identity-administration").source())
|
||||
.contains("create table sg_app_user")
|
||||
.contains("DATA_AI_TF");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -12,22 +12,22 @@ class StructuredDataServiceTest {
|
||||
private final StructuredDataService service = new StructuredDataService(mock(JdbcTemplate.class));
|
||||
|
||||
@Test
|
||||
void exposesOnlyTheSevenApprovedStructuredTables() {
|
||||
void exposesOnlyTheSevenApprovedSmilegateStructuredTables() {
|
||||
assertThat(service.tables())
|
||||
.extracting(table -> table.tableName())
|
||||
.containsExactly(
|
||||
"KB_CUSTOMERS",
|
||||
"KB_PRODUCTS",
|
||||
"KB_CONTRACTS",
|
||||
"KB_COVERAGES",
|
||||
"KB_CLAIMS",
|
||||
"KB_EXTERNAL_HOLDINGS",
|
||||
"KB_STAKEHOLDERS");
|
||||
"CZN_COMN_USER_MST",
|
||||
"CZN_COMN_CHARACTER_MST",
|
||||
"COMN_SALES_TXN",
|
||||
"COMN_REFUND_TXN",
|
||||
"COMN_SALES_PRODUCT_DISP_BAS",
|
||||
"COMN_GAME_SERVER_BAS",
|
||||
"COMN_GAME_ALIAS_BAS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsAnyTableOutsideTheServerSideAllowlist() {
|
||||
assertThatThrownBy(() -> service.requireTable("KB_SECURITY_AUDIT_LOG"))
|
||||
assertThatThrownBy(() -> service.requireTable("security-audit-log"))
|
||||
.isInstanceOf(AppException.class)
|
||||
.hasMessage("선택할 수 없는 정형 데이터 테이블입니다.");
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class GuidedFlowTemplateTest {
|
||||
.doesNotContain("dashboard-workflow")
|
||||
.doesNotContain(">01<", ">02<");
|
||||
assertThat(layout)
|
||||
.contains("데이터 접근 제어")
|
||||
.contains("운영 사용자 관리")
|
||||
.contains("접근 제어")
|
||||
.contains("보호·검증")
|
||||
.contains("연동 도구")
|
||||
@@ -122,7 +122,7 @@ class GuidedFlowTemplateTest {
|
||||
.contains("data-wizard-target=\"2\">대상")
|
||||
.doesNotContain(">1 역할<", ">2 객체<", "wizard-step-number");
|
||||
assertThat(tokens)
|
||||
.contains("직원 토큰 발급", "검증 세션 발급")
|
||||
.contains("도구 사용자 토큰 발급", "검증 세션 발급")
|
||||
.doesNotContain("1. 검증할 사용자 선택", "2. 검증 세션 발급");
|
||||
assertThat(probe)
|
||||
.contains("접근 검증 실행", "<strong>검증 결과</strong>")
|
||||
@@ -198,7 +198,7 @@ class GuidedFlowTemplateTest {
|
||||
String javascript = Files.readString(Path.of("src/main/resources/static/js/app.js"));
|
||||
|
||||
assertThat(html)
|
||||
.contains("value=\"OWN_CUSTOMER\">본인 담당 고객")
|
||||
.contains("value=\"OWN_CUSTOMER\">담당 게임 사용자")
|
||||
.contains("value=\"STATIC_SQL\">정적 SQL 조건식")
|
||||
.contains("행 규칙의 두 가지 적용 방식 보기")
|
||||
.contains("한 권한 안의 규칙은 모두 AND")
|
||||
@@ -221,8 +221,8 @@ class GuidedFlowTemplateTest {
|
||||
String filters = template("vpd-filter-policies.html");
|
||||
|
||||
assertThat(roles)
|
||||
.contains("표시 보호 등급 상한")
|
||||
.contains("행 접근 권한은 행 접근 규칙과 Oracle VPD 정책에서 결정합니다");
|
||||
.contains("스마일게이트 Data & AI PoC 운영 역할")
|
||||
.contains("데이터 취급 등급");
|
||||
assertThat(tokens)
|
||||
.contains("회수·만료 포함")
|
||||
.contains("현재 사용 가능한 토큰만");
|
||||
|
||||
@@ -31,26 +31,26 @@ class MaskingRuleTemplateRenderTest {
|
||||
var engine = new SpringTemplateEngine();
|
||||
engine.setTemplateResolver(resolver);
|
||||
|
||||
var object = new ProtectedObject(7L, "POC_2", "KB_CUSTOMERS", "kb/customers", "Y");
|
||||
var contractObject = new ProtectedObject(8L, "POC_2", "KB_CONTRACTS", "kb/contracts", "Y");
|
||||
var column = new ProtectedColumn(11L, 7L, "RRN_MASKED", "Y", null, "RESTRICTED", "NULLIFY");
|
||||
var rule = new MaskingRule(1L, "KB_RRN_STANDARD", "주민번호 기본 마스킹", "RRN_PARTIAL", "테스트", "Y");
|
||||
var columnRule = new ColumnMaskingRule(11L, 7L, "POC_2", "KB_CUSTOMERS", "RRN_MASKED",
|
||||
1L, "KB_RRN_STANDARD", "주민번호 기본 마스킹", "RRN_PARTIAL", "Y");
|
||||
var object = new ProtectedObject(7L, "SGMP_POC", "CZN_COMN_USER_MST", "sgmp-poc/czn-users", "Y");
|
||||
var transactionObject = new ProtectedObject(8L, "SGMP_POC", "COMN_SALES_TXN", "sgmp-poc/sales", "Y");
|
||||
var column = new ProtectedColumn(11L, 7L, "GUID", "Y", null, "RESTRICTED", "NULLIFY");
|
||||
var rule = new MaskingRule(1L, "GAME_GUID_MASK", "게임 사용자 식별자 기본 마스킹", "TEXT_PARTIAL", "테스트", "Y");
|
||||
var columnRule = new ColumnMaskingRule(11L, 7L, "SGMP_POC", "CZN_COMN_USER_MST", "GUID",
|
||||
1L, "GAME_GUID_MASK", "게임 사용자 식별자 기본 마스킹", "TEXT_PARTIAL", "Y");
|
||||
var context = new Context(Locale.KOREAN);
|
||||
context.setVariable("_csrf", new CsrfFixture("_csrf", "test-token"));
|
||||
context.setVariable("templates", List.of(MaskingTemplate.values()));
|
||||
context.setVariable("rules", List.of(rule));
|
||||
context.setVariable("columnRules", List.of(columnRule));
|
||||
var status = new MaskingPolicyStatus(
|
||||
"POC_2", "KB_CUSTOMERS", "KB_CUSTOMER_PII_REDACT", "YES", 1, 1, 0, 0
|
||||
"SGMP_POC", "CZN_COMN_USER_MST", "SG_CZN_USER_REDACT", "YES", 1, 1, 0, 0
|
||||
);
|
||||
context.setVariable("policyStatuses", List.of(status));
|
||||
context.setVariable("policyStatusByObjectName", Map.of("KB_CUSTOMERS", status));
|
||||
context.setVariable("objects", List.of(object, contractObject));
|
||||
context.setVariable("maskingTargetObjects", List.of(object, contractObject));
|
||||
context.setVariable("policyStatusByObjectName", Map.of("CZN_COMN_USER_MST", status));
|
||||
context.setVariable("objects", List.of(object, transactionObject));
|
||||
context.setVariable("maskingTargetObjects", List.of(object, transactionObject));
|
||||
context.setVariable("sensitiveColumnsByObject", Map.of(7L, List.of(column), 8L, List.of()));
|
||||
context.setVariable("availableMaskingColumnsByObject", Map.of(7L, List.of("CUST_NM"), 8L, List.of("PREMIUM")));
|
||||
context.setVariable("availableMaskingColumnsByObject", Map.of(7L, List.of("GUID"), 8L, List.of("GUID")));
|
||||
|
||||
String rulesPage = engine.process("masking-rules", context);
|
||||
|
||||
@@ -64,13 +64,13 @@ class MaskingRuleTemplateRenderTest {
|
||||
.contains("DB Redaction 컬럼")
|
||||
.contains("레거시 VPD 컬럼 제어")
|
||||
.contains("마스킹 대상 컬럼 추가")
|
||||
.contains("POC_2.KB_CONTRACTS.PREMIUM")
|
||||
.contains("KB_CUSTOMER_PII_REDACT")
|
||||
.contains("SGMP_POC.COMN_SALES_TXN.GUID")
|
||||
.contains("SG_CZN_USER_REDACT")
|
||||
.contains("적용됨");
|
||||
|
||||
context.setVariable("users", List.of(new AppUser(2L, "KB_VPD_ADMIN", "ADMIN", "SEC", "N", "Y")));
|
||||
context.setVariable("userRules", List.of(new UserMaskingRule(2L, "KB_VPD_ADMIN", 11L,
|
||||
"POC_2", "KB_CUSTOMERS", "RRN_MASKED", "주민번호 기본 마스킹", "RRN_PARTIAL", "UNMASK", "Y")));
|
||||
context.setVariable("users", List.of(new AppUser(2L, "sg-teamlead", "SG-001", "DATA_AI", "N", "Y")));
|
||||
context.setVariable("userRules", List.of(new UserMaskingRule(2L, "sg-teamlead", 11L,
|
||||
"SGMP_POC", "CZN_COMN_USER_MST", "GUID", "게임 사용자 식별자 기본 마스킹", "TEXT_PARTIAL", "UNMASK", "Y")));
|
||||
String userPage = engine.process("user-masking-rules", context);
|
||||
|
||||
assertThat(userPage)
|
||||
|
||||
Reference in New Issue
Block a user