fix(outbound): wire rulesReferencing to AlertRuleRepository (Plan 01 gate)
Replaces the Plan 01 stub that returned [] with a real call through AlertRuleRepository.findRuleIdsByOutboundConnectionId. Adds AlertingBeanConfig exposing the AlertRuleRepository bean; widens OutboundBeanConfig constructor to inject it. Delete and narrow-envs guards now correctly block when rules reference a connection. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package com.cameleer.server.app.alerting.config;
|
||||
|
||||
import com.cameleer.server.app.alerting.storage.PostgresAlertRuleRepository;
|
||||
import com.cameleer.server.core.alerting.AlertRuleRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
@Configuration
|
||||
public class AlertingBeanConfig {
|
||||
|
||||
@Bean
|
||||
public AlertRuleRepository alertRuleRepository(JdbcTemplate jdbc, ObjectMapper om) {
|
||||
return new PostgresAlertRuleRepository(jdbc, om);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.cameleer.server.app.outbound;
|
||||
|
||||
import com.cameleer.server.core.alerting.AlertRuleRepository;
|
||||
import com.cameleer.server.core.outbound.OutboundConnection;
|
||||
import com.cameleer.server.core.outbound.OutboundConnectionRepository;
|
||||
import com.cameleer.server.core.outbound.OutboundConnectionService;
|
||||
@@ -13,10 +14,15 @@ import java.util.UUID;
|
||||
public class OutboundConnectionServiceImpl implements OutboundConnectionService {
|
||||
|
||||
private final OutboundConnectionRepository repo;
|
||||
private final AlertRuleRepository ruleRepo;
|
||||
private final String tenantId;
|
||||
|
||||
public OutboundConnectionServiceImpl(OutboundConnectionRepository repo, String tenantId) {
|
||||
public OutboundConnectionServiceImpl(
|
||||
OutboundConnectionRepository repo,
|
||||
AlertRuleRepository ruleRepo,
|
||||
String tenantId) {
|
||||
this.repo = repo;
|
||||
this.ruleRepo = ruleRepo;
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
@@ -91,8 +97,7 @@ public class OutboundConnectionServiceImpl implements OutboundConnectionService
|
||||
|
||||
@Override
|
||||
public List<UUID> rulesReferencing(UUID id) {
|
||||
// Plan 01 stub. Plan 02 will wire this to AlertRuleRepository.
|
||||
return List.of();
|
||||
return ruleRepo.findRuleIdsByOutboundConnectionId(id);
|
||||
}
|
||||
|
||||
private void assertNameUnique(String name, UUID excludingId) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.cameleer.server.app.outbound.config;
|
||||
import com.cameleer.server.app.outbound.OutboundConnectionServiceImpl;
|
||||
import com.cameleer.server.app.outbound.crypto.SecretCipher;
|
||||
import com.cameleer.server.app.outbound.storage.PostgresOutboundConnectionRepository;
|
||||
import com.cameleer.server.core.alerting.AlertRuleRepository;
|
||||
import com.cameleer.server.core.outbound.OutboundConnectionRepository;
|
||||
import com.cameleer.server.core.outbound.OutboundConnectionService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -29,7 +30,8 @@ public class OutboundBeanConfig {
|
||||
@Bean
|
||||
public OutboundConnectionService outboundConnectionService(
|
||||
OutboundConnectionRepository repo,
|
||||
AlertRuleRepository ruleRepo,
|
||||
@Value("${cameleer.server.tenant.id:default}") String tenantId) {
|
||||
return new OutboundConnectionServiceImpl(repo, tenantId);
|
||||
return new OutboundConnectionServiceImpl(repo, ruleRepo, tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.cameleer.server.app.outbound;
|
||||
|
||||
import com.cameleer.server.app.AbstractPostgresIT;
|
||||
import com.cameleer.server.app.alerting.storage.PostgresAlertRuleRepository;
|
||||
import com.cameleer.server.core.alerting.*;
|
||||
import com.cameleer.server.core.http.TrustMode;
|
||||
import com.cameleer.server.core.outbound.*;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class OutboundConnectionServiceRulesReferencingIT extends AbstractPostgresIT {
|
||||
|
||||
@Autowired OutboundConnectionService service;
|
||||
@Autowired OutboundConnectionRepository repo;
|
||||
|
||||
private UUID envId;
|
||||
private UUID connId;
|
||||
private UUID ruleId;
|
||||
private PostgresAlertRuleRepository ruleRepo;
|
||||
|
||||
@BeforeEach
|
||||
void seed() {
|
||||
ruleRepo = new PostgresAlertRuleRepository(jdbcTemplate, new ObjectMapper());
|
||||
envId = UUID.randomUUID();
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO environments (id, slug, display_name) VALUES (?, ?, ?)",
|
||||
envId, "env-" + UUID.randomUUID(), "Test Env");
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO users (user_id, provider, email) VALUES ('u-ref', 'local', 'a@b.test')" +
|
||||
" ON CONFLICT (user_id) DO NOTHING");
|
||||
|
||||
var c = repo.save(new OutboundConnection(
|
||||
UUID.randomUUID(), "default", "conn-" + UUID.randomUUID(), null,
|
||||
"https://example.test", OutboundMethod.POST,
|
||||
Map.of(), null, TrustMode.SYSTEM_DEFAULT, List.of(), null,
|
||||
new OutboundAuth.None(), List.of(),
|
||||
Instant.now(), "u-ref", Instant.now(), "u-ref"));
|
||||
connId = c.id();
|
||||
|
||||
ruleId = UUID.randomUUID();
|
||||
var rule = new AlertRule(
|
||||
ruleId, envId, "r", null, AlertSeverity.WARNING, true,
|
||||
ConditionKind.AGENT_STATE,
|
||||
new AgentStateCondition(new AlertScope(null, null, null), "DEAD", 60),
|
||||
60, 0, 60, "t", "m",
|
||||
List.of(new WebhookBinding(UUID.randomUUID(), connId, null, Map.of())),
|
||||
List.of(), Instant.now(), null, null, Map.of(),
|
||||
Instant.now(), "u-ref", Instant.now(), "u-ref");
|
||||
ruleRepo.save(rule);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
jdbcTemplate.update("DELETE FROM alert_rules WHERE id = ?", ruleId);
|
||||
jdbcTemplate.update("DELETE FROM outbound_connections WHERE id = ?", connId);
|
||||
jdbcTemplate.update("DELETE FROM environments WHERE id = ?", envId);
|
||||
jdbcTemplate.update("DELETE FROM users WHERE user_id = 'u-ref'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteConnectionReferencedByRuleReturns409() {
|
||||
assertThat(service.rulesReferencing(connId)).hasSize(1);
|
||||
assertThatThrownBy(() -> service.delete(connId, "u-ref"))
|
||||
.isInstanceOf(ResponseStatusException.class)
|
||||
.hasMessageContaining("referenced by rules");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user