fix(events): reject malformed pagination cursors as 400 errors

Wraps DateTimeParseException from Instant.parse in IllegalArgumentException
so the controller maps it to 400. Also rejects cursors with empty
instance_id (trailing '|') which would otherwise produce a vacuous
keyset predicate.
This commit is contained in:
hsiegeln
2026-04-17 12:02:40 +02:00
parent d293dafb99
commit 0194549f25
2 changed files with 29 additions and 2 deletions

View File

@@ -80,10 +80,15 @@ public class ClickHouseAgentEventRepository implements AgentEventRepository {
if (cursor != null && !cursor.isEmpty()) {
String decoded = new String(Base64.getUrlDecoder().decode(cursor), StandardCharsets.UTF_8);
int bar = decoded.indexOf('|');
if (bar <= 0) {
if (bar <= 0 || bar == decoded.length() - 1) {
throw new IllegalArgumentException("Malformed cursor");
}
Instant cursorTs = Instant.parse(decoded.substring(0, bar));
Instant cursorTs;
try {
cursorTs = Instant.parse(decoded.substring(0, bar));
} catch (java.time.format.DateTimeParseException e) {
throw new IllegalArgumentException("Malformed cursor", e);
}
String cursorInstance = decoded.substring(bar + 1);
sql.append(" AND (timestamp < ? OR (timestamp = ? AND instance_id > ?))");
params.add(Timestamp.from(cursorTs));

View File

@@ -227,4 +227,26 @@ class ClickHouseAgentEventRepositoryIT {
assertThat(p2.data().get(0).instanceId()).isEqualTo("agent-z");
assertThat(p2.hasMore()).isFalse();
}
@Test
void queryPage_malformedCursor_invalidTimestamp_throws() {
String raw = "not-a-timestamp|agent-1";
String cursor = java.util.Base64.getUrlEncoder().withoutPadding()
.encodeToString(raw.getBytes(java.nio.charset.StandardCharsets.UTF_8));
org.junit.jupiter.api.Assertions.assertThrows(
IllegalArgumentException.class,
() -> repo.queryPage(null, null, null, null, null, cursor, 10));
}
@Test
void queryPage_malformedCursor_emptyInstanceId_throws() {
String raw = "2026-04-01T10:00:00Z|";
String cursor = java.util.Base64.getUrlEncoder().withoutPadding()
.encodeToString(raw.getBytes(java.nio.charset.StandardCharsets.UTF_8));
org.junit.jupiter.api.Assertions.assertThrows(
IllegalArgumentException.class,
() -> repo.queryPage(null, null, null, null, null, cursor, 10));
}
}