Skip to content

Conversation

Fabinatix97
Copy link
Member

@Fabinatix97 Fabinatix97 commented Sep 15, 2025

Pull Request

Changes

  • Added a boolean is_whitelisted tag to the exisiting metrics

Checklist

General

  • Met all acceptance criteria of the issue
  • Added meaningful PR title and list of changes in the description

Code

  • Wrote code and comments in English
  • Added unit tests
  • Removed waste on branch (e.g. console.log), see code quality tooling

Backend

  • Added integration tests

Summary by CodeRabbit

  • New Features
    • Metrics now include an is_whitelisted tag to indicate whether a request originates from a whitelisted source address, available on challenge requests, verification success, and client solve time. This enables improved filtering and analysis in monitoring dashboards without changing existing behavior.
  • Tests
    • Added coverage for whitelisted source scenarios and updated existing metric assertions to include the is_whitelisted tag across relevant metrics.

Copy link
Contributor

coderabbitai bot commented Sep 15, 2025

Walkthrough

Adds an is_whitelisted metric tag to three captcha-related metrics by deriving it from DifficultyService.isSourceAddressWhitelisted. Updates tests to validate the new tag for both whitelisted and non-whitelisted source addresses without changing public APIs or error handling.

Changes

Cohort / File(s) Summary
Metrics tagging
captchaservice-backend/src/main/java/de/muenchen/captchaservice/service/metrics/MetricsService.java
Adds is_whitelisted tag to captcha.challenge.requests (Counter), captcha.verify.success (Counter), and captcha.client.solve.time (DistributionSummary), using DifficultyService.isSourceAddressWhitelisted(siteKey, sourceAddress).
Controller tests update
captchaservice-backend/src/test/java/de/muenchen/captchaservice/controller/captcha/CaptchaControllerTest.java
Introduces a whitelisted test address and a new test asserting is_whitelisted=true for challenge metrics; extends existing tests to assert is_whitelisted=false for non-whitelisted cases across challenge, verify, and client solve time metrics.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant CaptchaController
  participant MetricsService
  participant DifficultyService
  participant MetricsRegistry

  Client->>CaptchaController: POST /captcha/challenge or /verify
  CaptchaController->>MetricsService: record metrics (siteKey, sourceAddress, ...)
  MetricsService->>DifficultyService: isSourceAddressWhitelisted(siteKey, sourceAddress)
  DifficultyService-->>MetricsService: boolean isWhitelisted
  rect rgba(213,232,255,0.4)
    note right of MetricsService: Tag metrics with is_whitelisted = isWhitelisted
    MetricsService->>MetricsRegistry: increment/record with tags<br/>site_key, difficulty, is_whitelisted
  end
  MetricsRegistry-->>MetricsService: ack
  MetricsService-->>CaptchaController: done
  CaptchaController-->>Client: response
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I hopped through tags with metric delight,
Adding whitelist whispers to chart the night.
Counters click, summaries chime,
True or false, all neatly in line.
With ears up high, I log and I cheer—
Observability’s carrot is crystal clear. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Add is_whitelisted tag to captcha metrics" is a concise, single-sentence summary that accurately describes the primary change in the changeset — adding an is_whitelisted boolean tag to captcha-related metrics. It is specific to the main observable change, free of file lists or noise, and would be clear to a teammate scanning PR history. No rewording is required.
Description Check ✅ Passed The PR description follows the repository template structure by including Links, a Changes section stating the addition of an is_whitelisted metric tag, and a Checklist indicating tests were added; it therefore documents the core intent and test coverage. However the template's "Reference" (Issue: #XXX) line is missing and the Changes section is minimal — it does not list the specific metrics affected (captcha.challenge.requests, captcha.verify.success, captcha.client.solve.time) or name the new test that was added. Overall the description is mostly complete and actionable but would benefit from these additions for traceability.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-whitelisted-ip-metrics-tag

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 42b61f3 and 4de3dd5.

📒 Files selected for processing (2)
  • captchaservice-backend/src/main/java/de/muenchen/captchaservice/service/metrics/MetricsService.java (2 hunks)
  • captchaservice-backend/src/test/java/de/muenchen/captchaservice/controller/captcha/CaptchaControllerTest.java (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: codeql / Analyze Java source files (./captchaservice-backend)
🔇 Additional comments (1)
captchaservice-backend/src/test/java/de/muenchen/captchaservice/controller/captcha/CaptchaControllerTest.java (1)

282-284: Assertions look right for non‑whitelisted path.

LGTM; asserts both the evolving request_count and is_whitelisted=false.

Comment on lines +36 to 47
final boolean isWhitelisted = difficultyService.isSourceAddressWhitelisted(siteKey, sourceAddress);
long sameSourceAddressRequestCount = getSameSourceAddressRequestCount(sourceAddress);

Counter.builder("captcha.challenge.requests")
.tag("site_key", siteKey)
.tag("difficulty", String.valueOf(difficulty))
.tag("same_source_address_request_count", String.valueOf(sameSourceAddressRequestCount))
.tag("is_whitelisted", String.valueOf(isWhitelisted))
.description("Counter for captcha challenge requests")
.register(meterRegistry)
.increment();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

New tag changes meter identity; also flag high-cardinality tag risk.

  • Adding is_whitelisted changes the time‑series identity for captcha.challenge.requests. Coordinate dashboard/alert updates and backfills.
  • Pre‑existing tag same_source_address_request_count creates unbounded series (new time series per request count). This is a metrics anti‑pattern and can explode cardinality. Remove it or encode it as a measurement/bucketed histogram instead.

Apply this diff to drop the risky tag (not introduced by this PR, but strongly recommended):

 Counter.builder("captcha.challenge.requests")
     .tag("site_key", siteKey)
     .tag("difficulty", String.valueOf(difficulty))
-    .tag("same_source_address_request_count", String.valueOf(sameSourceAddressRequestCount))
     .tag("is_whitelisted", String.valueOf(isWhitelisted))

To check for dashboards/alerts using this metric:


🏁 Script executed:

#!/bin/bash
rg -nP -C2 'captcha\.challenge\.requests|captcha\.verify\.success|captcha\.client\.solve\.time'

Length of output: 5720


Remove high‑cardinality tag "same_source_address_request_count" from all captcha metrics; coordinate any "is_whitelisted" identity change.

  • The numeric tag same_source_address_request_count is present as a tag in MetricsService.java for: captcha.challenge.requests, captcha.verify.success, and captcha.client.solve.time (MetricsService.java ~lines 37–41, 52–56, 72–76). A count used as a tag creates effectively unbounded cardinality — remove it or record it as a measurement/histogram with bucketed ranges.
  • is_whitelisted is present in the metrics and asserted in tests (CaptchaControllerTest); adding/changing it alters time‑series identity — update dashboards/alerts and backfill as needed.

Apply this removal in each metric builder:

-.tag("same_source_address_request_count", String.valueOf(sameSourceAddressRequestCount))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final boolean isWhitelisted = difficultyService.isSourceAddressWhitelisted(siteKey, sourceAddress);
long sameSourceAddressRequestCount = getSameSourceAddressRequestCount(sourceAddress);
Counter.builder("captcha.challenge.requests")
.tag("site_key", siteKey)
.tag("difficulty", String.valueOf(difficulty))
.tag("same_source_address_request_count", String.valueOf(sameSourceAddressRequestCount))
.tag("is_whitelisted", String.valueOf(isWhitelisted))
.description("Counter for captcha challenge requests")
.register(meterRegistry)
.increment();
}
final boolean isWhitelisted = difficultyService.isSourceAddressWhitelisted(siteKey, sourceAddress);
long sameSourceAddressRequestCount = getSameSourceAddressRequestCount(sourceAddress);
Counter.builder("captcha.challenge.requests")
.tag("site_key", siteKey)
.tag("difficulty", String.valueOf(difficulty))
.tag("is_whitelisted", String.valueOf(isWhitelisted))
.description("Counter for captcha challenge requests")
.register(meterRegistry)
.increment();
}

Comment on lines +51 to 59
final boolean isWhitelisted = difficultyService.isSourceAddressWhitelisted(siteKey, sourceAddress);
long sameSourceAddressRequestCount = getSameSourceAddressRequestCount(sourceAddress);

Counter.builder("captcha.verify.success")
.tag("site_key", siteKey)
.tag("difficulty", String.valueOf(difficulty))
.tag("same_source_address_request_count", String.valueOf(sameSourceAddressRequestCount))
.tag("is_whitelisted", String.valueOf(isWhitelisted))
.description("Counter for captcha verify success requests")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Avoid duplicate lookups if possible.

If DifficultyService can expose a single call returning both difficulty and whitelisted status, prefer that to reduce I/O/CPU on hot paths. Otherwise, LGTM.

🤖 Prompt for AI Agents
In
captchaservice-backend/src/main/java/de/muenchen/captchaservice/service/metrics/MetricsService.java
around lines 51 to 59, the code calls difficultyService twice to obtain
difficulty and whitelisted status which causes duplicate lookups on a hot path;
change DifficultyService to expose a single method (e.g., getDifficultyInfo or a
DTO like DifficultyInfo {int difficulty; boolean isWhitelisted}) that returns
both values in one call, update the service implementation accordingly, and
replace the two separate calls in MetricsService with a single call that unpacks
the difficulty and isWhitelisted values for the metric tags.

Comment on lines 70 to 79
final long difficulty = difficultyService.getDifficultyForSourceAddress(siteKey, sourceAddress);
final boolean isWhitelisted = difficultyService.isSourceAddressWhitelisted(siteKey, sourceAddress);
long sameSourceAddressRequestCount = getSameSourceAddressRequestCount(sourceAddress);

DistributionSummary.builder("captcha.client.solve.time")
.tag("site_key", siteKey)
.tag("difficulty", String.valueOf(difficulty))
.tag("same_source_address_request_count", String.valueOf(sameSourceAddressRequestCount))
.tag("is_whitelisted", String.valueOf(isWhitelisted))
.description("Summary of the time taken by clients to solve captcha challenges")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consistent tagging; please add whitelisted-path coverage.

Tagging is consistent. Add tests that assert is_whitelisted=true for verify and client.solve.time as well.

🤖 Prompt for AI Agents
In
captchaservice-backend/src/main/java/de/muenchen/captchaservice/service/metrics/MetricsService.java
around lines 70 to 79, tests and metric coverage are missing for the
whitelisted-path case; add unit/integration tests that exercise the whitelisted
verification and client.solve.time flows with a whitelisted sourceAddress so the
emitted metrics include is_whitelisted=true, and assert the metric tags for both
"verify" and "captcha.client.solve.time" contain is_whitelisted=true (and
include any whitelisted-path tag if your metric schema requires it); ensure the
test sets up difficultyService.isSourceAddressWhitelisted(...) to return true,
invokes the verify and client solve endpoints/services, and asserts the created
DistributionSummary/metric tags contain the expected whitelisted values.

@@ -55,6 +55,7 @@ class CaptchaControllerTest {
private static final String TEST_SITE_SECRET = "test_secret";
private static final String TEST_HMAC_KEY = "secret";
private static final String TEST_CLIENT_ADDRESS = "1.2.3.4";
private static final String TEST_WHITELISTED_ADDRESS = "10.0.0.0";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Use a host address, not the network address.

10.0.0.0 can be treated as a network address. Prefer 10.0.0.1 (still private/whitelisted) to avoid edge‑case parser behavior.

-    private static final String TEST_WHITELISTED_ADDRESS = "10.0.0.0";
+    private static final String TEST_WHITELISTED_ADDRESS = "10.0.0.1";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static final String TEST_WHITELISTED_ADDRESS = "10.0.0.0";
private static final String TEST_WHITELISTED_ADDRESS = "10.0.0.1";
🤖 Prompt for AI Agents
In
captchaservice-backend/src/test/java/de/muenchen/captchaservice/controller/captcha/CaptchaControllerTest.java
around line 58, the test uses the network address "10.0.0.0" as
TEST_WHITELISTED_ADDRESS which can be interpreted as a network rather than a
host; change the constant to a valid host address such as "10.0.0.1" (or another
private host IP) so parsers treat it as a host and update any dependent
assertions or mocks if they reference the constant.

Comment on lines +240 to +260
@Test
@SneakyThrows
void testChallengeMetricsWhiteListedSourceAddress() {
final PostChallengeRequest challengeRequest = new PostChallengeRequest(TEST_SITE_KEY, TEST_SITE_SECRET, TEST_WHITELISTED_ADDRESS);
final String challengeRequestBody = objectMapper.writeValueAsString(challengeRequest);

mockMvc.perform(
post("/api/v1/captcha/challenge")
.content(challengeRequestBody)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());

mockMvc.perform(
get("/actuator/metrics/captcha.challenge.requests"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.measurements[0].value", is(1.0)))
.andExpect(jsonPath("$.availableTags[?(@.tag=='difficulty')].values[0]", hasItem("1")))
.andExpect(jsonPath("$.availableTags[?(@.tag=='site_key')].values[0]", hasItem("test_site")))
.andExpect(jsonPath("$.availableTags[?(@.tag=='same_source_address_request_count')].values[*]", hasItem("1")))
.andExpect(jsonPath("$.availableTags[?(@.tag=='is_whitelisted')].values[0]", hasItem("true")));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Stabilize test preconditions and whitelist source.

  • Clear DB before asserting same_source_address_request_count == 1 to avoid flakiness from leftover state.
  • Ensure the whitelist actually contains TEST_WHITELISTED_ADDRESS in tests (property or stub DifficultyService) so the test isn’t env‑dependent.
 @Test
 @SneakyThrows
 void testChallengeMetricsWhiteListedSourceAddress() {
+    databaseTestUtil.clearDatabase();
     final PostChallengeRequest challengeRequest = new PostChallengeRequest(TEST_SITE_KEY, TEST_SITE_SECRET, TEST_WHITELISTED_ADDRESS);

If needed, I can add a @DynamicPropertySource to inject the whitelist CIDR for tests.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +314 to 316
.andExpect(jsonPath("$.availableTags[?(@.tag=='same_source_address_request_count')]").exists())
.andExpect(jsonPath("$.availableTags[?(@.tag=='is_whitelisted')].values[0]", hasItem("false")));

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Extend coverage to whitelisted verify/solve‑time.

Consider adding mirror tests using TEST_WHITELISTED_ADDRESS to assert is_whitelisted=true for captcha.verify.success and captcha.client.solve.time.

Also applies to: 324-326

🤖 Prompt for AI Agents
In
captchaservice-backend/src/test/java/de/muenchen/captchaservice/controller/captcha/CaptchaControllerTest.java
around lines 314-316 (and similarly 324-326), tests assert is_whitelisted=false
for certain metrics but lack mirror cases for a whitelisted address; add
parallel test flows using TEST_WHITELISTED_ADDRESS that exercise
captcha.verify.success and captcha.client.solve.time and assert the JSON
responses contain is_whitelisted=true (e.g., the availableTags entries for these
events should have is_whitelisted true and related value assertions); ensure the
test setup uses the whitelisted constant for request origin, performs the same
requests as the existing non-whitelisted tests, and adds jsonPath assertions
checking is_whitelisted equals true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant