Repository navigation
feat(entitlements): trim to MaxSSOUsers + MaxChecksPerMinute, enforce both - #49
Merged
Merged
Conversation
… both
Pre-1.0 cleanup. The v1 entitlements model had eleven limits and six
feature flags but no enforcement: CanCreate / FeatureEnabled were
stubs that always allowed. Replace that surface with the two limits
that actually matter today and wire enforcement for both:
- MaxSSOUsers (default 30 on self-hosted, nil on SaaS) — checked at
every OAuth ensureMembership and autoJoinMatchingOrgs across the
six provider services. The 31st new SSO membership is refused with
ENTITLEMENT_EXCEEDED; the very first member of a fresh org always
passes (count=0 < cap).
- MaxChecksPerMinute (default 6 on SaaS, nil on self-hosted) — gated
at the worker dispatch via an in-memory token bucket per org.
Drained buckets reschedule the job for next period without writing
a result and bump solidping_checks_rate_limited_total{organization}.
A new SP_DEPLOYMENT_MODE env (saas | self-hosted, default
self-hosted) drives the default selection at startup; admins can
still override either cap per-org via the existing PUT/PATCH
/api/v1/orgs/$org/entitlements path. The entitlements payload schema
shrinks accordingly: MaxChecks, MaxMembers, MaxStatusPages,
MaxCheckGroups, MaxMaintenanceWindows, MaxConnections, MaxWorkers,
MaxAPITokens, RetentionDaysRaw, RetentionDaysAggregated,
MinCheckPeriodSeconds, AllowedCheckTypes, and the six Feature flags
are dropped. encoding/json silently ignores unknown keys, so audit
rows written under v1 still parse; PATCH bodies reject deleted keys
loudly via DisallowUnknownFields so clients get a clear
VALIDATION_ERROR.
The token bucket lives in process memory — multi-replica deployments
will need a shared store (TODO comment marks the spot).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fclairamb
enabled auto-merge (squash)
May 10, 2026 15:51
Merged
fclairamb
added a commit
that referenced
this pull request
Jun 23, 2026
🤖 I have created a release *beep* *boop* --- ## [0.1.0](v0.0.0...v0.1.0) (2026-06-22) ### Features * add check type registry, sample configs, notification senders, and observability integrations ([eea049e](eea049e)) * batch — Warning/Degraded statuses, SSL/Docker check upgrades, MCP OAuth 2.1, config-as-code ([#85](#85)) ([936d830](936d830)) * batch spec implementations (dashboard UI, jobs, notifications, SaaS, perf) ([#78](#78)) ([fe003e4](fe003e4)) * bulk feature integration (discovery, web push, badges, webhooks, and more) ([#73](#73)) ([a976856](a976856)) * custom user-agent, refresh checks, vite plugin switch, CI updates ([#1](#1)) ([cc00858](cc00858)) * documentation site served at /docs (co-located in web/docs) ([#88](#88)) ([27d9ccd](27d9ccd)) * email check frontend (spec 03) ([#30](#30)) ([aebd106](aebd106)) * email inbox foundation via JMAP (spec 01) ([#24](#24)) ([0f3b0c1](0f3b0c1)) * email passive checks (spec 02) ([#27](#27)) ([ba5536f](ba5536f)) * **entitlements:** trim to MaxSSOUsers + MaxChecksPerMinute + status page history fixes ([#50](#50)) ([a007de0](a007de0)) * **entitlements:** trim to MaxSSOUsers + MaxChecksPerMinute, enforce both ([#49](#49)) ([d25cc5f](d25cc5f)) * group incident correlation (spec 04 backend v1) ([#31](#31)) ([1883986](1883986)) * **observability:** instrument hot path + add bench harness ([#60](#60)) ([c6604cc](c6604cc)) * **oncall:** searchable timezone dropdown + sidebar logo polish ([#46](#46)) ([4396898](4396898)) * per-IP HTTP rate limiting and concurrency limiting ([#59](#59)) ([f9cc273](f9cc273)) * soften HTTP rate limits with bounded queues + request timeout ([#63](#63)) ([025501b](025501b)) * SolidPing — distributed uptime monitoring platform ([eef4383](eef4383)) * **statuspages:** drag-and-drop resource reordering + dash conventions ([#41](#41)) ([cf910d4](cf910d4)) ### Bug Fixes * **deps:** update dependency i18next to v26 ([#26](#26)) ([d5d1b7e](d5d1b7e)) * **deps:** update dependency lucide-react to v1 ([#28](#28)) ([cdc8e8c](cdc8e8c)) * **deps:** update dependency react-i18next to v17 ([#29](#29)) ([13135d8](13135d8)) * **deps:** update dependency recharts to v3.8.1 ([#14](#14)) ([5d95a3b](5d95a3b)) * **deps:** update go dependencies (non-major) ([#16](#16)) ([2450f13](2450f13)) * **deps:** update go dependencies (non-major) ([#19](#19)) ([f842310](f842310)) * **deps:** update go dependencies (non-major) ([#37](#37)) ([c020eca](c020eca)) * **deps:** update go dependencies (non-major) ([#44](#44)) ([ff0bcd0](ff0bcd0)) * **deps:** update go dependencies (non-major) ([#52](#52)) ([2e3bc28](2e3bc28)) * **deps:** update go dependencies (non-major) ([#69](#69)) ([a65ed4c](a65ed4c)) * **deps:** update go dependencies (non-major) ([#77](#77)) ([a0920ff](a0920ff)) * **deps:** update go dependencies (non-major) to v1.4.2 ([#86](#86)) ([1eb7504](1eb7504)) * **deps:** update module github.com/aws/aws-sdk-go-v2/config to v1.32.18 ([#72](#72)) ([6406537](6406537)) * **deps:** update module github.com/aws/aws-sdk-go-v2/service/s3 to v1.101.0 ([#39](#39)) ([f9c9563](f9c9563)) * **deps:** update module github.com/go-webauthn/webauthn to v0.17.3 ([#45](#45)) ([593931a](593931a)) * **deps:** update module github.com/go-webauthn/webauthn to v0.17.4 ([#70](#70)) ([fca1c97](fca1c97)) * **deps:** update module github.com/ibm/sarama to v1.48.1 ([#47](#47)) ([93ccf3a](93ccf3a)) * **deps:** update module github.com/ibm/sarama to v1.48.2 ([#54](#54)) ([e84d868](e84d868)) * **deps:** update module github.com/ibm/sarama to v1.49.0 ([#64](#64)) ([fd61bd7](fd61bd7)) * **deps:** update module github.com/oapi-codegen/runtime to v1.4.1 ([#65](#65)) ([a3a3e9f](a3a3e9f)) * **deps:** update module github.com/prometheus/common to v0.67.5 ([#61](#61)) ([095dd6f](095dd6f)) * **deps:** update module github.com/slack-go/slack to v0.24.0 ([#75](#75)) ([6e86d5b](6e86d5b)) * **deps:** update module golang.org/x/sys to v0.44.0 ([#42](#42)) ([a245730](a245730)) * **deps:** update module golang.org/x/sys to v0.45.0 ([#67](#67)) ([49c3d90](49c3d90)) * **deps:** update module golang.org/x/term to v0.43.0 ([#43](#43)) ([4a934f1](4a934f1)) * **deps:** update module google.golang.org/grpc to v1.81.0 ([#36](#36)) ([1be183a](1be183a)) * **deps:** update module google.golang.org/grpc to v1.81.1 ([#55](#55)) ([6bfac2d](6bfac2d)) * status lifecycle improvements and created/running result handling ([#5](#5)) ([fc64c7d](fc64c7d)) * **status0:** white page header and de-duplicated footer ([#48](#48)) ([77506a7](77506a7)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This was referenced Sep 8, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The v1 entitlements model had eleven limits and six feature flags but no enforcement —
CanCreateandFeatureEnabledwere stubs that always allowed. This PR replaces that surface with the two limits that actually matter today, and wires enforcement for both.MaxSSOUsers(default30on self-hosted,nilon SaaS) — checked at every OAuthensureMembershipand insideautoJoinMatchingOrgsacross all six provider services (google/github/gitlab/microsoft/discord/slack). The 31st new SSO membership for an org is refused withENTITLEMENT_EXCEEDED. The very first member of a fresh org always passes (count0 < cap).MaxChecksPerMinute(default6on SaaS,nilon self-hosted) — gated at the worker dispatch via an in-memory token bucket per org. Drained buckets reschedule the job for next period without writing a result, and bumpsolidping_checks_rate_limited_total{organization}.A new
SP_DEPLOYMENT_MODEenv (saas|self-hosted, defaultself-hosted) drives default selection at startup. Admins can still override either cap per-org via the existingPUT/PATCH /api/v1/orgs/$org/entitlements.Cleanup
The entitlements payload schema shrinks. Dropped from the model:
MaxChecks,MaxMembers,MaxStatusPages,MaxCheckGroups,MaxMaintenanceWindows,MaxConnections,MaxWorkers,MaxAPITokens,RetentionDaysRaw,RetentionDaysAggregated,MinCheckPeriodSeconds,AllowedCheckTypes, and the six features (SSO,MCP,CustomBranding,PrioritySupport,MultiRegion,AdvancedAlerts).encoding/jsonsilently drops unknown keys, so historical audit-log rows written under v1 still parse cleanly into the smaller struct. PATCH bodies, however, reject deleted keys loudly viaDisallowUnknownFields— clients sending legacymaxChecksetc. get a clearVALIDATION_ERROR.The four
Count*ForOrgDB methods that fed the deleted "usage" panel are removed; a singleCountSSOMembersForOrgjoinsorganization_memberswithuser_providersfor the SSO cap.Caveats
TODOmarks the spot inentitlements/service.go.payloadJSONB column is unchanged; old keys silently dropped on read.Test plan
make lint-backcleango test ./...— 1886 tests pass across 122 packagesGET /api/v1/orgs/default/entitlementsreturns{maxSsoUsers: 30}+source: "default", nomaxChecksPerMinuteSP_DEPLOYMENT_MODE=saas: same call returns{maxChecksPerMinute: 6}, nomaxSsoUsers{"maxChecks": 100}) returnsVALIDATION_ERRORsolidping_checks_rate_limited_total🤖 Generated with Claude Code