Skip to content

Conversation

@everettbu
Copy link

@everettbu everettbu commented Jul 26, 2025

Test 1

Summary by CodeRabbit

  • New Features

    • Introduced a configurable limit for anonymous devices, allowing administrators to set a maximum number of anonymous device connections.
    • Added new configuration options to manage anonymous device limits via system settings and configuration files.
  • Bug Fixes

    • Improved error handling when the anonymous device limit is reached, providing clearer feedback to users.
  • Tests

    • Added tests to verify enforcement of the anonymous device limit and related behaviors.
  • Refactor

    • Streamlined configuration reading and internal logic for managing anonymous device settings.

* Anonymous: Add device limiter

* break auth if limit reached

* fix typo

* refactored const to make it clearer with expiration

* anon device limit for config

---------

Co-authored-by: Eric Leijonmarck <eric.leijonmarck@gmail.com>
@coderabbitai
Copy link

coderabbitai bot commented Jul 26, 2025

Walkthrough

A device limit for anonymous users was introduced across multiple layers of the system. New configuration fields were added to backend and frontend config structures, device limit enforcement was implemented in the anonymous device database store, and related tests and service wiring were updated. Error handling and configuration reading logic were adjusted accordingly.

Changes

File(s) Change Summary
packages/grafana-data/src/types/config.ts, packages/grafana-runtime/src/config.ts Added anonymousDeviceLimit property/field to frontend config interfaces/classes.
pkg/api/dtos/frontend_settings.go, pkg/setting/setting.go Added AnonymousDeviceLimit field to backend config/data transfer structs.
pkg/api/frontendsettings.go Populates AnonymousDeviceLimit in frontend settings DTO from server config.
pkg/services/anonymous/anonimpl/anonstore/database.go Added device limit enforcement: new field, error, constructor arg, and update logic for device creation/updating.
pkg/services/anonymous/anonimpl/anonstore/database_test.go Updated tests for new constructor signature; added test for device limit enforcement.
pkg/services/anonymous/anonimpl/api/api.go Renamed device expiration constant for clarity.
pkg/services/anonymous/anonimpl/client.go Changed device tagging to synchronous; improved error handling for device limit.
pkg/services/anonymous/anonimpl/impl.go Updated service construction to wire device limit; error propagation improved in device tagging.
pkg/services/anonymous/anonimpl/impl_test.go Updated service construction and device listing in tests to match new wiring.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Frontend
    participant Backend
    participant AnonService
    participant DB

    User->>Frontend: Access anonymously
    Frontend->>Backend: Request (with anonymousDeviceLimit in config)
    Backend->>AnonService: Authenticate/TagDevice
    AnonService->>DB: CreateOrUpdateDevice
    alt Device limit not reached
        DB-->>AnonService: Device created/updated
        AnonService-->>Backend: Success
    else Device limit reached
        DB-->>AnonService: ErrDeviceLimitReached
        AnonService-->>Backend: Error
    end
    Backend-->>Frontend: Response (with anonymousDeviceLimit)
    Frontend-->>User: Rendered UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Poem

In the warren of code, a new rule takes flight,
Anonymous bunnies now face a set limit tonight.
Devices are counted, their numbers held tight,
Tests hop along, ensuring all is right.
With config and checks, the garden’s secure—
A carrot for order, and access demure! 🥕🐇

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.2.2)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/product/migration-guide for migration instructions

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

yarn install v1.22.22
[1/4] Resolving packages...
(node:11622) [DEP0169] DeprecationWarning: url.parse() behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for url.parse() vulnerabilities.
(Use node --trace-deprecation ... to show where the warning was created)
warning @grafana/eslint-config > eslint@8.42.0: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning @grafana/eslint-config > eslint > @humanwhocodes/config-array@0.11.14: Use @eslint/config-array instead
warning @grafana/eslint-config > eslint > @humanwhocodes/config-array > @humanwhocodes/object-schema@2.0.3: Use @eslint/object-schema instead
warning @grafana/eslint-config > eslint > file-entry-cache > flat-cache > rimraf@3.0.2: Rimraf versions prior to v4 are no longer supported
warning @grafana/eslint-config > eslint > file-entry-cache > flat-cache > rimraf > glob@7.2.3: Glob versions prior to v9 are no longer supported
warning @grafana/eslint-config > eslint > file-entry-cache > flat-cache > rimraf > glob > inflight@1.0.6: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
warning eslint@8.52.0: This version is no longer supported. Please see https://eslint.org/version-support for other options.
warning eslint > @humanwhocodes/config-array@0.11.14: Use @eslint/config-array instead
error Couldn't find any versions for "@grafana/data" that matches "workspace:*"
info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command.

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch implement-device-limits

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

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

🧹 Nitpick comments (4)
pkg/services/anonymous/anonimpl/anonstore/database.go (4)

18-18: Make error message more descriptive

The error message could be more informative by including context about the anonymous device limit.

-var ErrDeviceLimitReached = fmt.Errorf("device limit reached")
+var ErrDeviceLimitReached = fmt.Errorf("anonymous device limit reached")

52-54: Consider validating deviceLimit parameter

The constructor should validate that deviceLimit is not negative to prevent unexpected behavior.

 func ProvideAnonDBStore(sqlStore db.DB, deviceLimit int64) *AnonDBStore {
+	if deviceLimit < 0 {
+		deviceLimit = 0 // Disable limit for negative values
+	}
 	return &AnonDBStore{sqlStore: sqlStore, log: log.New("anonstore"), deviceLimit: deviceLimit}
 }

108-119: Document device limit behavior and consider metrics

When the device limit is reached, new anonymous devices cannot be created, which may impact legitimate users. Consider:

  1. Adding metrics to monitor when the limit is reached
  2. Documenting this behavior clearly for operators
 	// if device limit is reached, only update devices
 	if s.deviceLimit > 0 {
 		count, err := s.CountDevices(ctx, time.Now().UTC().Add(-anonymousDeviceExpiration), time.Now().UTC().Add(time.Minute))
 		if err != nil {
 			return err
 		}
 
 		if count >= s.deviceLimit {
+			s.log.Warn("Anonymous device limit reached", "limit", s.deviceLimit, "count", count)
 			return s.updateDevice(ctx, device)
 		}
 	}

109-113: Consider caching the device count for performance

The CountDevices query is executed on every device creation/update attempt when a limit is configured. For high-traffic instances, this could impact performance.

Consider implementing a caching mechanism or using an approximate count to reduce database load, especially if this endpoint receives high traffic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed86583 and 3647ba7.

📒 Files selected for processing (11)
  • packages/grafana-data/src/types/config.ts (1 hunks)
  • packages/grafana-runtime/src/config.ts (1 hunks)
  • pkg/api/dtos/frontend_settings.go (1 hunks)
  • pkg/api/frontendsettings.go (1 hunks)
  • pkg/services/anonymous/anonimpl/anonstore/database.go (3 hunks)
  • pkg/services/anonymous/anonimpl/anonstore/database_test.go (2 hunks)
  • pkg/services/anonymous/anonimpl/api/api.go (2 hunks)
  • pkg/services/anonymous/anonimpl/client.go (2 hunks)
  • pkg/services/anonymous/anonimpl/impl.go (4 hunks)
  • pkg/services/anonymous/anonimpl/impl_test.go (2 hunks)
  • pkg/setting/setting.go (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
pkg/services/anonymous/anonimpl/impl_test.go (4)
pkg/services/anonymous/anontest/fake.go (1)
  • FakeService (11-14)
pkg/services/stats/statstest/stats.go (1)
  • FakeService (9-17)
pkg/setting/setting.go (1)
  • NewCfg (985-997)
pkg/services/org/orgtest/fake.go (1)
  • NewOrgServiceFake (25-27)
pkg/services/anonymous/anonimpl/client.go (2)
pkg/services/anonymous/service.go (1)
  • AnonDeviceUI (12-12)
pkg/services/anonymous/anonimpl/anonstore/database.go (1)
  • ErrDeviceLimitReached (18-18)
pkg/api/frontendsettings.go (1)
pkg/setting/setting.go (1)
  • Cfg (149-578)
pkg/setting/setting.go (1)
pkg/login/social/connectors/common.go (1)
  • MustBool (178-198)
🔇 Additional comments (20)
packages/grafana-runtime/src/config.ts (1)

97-97: LGTM! Property addition is correctly implemented.

The anonymousDeviceLimit property is properly added to the GrafanaBootConfig class with appropriate initialization and placement next to related anonymous configuration properties.

pkg/services/anonymous/anonimpl/api/api.go (2)

18-18: Improved constant naming for better code clarity.

The rename from thirtyDays to anonymousDeviceExpiration makes the constant's purpose more explicit and self-documenting.


71-71: Consistent usage of the renamed constant.

The updated reference to anonymousDeviceExpiration maintains functionality while using the improved naming.

packages/grafana-data/src/types/config.ts (1)

200-200: Well-typed interface property addition.

The anonymousDeviceLimit property is correctly typed as number | undefined to allow for optional configuration, and appropriately placed next to related anonymous settings.

pkg/api/dtos/frontend_settings.go (1)

195-195: Correctly implemented DTO field addition.

The AnonymousDeviceLimit field is properly added with appropriate int64 type and correct JSON tag following camelCase convention for frontend compatibility.

pkg/api/frontendsettings.go (1)

198-198: Configuration properly propagated to frontend settings.

The AnonymousDeviceLimit field assignment correctly transfers the backend configuration value to the frontend DTO, completing the configuration pipeline.

pkg/services/anonymous/anonimpl/impl_test.go (3)

116-117: LGTM: Test correctly updated for new service construction pattern.

The test properly adapts to the refactored ProvideAnonymousDeviceService function that now accepts a generic SQL store instead of a pre-constructed anonymous store.


124-124: LGTM: Test assertion correctly updated to access store through service.

The change from anonDBStore.ListDevices to anonService.anonStore.ListDevices properly reflects the new service structure where the anonymous store is created internally.


151-152: LGTM: Consistent test pattern maintained.

The second test function follows the same updated pattern as the first test, maintaining consistency in the test suite.

pkg/services/anonymous/anonimpl/anonstore/database_test.go (3)

16-16: LGTM: Test updated for new constructor signature.

The addition of the device limit parameter (set to 0, likely meaning unlimited) maintains the existing test behavior while adapting to the new ProvideAnonDBStore signature.


51-70: LGTM: Excellent test coverage for device limit enforcement.

This new test thoroughly validates the device limit functionality by:

  1. Setting a limit of 1 device
  2. Successfully creating the first device
  3. Verifying that creating a second device fails with ErrDeviceLimitReached

This provides essential coverage for the core feature being implemented.


74-74: LGTM: Consistent test pattern maintained.

All existing tests are consistently updated to include the device limit parameter, maintaining uniformity across the test suite.

pkg/setting/setting.go (2)

375-375: LGTM: Appropriate field type and placement.

The AnonymousDeviceLimit field is correctly typed as int64 for handling device counts and is logically placed with other anonymous configuration fields.


1650-1655: LGTM: Clean refactoring with new configuration option.

The refactoring to use a local anonSection variable improves code readability and maintainability. The new AnonymousDeviceLimit configuration is properly read with a sensible default of 0 (likely unlimited).

pkg/services/anonymous/anonimpl/client.go (2)

5-5: LGTM: Necessary imports for enhanced error handling.

The errors and anonstore imports are required for the new error comparison logic that specifically handles device limit exceeded scenarios.

Also applies to: 11-11


44-50: LGTM: Proper synchronous error handling for device limits.

The refactoring from asynchronous to synchronous TagDevice calling is appropriate for authentication flow. The specific handling of ErrDeviceLimitReached correctly aborts authentication when the device limit is exceeded, while other errors are logged but don't prevent anonymous access - a sensible approach for non-critical device tagging functionality.

pkg/services/anonymous/anonimpl/impl.go (4)

9-9: LGTM: Required import for new dependency injection pattern.

The db import is necessary for the updated service construction that accepts a generic SQL store interface.


36-43: LGTM: Improved service construction with device limit integration.

The refactoring to accept a generic db.DB parameter and internally create the anonymous store with cfg.AnonymousDeviceLimit is a clean design. This ensures the device limit configuration is properly propagated to the storage layer while simplifying dependency injection.


61-61: LGTM: Consistent usage of internally created store.

The API initialization correctly uses the anonymous store from the service struct, maintaining consistency with the new construction pattern.


147-147: LGTM: Proper error propagation for device limit handling.

Returning the error instead of just logging it allows callers to handle device limit scenarios appropriately, which is essential for the authentication flow to fail when limits are exceeded.

@github-actions
Copy link
Contributor

This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 2 weeks if no further activity occurs. Please feel free to give a status update or ping for review. Thank you for your contributions!

@github-actions github-actions bot added the stale label Aug 26, 2025
@github-actions
Copy link
Contributor

This pull request has been automatically closed because it has not had any further activity in the last 2 weeks. Thank you for your contributions!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants