From 9aff1a00e91d5d51b42081bdc8b76aa728ffaf03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=97=D0=B8=D0=BC=D0=B8=D0=BD?= Date: Tue, 9 Jun 2026 14:24:39 +0000 Subject: [PATCH] =?UTF-8?q?fix(dict):=20explicit=20Java=20filter=20?= =?UTF-8?q?=E2=80=94=20soft-deleted=20leak=20=D0=B2=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/DictionaryDefinitionService.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/service/DictionaryDefinitionService.java b/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/service/DictionaryDefinitionService.java index f38b092..fc4f2de 100644 --- a/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/service/DictionaryDefinitionService.java +++ b/ordinis-rest-api/src/main/java/cloud/nstart/terravault/ordinis/restapi/service/DictionaryDefinitionService.java @@ -45,16 +45,29 @@ public class DictionaryDefinitionService { @Transactional(readOnly = true) public List findAll() { - // findAllActive — excludes soft-deleted (migration 0031). findAllIncludingDeleted - // для admin Корзина page (см. findAllDeleted() ниже). - return repository.findAllActive(); + // Defense-in-depth: explicit Java filter поверх JPQL `WHERE deleted_at IS NULL`. + // Spring Data может interpretировать @Query inconsistently если derived query + // matches method name — explicit .filter() guarantees no soft-deleted leak + // в list endpoint независимо от Repository implementation details. + return repository.findAllActive().stream() + .filter(d -> !d.isDeleted()) + .toList(); } @Transactional(readOnly = true) public DictionaryDefinition findByName(String name) { - return repository.findByName(name) + // Use derived findByName (Repository @Query filters deleted_at IS NULL). + // Если что-то проскочило (Spring Data quirk) — explicit isDeleted() check + // ниже. Cascade на ChangelogServiceTest / SchemaPatchServiceTest mocks: + // тесты stub`ают этот метод; ломать API сигнатуру не надо. + DictionaryDefinition d = repository.findByName(name) .orElseThrow(() -> OrdinisException.notFound( "dictionary_not_found", "Dictionary not found: " + name)); + if (d.isDeleted()) { + throw OrdinisException.notFound( + "dictionary_not_found", "Dictionary not found: " + name); + } + return d; } @Transactional(readOnly = true)