Skip to content

Conversation

@everettbu
Copy link

@everettbu everettbu commented Jul 28, 2025

Test 1

* 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 <[email protected]>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR implements a configurable device limit feature for anonymous access in Grafana. The changes add a new configuration option anonymousDeviceLimit that allows administrators to control the maximum number of anonymous devices that can be tracked simultaneously.

The implementation spans both frontend and backend components:

Frontend Changes:

  • Adds anonymousDeviceLimit property to the GrafanaConfig interface in TypeScript definitions
  • Exposes the configuration through the boot config system to make it available to client-side code

Backend Changes:

  • Adds AnonymousDeviceLimit field to the main configuration struct, loaded from the auth.anonymous.device_limit INI setting with a default of 0 (no limit)
  • Exposes the limit to the frontend via the FrontendSettingsDTO API response
  • Modifies the anonymous device store to enforce limits by checking device count before allowing new device creation
  • When the limit is reached, the system falls back to update-only mode for existing devices and returns ErrDeviceLimitReached for new device attempts
  • Refactors the authentication client to handle device limit errors synchronously, causing authentication to fail immediately when limits are exceeded
  • Updates the dependency injection pattern to pass the device limit configuration properly to the database store

The feature integrates with Grafana's existing anonymous device tracking system, which maintains device records with 30-day expiration. The limit is enforced at the database level and prevents resource exhaustion from unlimited anonymous device registrations while allowing existing users to continue accessing the system.

Confidence score: 2/5

  • This PR has significant implementation issues that could cause production problems, particularly race conditions in device counting logic
  • The score is low due to potential race conditions in the device limit enforcement and inconsistent time window calculations in the database layer
  • Files that need more attention: pkg/services/anonymous/anonimpl/anonstore/database.go (race condition in device counting), pkg/services/anonymous/anonimpl/client.go (synchronous authentication changes), and the overall architectural changes in pkg/services/anonymous/anonimpl/impl.go

11 files reviewed, 6 comments

Edit Code Review Bot Settings | Greptile

}

devices, err := anonDBStore.ListDevices(context.Background(), nil, nil)
devices, err := anonService.anonStore.ListDevices(context.Background(), nil, nil)
Copy link

Choose a reason for hiding this comment

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

style: accessing internal field anonStore - consider exposing a public method on the service instead of accessing private fields in tests

theme2: GrafanaTheme2;
featureToggles: FeatureToggles = {};
anonymousEnabled = false;
anonymousDeviceLimit = undefined;
Copy link

Choose a reason for hiding this comment

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

style: Consider using a more specific type like number | undefined instead of just undefined to match the backend type definition

Comment on lines +108 to +118
// 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 {
return s.updateDevice(ctx, device)
}
}
Copy link

Choose a reason for hiding this comment

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

logic: Race condition: Multiple concurrent requests could pass the device count check simultaneously and create devices beyond the limit. Consider using a database transaction or lock.

Comment on lines +80 to +82
args := []interface{}{device.ClientIP, device.UserAgent, device.UpdatedAt.UTC(), device.DeviceID,
device.UpdatedAt.UTC().Add(-anonymousDeviceExpiration), device.UpdatedAt.UTC().Add(time.Minute),
}
Copy link

Choose a reason for hiding this comment

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

logic: Time window calculation inconsistency: Using device.UpdatedAt.UTC().Add(-anonymousDeviceExpiration) as the lower bound but device.UpdatedAt as the current time may not match the intended logic. Consider using time.Now().UTC() consistently.

Comment on lines +95 to +97
if rowsAffected == 0 {
return ErrDeviceLimitReached
}
Copy link

Choose a reason for hiding this comment

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

logic: Misleading error: Returning ErrDeviceLimitReached when no rows are affected in updateDevice is confusing since the device might not exist rather than limit being reached.


// 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))
Copy link

Choose a reason for hiding this comment

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

logic: Inconsistent time windows: The count query uses time.Now().UTC().Add(time.Minute) as upper bound, but updateDevice uses device.UpdatedAt.UTC().Add(time.Minute). This could cause timing issues.

greptile-apps[bot]

This comment was marked as duplicate.

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

@github-actions github-actions bot closed this Sep 12, 2025
@everettbu everettbu reopened this Sep 12, 2025
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

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