Add guardrail spec for EE API route tiers
What does this MR do and why?
Adds a spec that fails when an EE API route in the OpenAPI spec has no route_setting :tier, so new paid endpoints can't ship without x-gitlab-tier. This is the last MR for the tier backfill in #631956 (closed). The other seven are merged.
-
ee/spec/lib/api/every_ee_api_endpoint_tier_spec.rb: picks routes the same way the OpenAPI v3 generator does, then keeps the ones defined underee/. The spec has two examples:- Every route declares a tier, or is on the allowlist.
- No allowlist entry is stale, meaning the route now has a tier or no longer exists.
-
ee/spec/support/api/routes_without_tier.yml: an allowlist of the 125 EE routes without a tier, grouped by reason:Reason Routes Free on every tier (license, billing, seats, setup) 38 Free on every tier (Orbit skills and status, which skip the entitlement check) 4 Pending: gated by a GitLab Duo add-on rather than a tier 43 Pending: instance admin endpoints that check only admin access 10 Pending: likely Premium, with no license check of their own 12 Pending: docs and code disagree, or the owning team needs to confirm 5 Pending: deprecated managed_licensesendpoint5 Geo node-to-node traffic, candidates for excluded_api_classes8 Closing a pending group means annotating its routes and deleting their entries. The stale-entry example makes sure the list shrinks when that happens.
-
rubocop/cop/api/route_setting_tier.rb: docstring only. The cop validates tier values, but it can't detect a missing tier, so it now points to the new spec. -
tests.ymlandscripts/verify-tff-mapping: map EE API files and the allowlist to the new spec, so predictive MR pipelines run it when a route changes. Without the mapping, an untiered route would first fail on master.
Scope and design notes
- Only routes whose source is under
ee/. EE routes produced by shared CE loops (for example epic notes and group hooks) have their source inlib/. The route tier specs added in the shared-loops MR cover them. - No check that one definition site produces a single tier. The original plan included one, but it would fail on the shared CE loops, which produce Free and paid routes from one site on purpose.
- Route selection matches
lib/tasks/gitlab/openapi/v3_document.rb:API::Base.descendants, minusexcluded_api_classes, minus hidden routes and the*catch-all. The spec checks exactly the routes the published spec contains. - A spec rather than a RuboCop cop with a todo file. RuboCop todos exclude whole files, and many files mix Free and paid routes, so new paid routes in those files would go unchecked. A cop also cannot see
excluded_api_classesor tiers set through shared CE loops. The allowlist works per route, and records permanently Free routes with a reason. It followsspec/lib/api/every_api_endpoint_spec.rbandspec/models/every_model_spec.rb. - The spec takes about 10 seconds locally.
References
Screenshots or screen recordings
Not applicable: no UI change.
How to set up and validate locally
No manual steps. The change is a spec, and CI runs it. To see the failure message, remove a route_setting :tier from any EE route, for example in ee/lib/api/epics.rb.
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.