PD Guard: модуль безопасности персональных данных
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
package ru.pdguard;
|
||||
|
||||
import io.restassured.path.json.JsonPath;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/** Демонстрационное плечо: потребитель → маскирование → LLM → демаскирование. */
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class ProxyResourceTest {
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
private static final String PROMPT =
|
||||
"Составь письмо клиенту Иванову Ивану Ивановичу, паспорт 4509 123456, почта ivan@mail.ru";
|
||||
|
||||
private JsonPath proxy(String prompt) {
|
||||
return given()
|
||||
.port(port)
|
||||
.contentType("application/json")
|
||||
.body(Map.of("prompt", prompt))
|
||||
.when().post("/proxy")
|
||||
.then().statusCode(200)
|
||||
.extract().jsonPath();
|
||||
}
|
||||
|
||||
@Test
|
||||
void personalDataDoesNotReachTheModel() {
|
||||
JsonPath json = proxy(PROMPT);
|
||||
String toModel = json.getString("prompt_masked");
|
||||
|
||||
assertFalse(toModel.contains("Иванову Ивану Ивановичу"), toModel);
|
||||
assertFalse(toModel.contains("4509 123456"), toModel);
|
||||
assertFalse(toModel.contains("ivan@mail.ru"), toModel);
|
||||
}
|
||||
|
||||
@Test
|
||||
void consumerGetsTheAnswerWithOriginalValues() {
|
||||
JsonPath json = proxy(PROMPT);
|
||||
String answer = json.getString("response");
|
||||
|
||||
assertTrue(answer.contains("Иванову Ивану Ивановичу"), answer);
|
||||
assertTrue(answer.contains("4509 123456"), answer);
|
||||
assertTrue(answer.contains("ivan@mail.ru"), answer);
|
||||
}
|
||||
|
||||
@Test
|
||||
void responseShowsTheWholeChain() {
|
||||
JsonPath json = proxy(PROMPT);
|
||||
|
||||
assertTrue(json.getString("prompt_masked").contains("[FIO_1]"),
|
||||
"в модель уходит обратимая подстановка: " + json.getString("prompt_masked"));
|
||||
assertTrue(json.getString("llm_response_masked").contains("[FIO_1]"),
|
||||
"ответ модели ещё содержит подстановки");
|
||||
assertFalse(json.getString("response").contains("[FIO_1]"),
|
||||
"потребителю подстановки не видны");
|
||||
assertEquals("заглушка", json.getString("llm"));
|
||||
assertFalse(json.getMap("replaced").isEmpty(), "таблица замен не должна быть пустой");
|
||||
}
|
||||
|
||||
@Test
|
||||
void textWithoutPersonalDataPassesThrough() {
|
||||
JsonPath json = proxy("Объясни разницу между вкладом и накопительным счётом");
|
||||
assertEquals("Объясни разницу между вкладом и накопительным счётом", json.getString("prompt_masked"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsEmptyPrompt() {
|
||||
given().port(port).contentType("application/json").body(Map.of("prompt", " "))
|
||||
.when().post("/proxy").then().statusCode(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
void disabledSystemIsRefused() {
|
||||
given().port(port).contentType("application/json")
|
||||
.header("X-System-Id", "disabled")
|
||||
.body(Map.of("prompt", PROMPT))
|
||||
.when().post("/proxy").then().statusCode(403);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user