Merge branch 'fix/dict-list-exclude-deleted' into 'main'

fix(dict): explicit Java filter — soft-deleted leak в list

See merge request 2-6/2-6-4/terravault/ordinis!298
This commit is contained in:
Александр Зимин
2026-06-09 14:24:39 +00:00
@@ -45,16 +45,29 @@ public class DictionaryDefinitionService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<DictionaryDefinition> findAll() { public List<DictionaryDefinition> findAll() {
// findAllActive — excludes soft-deleted (migration 0031). findAllIncludingDeleted // Defense-in-depth: explicit Java filter поверх JPQL `WHERE deleted_at IS NULL`.
// для admin Корзина page (см. findAllDeleted() ниже). // Spring Data может interpretировать @Query inconsistently если derived query
return repository.findAllActive(); // 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) @Transactional(readOnly = true)
public DictionaryDefinition findByName(String name) { 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( .orElseThrow(() -> OrdinisException.notFound(
"dictionary_not_found", "Dictionary not found: " + name)); "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) @Transactional(readOnly = true)