fix: resolve 25 SonarQube code smells across 21 files
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m2s
CI / docker (push) Successful in 45s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 38s

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:
hsiegeln
2026-04-04 09:36:13 +02:00
parent 633a61d89d
commit b04b12220b
21 changed files with 42 additions and 90 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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());

View File

@@ -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);
});

View File

@@ -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)

View File

@@ -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()
);
}
}

View File

@@ -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

View File

@@ -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)));
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -5,7 +5,7 @@ import java.util.List;
public interface AuditRepository {
void insert(AuditRecord record);
void insert(AuditRecord auditRecord);
record AuditQuery(
String username,

View File

@@ -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);

View File

@@ -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();
}
/**

View File

@@ -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();
}
}