Backport of 'Stop dependency proxy requests counting against the web rate limit'

🤔 What does this MR do and why?

Backports !253039 (merged) (merged into master 2026-09-14, deployed to GitLab.com the same day) to 19-3-stable-ee for the next 19.3 patch release.

Fixes #627044 (closed) (severity::2). Authenticated dependency proxy container image pulls counted against the authenticated web rate limit, so image pulls shared one budget with a user's ordinary browsing. CI jobs running several parallel docker pulls exhausted that budget and failed with HTTP 429. A GitLab Dedicated customer running 19.2.4 hit this in production.

The fix adds a dedicated throttle, throttle_authenticated_dependency_proxy, registered in both enforcement stacks: the legacy Rack::Attack predicates and the newer Labkit throttle registry. It adds three keys to the existing rate_limits JSONB column, so there is no schema change. Defaults: disabled, 1000 requests, 15 seconds. A post-deployment migration enables the throttle on any instance where the authenticated web throttle is already enabled, copying that throttle's requests-per-period and period-in-seconds.

This is a split of an existing rate limit, not a new one. It can only loosen limits, never tighten them: before, web browsing and dependency proxy pulls shared one budget; after, each gets its own budget of the same size. While the setting is off, dependency proxy requests keep counting against the web throttle, so nothing escapes rate limiting.

🔀 Backport adaptations

This is not a clean cherry-pick. 19.3 predates a 19.4 refactor, so three things diverge from the master original:

  • 19.4 moved the rate-limit path predicates out of lib/gitlab/rack_attack/request.rb into lib/gitlab/rate_limit/request_classification.rb. Those files don't exist on 19.3, so dependency_proxy_path? was re-homed into lib/gitlab/rack_attack/request.rb, with the EE virtual-registry exclusion in ee/lib/ee/gitlab/rack_attack/request.rb. ClassifiedRequest includes Gitlab::RackAttack::Request and carries prepend_mod_with, so the CE helper plus the EE override still reach both enforcement stacks from one definition, matching the master behaviour.
  • spec/requests/labkit_rack_rate_limit_spec.rb is a master-era merge of two files 19.3 still keeps separate. The new claim-before-web and fall-through-to-web cases went into spec/requests/labkit_rack_rate_limit_shadow_spec.rb instead, modelled on its existing "a git throttle is claimed before the web rule" block. The #dependency_proxy_path? unit coverage moved into spec/lib/gitlab/rack_attack/request_spec.rb.
  • lib/api/settings.rb needs no change on 19.3. Master adds three parameter descriptions to a block from unrelated later work that doesn't exist here; the settings are already accepted via optional(*Helpers::SettingsHelpers.optional_attributes), fed by the included visible_attributes change.

doc/api/openapi/openapi_v3.yaml was regenerated on this branch with bin/rake gitlab:openapi:v3:generate rather than hand-edited, so its RequestBody_ digest matches what the generator produces for 19.3.

The same two doc lines needed adjusting on this branch: the upgrade note in doc/administration/settings/user_and_ip_rate_limits.md and the {{< history >}} entry for the throttle_authenticated_dependency_proxy_* attributes in doc/api/settings.md both carried master's GitLab 19.4 reference verbatim. Commit d42289381700 repoints them to GitLab 19.3.3, the next patch after the already-released 19.3.2. As with the 19.2 backport, this is only accurate while the change lands in 19.3.3, so a slip to a later patch requires bumping both references again.

✅ Local verification

Verified against GDK running this branch: the throttle registers and its options resolve; the predicate fires for manifest and blob paths only; a dependency proxy request is excluded from the web throttle when the setting is on and still counted by it when off; the EE virtual-registry path is excluded; the Labkit rule is ordered ahead of both web rules and the registry still covers every Rack::Attack throttle.

The post-deployment migration was run against the real 19.3 schema in rolled-back transactions: it seeds from the web throttle's values, leaves instances with the web throttle disabled untouched, and doesn't clobber values an administrator already set.

End to end over HTTP with the limit set to 1 request per 60 seconds: with the new throttle enabled, the second pull returned 429 with header Ratelimit-Name: throttle_authenticated_dependency_proxy, proving the dedicated budget is enforced. With the throttle disabled and the web throttle at 1 per 60 seconds, the request returned 429 with Ratelimit-Name: throttle_authenticated_web, proving the fall-through keeps working while the setting is off.

One known follow-up: the backported docs say the throttle is enabled automatically "when you upgrade to GitLab 19.4 or later", which is accurate for master but not for a 19.3 patch. Following existing practice, this will be corrected by a separate documentation backport once the patch version numbers are known.

☑️ MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

  • This MR is backporting a bug fix, documentation update, or spec fix, previously merged in the default branch.
  • The MR that fixed the bug on the default branch has been deployed to GitLab.com (not applicable for documentation or spec changes).
  • The MR title is descriptive (e.g. "Backport of 'title of default branch MR'"). This is important, since the title will be copied to the patch blog post.
  • Required labels have been applied to this merge request
  • This MR has been approved by a maintainer (only one approval is required).
  • Ensure the e2e:test-on-omnibus-ee job has succeeded, or if it has failed, investigate the failures. If you determine the failures are unrelated, you may proceed. If you need assistance investigating, request help in the #s_developer_experience Slack channel to confirm the failures are unrelated to the merge request.

Note to the merge request author and maintainer

If you have questions about the patch release process, please:

Edited by David Fernandez

Merge request reports

Loading
Loading