Add upsertUserBudgetCapOverrides GraphQL mutation
What does this MR do and why?
Adds the upsertUserBudgetCapOverrides GraphQL mutation for bulk upserting
per-user budget cap overrides. Accepts GlobalIDType[User] IDs, validates
users exist, translates to CDot entityId strings, and proxies to CDot.
Includes a max 200 overrides limit, UserOverrideInputType, and 13 request
specs covering SaaS, self-managed, unauthorized, feature flag, and edge cases.
Gated behind the budget_caps_graphql_api feature flag.
Related to https://gitlab.com/gitlab-org/gitlab/-/issues/595491
Important: CDot prerequisite
A subscription-level flat user cap must exist in CDot before user overrides can be upserted. If no flat cap record exists, CDot returns:
{ "errors": ["Subscription budget cap not found"] }This means in practice, the upsertFlatUserCap mutation (MR3) must be called
first to create the subscription budget cap record, then upsertUserBudgetCapOverrides
can be used to set per-user overrides.
Stacked MR
| # | MR | Description | Status |
|---|---|---|---|
| 1 | !230214 (merged) | Foundation — feature flag + client + shared concern | Merged |
| 2 | !230218 (merged) | Query — budget caps read API (BudgetCapsType, UserOverrideType, PORO) |
Merged |
| 3 | !230224 (merged) | Mutation — upsert flat user cap | In review |
| 4 | This MR | Mutation — upsert user budget cap overrides | You are here |
| 5 | !230226 (closed) | Enable feature flag by default (draft, blocked by 3-4) | Draft |
How to set up and validate locally
Prerequisites: GDK running with CDot on localhost:5000. Use existing group saastestgroup.
-
Enable the feature flag
Feature.enable(:budget_caps_graphql_api) -
Ensure a flat cap exists in CDot
A subscription budget cap record must exist before user overrides can be added. Either use the
upsertFlatUserCapmutation (MR3) or seed directly in CDot console:BudgetCap::Subscription.create!( subscription_name: "A-S00409070", deployment_type: :saas, subscription_cap: 5000, subscription_cap_enabled: true, flat_user_cap: 200.0, flat_user_cap_enabled: true )Without this, the mutation returns:
"Subscription budget cap not found" -
SaaS — Owner upserts user overrides
Log in as owner of
saastestgroup. Open GraphiQL at http://localhost:3000/-/graphql-explorer:mutation { upsertUserBudgetCapOverrides(input: { namespacePath: "saastestgroup" overrides: [ { userId: "gid://gitlab/User/1", cap: 300.0, enabled: true } { userId: "gid://gitlab/User/3", cap: 150.0, enabled: false } ] }) { userOverrides { user { id username } cap capEnabled } errors } }Expected: updated overrides with resolved User objects.
-
Self-Managed — Instance admin upserts overrides
Log in as admin. Admin mode must be enabled — toggle admin mode from user settings (click avatar → Preferences → enable Admin Mode), or use a Personal Access Token (PAT) with
apiscope which bypasses admin mode automatically viasessionless_bypass_admin_mode!.Omit
namespacePathfor the SM path:mutation { upsertUserBudgetCapOverrides(input: { overrides: [ { userId: "gid://gitlab/User/1", cap: 500.0, enabled: true } ] }) { userOverrides { user { id username } cap capEnabled } errors } }Note: On Self-Managed, the
adminpolicy condition inBasePolicyrequires bothuser.admin?and an active admin mode session (Gitlab::Auth::CurrentUserMode#admin_mode?). Without admin mode enabled, the mutation returns a permission error. API requests authenticated with a PAT bypass this requirement automatically. -
Invalid userId
mutation { upsertUserBudgetCapOverrides(input: { namespacePath: "saastestgroup" overrides: [ { userId: "gid://gitlab/User/999999", cap: 100.0, enabled: true } ] }) { userOverrides { user { id } } errors } }Expected: error "One or more specified users were not found"
-
Unauthorized — non-owner (SaaS)
Log in as non-owner, run mutation from step 3. Expected: permission error.
-
Feature flag disabled
Feature.disable(:budget_caps_graphql_api)Run mutation from step 3 again. Expected: error about feature flag being disabled.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.