fix: resolve 25 SonarQube code smells across 21 files
Remove unused fields (log, rbacService, roleRepository, jwt), unused variables (agentTps, routeKeys, updated), unused imports (HttpHeaders, JdbcTemplate). Rename restricted identifier 'record' to 'auditRecord'/'event'. Return empty collections instead of null. Replace .collect(Collectors.toList()) with .toList(). Simplify conditional return in BootstrapTokenValidator. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,8 +11,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -34,8 +32,6 @@ import java.util.List;
|
||||
@Tag(name = "Ingestion", description = "Data ingestion endpoints")
|
||||
public class DiagramController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DiagramController.class);
|
||||
|
||||
private final IngestionService ingestionService;
|
||||
private final AgentRegistryService registryService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@@ -11,8 +11,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -39,8 +37,6 @@ import java.util.List;
|
||||
@Tag(name = "Ingestion", description = "Data ingestion endpoints")
|
||||
public class ExecutionController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ExecutionController.class);
|
||||
|
||||
private final IngestionService ingestionService;
|
||||
private final AgentRegistryService registryService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.cameleer3.server.core.admin.AuditService;
|
||||
import com.cameleer3.server.core.rbac.GroupDetail;
|
||||
import com.cameleer3.server.core.rbac.GroupRepository;
|
||||
import com.cameleer3.server.core.rbac.GroupSummary;
|
||||
import com.cameleer3.server.core.rbac.RbacService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -39,13 +38,10 @@ import java.util.UUID;
|
||||
public class GroupAdminController {
|
||||
|
||||
private final GroupRepository groupRepository;
|
||||
private final RbacService rbacService;
|
||||
private final AuditService auditService;
|
||||
|
||||
public GroupAdminController(GroupRepository groupRepository, RbacService rbacService,
|
||||
AuditService auditService) {
|
||||
public GroupAdminController(GroupRepository groupRepository, AuditService auditService) {
|
||||
this.groupRepository = groupRepository;
|
||||
this.rbacService = rbacService;
|
||||
this.auditService = auditService;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.cameleer3.server.app.controller;
|
||||
import com.cameleer3.server.core.admin.AuditCategory;
|
||||
import com.cameleer3.server.core.admin.AuditResult;
|
||||
import com.cameleer3.server.core.admin.AuditService;
|
||||
import com.cameleer3.server.core.rbac.RbacService;
|
||||
import com.cameleer3.server.core.rbac.RoleDetail;
|
||||
import com.cameleer3.server.core.rbac.RoleRepository;
|
||||
import com.cameleer3.server.core.rbac.SystemRole;
|
||||
@@ -37,13 +36,10 @@ import java.util.UUID;
|
||||
public class RoleAdminController {
|
||||
|
||||
private final RoleRepository roleRepository;
|
||||
private final RbacService rbacService;
|
||||
private final AuditService auditService;
|
||||
|
||||
public RoleAdminController(RoleRepository roleRepository, RbacService rbacService,
|
||||
AuditService auditService) {
|
||||
public RoleAdminController(RoleRepository roleRepository, AuditService auditService) {
|
||||
this.roleRepository = roleRepository;
|
||||
this.rbacService = rbacService;
|
||||
this.auditService = auditService;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,8 +82,6 @@ public class RouteCatalogController {
|
||||
Instant now = Instant.now();
|
||||
Instant rangeFrom = from != null ? Instant.parse(from) : now.minus(24, ChronoUnit.HOURS);
|
||||
Instant rangeTo = to != null ? Instant.parse(to) : now;
|
||||
Instant from1m = now.minus(1, ChronoUnit.MINUTES);
|
||||
|
||||
// Route exchange counts from AggregatingMergeTree (literal SQL — ClickHouse JDBC driver
|
||||
// wraps prepared statements in sub-queries that strip AggregateFunction column types)
|
||||
Map<String, Long> routeExchangeCounts = new LinkedHashMap<>();
|
||||
@@ -113,20 +111,6 @@ public class RouteCatalogController {
|
||||
}
|
||||
}
|
||||
|
||||
// Per-agent TPS from the last minute
|
||||
Map<String, Double> agentTps = new LinkedHashMap<>();
|
||||
try {
|
||||
jdbc.query(
|
||||
"SELECT application_id, countMerge(total_count) AS cnt " +
|
||||
"FROM stats_1m_route WHERE bucket >= " + lit(from1m) + " AND bucket < " + lit(now) +
|
||||
" GROUP BY application_id",
|
||||
rs -> {
|
||||
// This gives per-app TPS; we'll distribute among agents below
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// AggregatingMergeTree table may not exist yet
|
||||
}
|
||||
|
||||
// Build catalog entries — merge apps from agent registry + ClickHouse data
|
||||
Set<String> allAppIds = new LinkedHashSet<>(agentsByApp.keySet());
|
||||
allAppIds.addAll(routesByApp.keySet());
|
||||
|
||||
@@ -67,10 +67,6 @@ public class RouteMetricsController {
|
||||
}
|
||||
sql.append(" GROUP BY application_id, route_id ORDER BY application_id, route_id");
|
||||
|
||||
// Key struct for sparkline lookup
|
||||
record RouteKey(String appId, String routeId) {}
|
||||
List<RouteKey> routeKeys = new ArrayList<>();
|
||||
|
||||
List<RouteMetrics> metrics = jdbc.query(sql.toString(), (rs, rowNum) -> {
|
||||
String applicationId = rs.getString("application_id");
|
||||
String routeId = rs.getString("route_id");
|
||||
@@ -83,7 +79,6 @@ public class RouteMetricsController {
|
||||
double errorRate = total > 0 ? (double) failed / total : 0.0;
|
||||
double tps = windowSeconds > 0 ? (double) total / windowSeconds : 0.0;
|
||||
|
||||
routeKeys.add(new RouteKey(applicationId, routeId));
|
||||
return new RouteMetrics(routeId, applicationId, total, successRate,
|
||||
avgDur, p99Dur, errorRate, tps, List.of(), -1.0);
|
||||
});
|
||||
|
||||
@@ -136,7 +136,7 @@ public class SearchController {
|
||||
return ResponseEntity.ok(searchService.timeseriesForApp(from, end, buckets, application));
|
||||
}
|
||||
List<String> agentIds = resolveApplicationToAgentIds(application);
|
||||
if (routeId == null && agentIds == null) {
|
||||
if (routeId == null && agentIds.isEmpty()) {
|
||||
return ResponseEntity.ok(searchService.timeseries(from, end, buckets));
|
||||
}
|
||||
return ResponseEntity.ok(searchService.timeseries(from, end, buckets, routeId, agentIds));
|
||||
@@ -192,11 +192,11 @@ public class SearchController {
|
||||
|
||||
/**
|
||||
* Resolve an application name to agent IDs.
|
||||
* Returns null if application is null/blank (no filtering).
|
||||
* Returns empty list if application is null/blank (no filtering).
|
||||
*/
|
||||
private List<String> resolveApplicationToAgentIds(String application) {
|
||||
if (application == null || application.isBlank()) {
|
||||
return null;
|
||||
return List.of();
|
||||
}
|
||||
return registryService.findByApplication(application).stream()
|
||||
.map(AgentInfo::instanceId)
|
||||
|
||||
@@ -15,10 +15,10 @@ public record AgentEventResponse(
|
||||
String detail,
|
||||
@NotNull Instant timestamp
|
||||
) {
|
||||
public static AgentEventResponse from(AgentEventRecord record) {
|
||||
public static AgentEventResponse from(AgentEventRecord event) {
|
||||
return new AgentEventResponse(
|
||||
record.id(), record.instanceId(), record.applicationId(),
|
||||
record.eventType(), record.detail(), record.timestamp()
|
||||
event.id(), event.instanceId(), event.applicationId(),
|
||||
event.eventType(), event.detail(), event.timestamp()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package com.cameleer3.server.app.rbac;
|
||||
|
||||
import com.cameleer3.server.core.rbac.*;
|
||||
import com.cameleer3.server.core.rbac.GroupRepository;
|
||||
import com.cameleer3.server.core.rbac.GroupSummary;
|
||||
import com.cameleer3.server.core.rbac.RbacService;
|
||||
import com.cameleer3.server.core.rbac.RbacStats;
|
||||
import com.cameleer3.server.core.rbac.RoleSummary;
|
||||
import com.cameleer3.server.core.rbac.UserDetail;
|
||||
import com.cameleer3.server.core.rbac.UserSummary;
|
||||
import com.cameleer3.server.core.security.UserInfo;
|
||||
import com.cameleer3.server.core.security.UserRepository;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -14,14 +20,12 @@ public class RbacServiceImpl implements RbacService {
|
||||
private final JdbcTemplate jdbc;
|
||||
private final UserRepository userRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final RoleRepository roleRepository;
|
||||
|
||||
public RbacServiceImpl(JdbcTemplate jdbc, UserRepository userRepository,
|
||||
GroupRepository groupRepository, RoleRepository roleRepository) {
|
||||
GroupRepository groupRepository) {
|
||||
this.jdbc = jdbc;
|
||||
this.userRepository = userRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.roleRepository = roleRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,20 +31,12 @@ public class BootstrapTokenValidator {
|
||||
|
||||
byte[] providedBytes = provided.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
// Check current token
|
||||
// Check current token, then previous token (rotation support)
|
||||
String currentToken = properties.getBootstrapToken();
|
||||
if (currentToken != null
|
||||
&& MessageDigest.isEqual(providedBytes, currentToken.getBytes(StandardCharsets.UTF_8))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check previous token (rotation support)
|
||||
String previousToken = properties.getBootstrapTokenPrevious();
|
||||
if (previousToken != null
|
||||
&& MessageDigest.isEqual(providedBytes, previousToken.getBytes(StandardCharsets.UTF_8))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return (currentToken != null
|
||||
&& MessageDigest.isEqual(providedBytes, currentToken.getBytes(StandardCharsets.UTF_8)))
|
||||
|| (previousToken != null
|
||||
&& MessageDigest.isEqual(providedBytes, previousToken.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class PostgresApplicationConfigRepository {
|
||||
}
|
||||
|
||||
// Upsert: insert or update, auto-increment version
|
||||
int updated = jdbc.update("""
|
||||
jdbc.update("""
|
||||
INSERT INTO application_config (application, config_val, version, updated_at, updated_by)
|
||||
VALUES (?, ?::jsonb, 1, now(), ?)
|
||||
ON CONFLICT (application) DO UPDATE SET
|
||||
|
||||
@@ -34,11 +34,11 @@ public class PostgresAuditRepository implements AuditRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(AuditRecord record) {
|
||||
public void insert(AuditRecord auditRecord) {
|
||||
String detailJson = null;
|
||||
if (record.detail() != null) {
|
||||
if (auditRecord.detail() != null) {
|
||||
try {
|
||||
detailJson = objectMapper.writeValueAsString(record.detail());
|
||||
detailJson = objectMapper.writeValueAsString(auditRecord.detail());
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException("Failed to serialize audit detail", e);
|
||||
}
|
||||
@@ -48,11 +48,11 @@ public class PostgresAuditRepository implements AuditRepository {
|
||||
INSERT INTO audit_log (username, action, category, target, detail, result, ip_address, user_agent)
|
||||
VALUES (?, ?, ?, ?, ?::jsonb, ?, ?, ?)
|
||||
""",
|
||||
record.username(), record.action(),
|
||||
record.category() != null ? record.category().name() : null,
|
||||
record.target(), detailJson,
|
||||
record.result() != null ? record.result().name() : null,
|
||||
record.ipAddress(), record.userAgent());
|
||||
auditRecord.username(), auditRecord.action(),
|
||||
auditRecord.category() != null ? auditRecord.category().name() : null,
|
||||
auditRecord.target(), detailJson,
|
||||
auditRecord.result() != null ? auditRecord.result().name() : null,
|
||||
auditRecord.ipAddress(), auditRecord.userAgent());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -27,12 +27,11 @@ class SecurityFilterIT extends AbstractPostgresIT {
|
||||
@Autowired
|
||||
private TestSecurityHelper securityHelper;
|
||||
|
||||
private String jwt;
|
||||
private String viewerJwt;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
jwt = securityHelper.registerTestAgent("test-agent-security-filter-it");
|
||||
securityHelper.registerTestAgent("test-agent-security-filter-it");
|
||||
viewerJwt = securityHelper.viewerToken();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.List;
|
||||
|
||||
public interface AuditRepository {
|
||||
|
||||
void insert(AuditRecord record);
|
||||
void insert(AuditRecord auditRecord);
|
||||
|
||||
record AuditQuery(
|
||||
String username,
|
||||
|
||||
@@ -30,9 +30,9 @@ public class AuditService {
|
||||
HttpServletRequest request) {
|
||||
String ip = request != null ? request.getRemoteAddr() : null;
|
||||
String userAgent = request != null ? request.getHeader("User-Agent") : null;
|
||||
AuditRecord record = AuditRecord.create(username, action, category, target, detail, result, ip, userAgent);
|
||||
AuditRecord auditRecord = AuditRecord.create(username, action, category, target, detail, result, ip, userAgent);
|
||||
|
||||
repository.insert(record);
|
||||
repository.insert(auditRecord);
|
||||
|
||||
if (request != null) {
|
||||
request.setAttribute("audit.logged", true);
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* In-memory agent registry managing agent lifecycle, heartbeats, and commands.
|
||||
@@ -53,7 +53,7 @@ public class AgentRegistryService {
|
||||
List.copyOf(routeIds), Map.copyOf(capabilities),
|
||||
AgentState.LIVE, now, now, null);
|
||||
|
||||
AgentInfo result = agents.compute(id, (key, existing) -> {
|
||||
return agents.compute(id, (key, existing) -> {
|
||||
if (existing != null) {
|
||||
// Re-registration: update metadata, reset to LIVE
|
||||
log.info("Agent {} re-registering (was {})", id, existing.state());
|
||||
@@ -67,8 +67,6 @@ public class AgentRegistryService {
|
||||
log.info("Agent {} registered (name={}, application={})", id, name, application);
|
||||
return newAgent;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +194,7 @@ public class AgentRegistryService {
|
||||
public List<AgentInfo> findByState(AgentState state) {
|
||||
return agents.values().stream()
|
||||
.filter(a -> a.state() == state)
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,7 +203,7 @@ public class AgentRegistryService {
|
||||
public List<AgentInfo> findByApplication(String application) {
|
||||
return agents.values().stream()
|
||||
.filter(a -> application.equals(a.applicationId()))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +274,7 @@ public class AgentRegistryService {
|
||||
}
|
||||
return queue.stream()
|
||||
.filter(cmd -> cmd.status() == CommandStatus.PENDING)
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,7 @@ public class DetailService {
|
||||
// Prefer the raw processor tree (faithful to agent data) over
|
||||
// flat-record reconstruction (which loses iteration context).
|
||||
List<ProcessorNode> processors = parseProcessorsJson(exec.processorsJson());
|
||||
if (processors == null) {
|
||||
if (processors.isEmpty()) {
|
||||
// Fallback for executions ingested before processors_json was added
|
||||
List<ProcessorRecord> records = executionStore.findProcessors(executionId);
|
||||
processors = buildTree(records);
|
||||
@@ -78,12 +78,12 @@ public class DetailService {
|
||||
|
||||
/** Parse the raw processor tree JSON stored alongside the execution. */
|
||||
private List<ProcessorNode> parseProcessorsJson(String json) {
|
||||
if (json == null || json.isBlank()) return null;
|
||||
if (json == null || json.isBlank()) return List.of();
|
||||
try {
|
||||
List<ProcessorExecution> executions = JSON.readValue(json, PROCESSOR_EXEC_LIST);
|
||||
return convertProcessors(executions);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user