fix(alerts): backend hardening + complete ACKNOWLEDGED migration

- new AlertInstanceRepository.filterInEnvLive(ids, env): single-query bulk ID validation
- AlertController.inEnvLiveIds now one SQL round-trip instead of N
- bulkMarkRead SQL: defense-in-depth AND deleted_at IS NULL
- bulkAck SQL already had deleted_at IS NULL guard — no change needed
- PostgresAlertInstanceRepositoryIT: add filterInEnvLive_excludes_other_env_and_soft_deleted
- V12MigrationIT: remove alert_reads assertion (table dropped by V17)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-21 18:48:57 +02:00
parent c70fa130ab
commit 99b739d946
5 changed files with 34 additions and 8 deletions

View File

@@ -372,6 +372,18 @@ class PostgresAlertInstanceRepositoryIT extends AbstractPostgresIT {
assertThat(rows).extracting(AlertInstance::id).contains(inst.id());
}
@Test
void filterInEnvLive_excludes_other_env_and_soft_deleted() {
var a = insertFreshFiring(); // env envId, live
var b = insertFreshFiring(); // env envId, will be soft-deleted
repo.softDelete(b.id(), Instant.now());
UUID unknownId = UUID.randomUUID(); // not in DB at all
var kept = repo.filterInEnvLive(List.of(a.id(), b.id(), unknownId), envId);
assertThat(kept).containsExactly(a.id());
}
// -------------------------------------------------------------------------
/** Creates and saves a fresh FIRING instance targeted at the test userId with its own rule. */

View File

@@ -22,14 +22,15 @@ class V12MigrationIT extends AbstractPostgresIT {
@Test
void allAlertingTablesAndEnumsExist() {
// Note: alert_reads was created in V12 but dropped by V17 (superseded by read_at column).
var tables = jdbcTemplate.queryForList(
"SELECT table_name FROM information_schema.tables WHERE table_schema='public' " +
"AND table_name IN ('alert_rules','alert_rule_targets','alert_instances'," +
"'alert_silences','alert_notifications','alert_reads')",
"'alert_silences','alert_notifications')",
String.class);
assertThat(tables).containsExactlyInAnyOrder(
"alert_rules","alert_rule_targets","alert_instances",
"alert_silences","alert_notifications","alert_reads");
"alert_silences","alert_notifications");
var enums = jdbcTemplate.queryForList(
"SELECT typname FROM pg_type WHERE typname IN " +