Move o11y service settings tool to admin area
What does this MR do?
Moves the o11y service settings management tool from the flag-gated /-/experimental/o11y_service_settings namespace into the Admin area (/admin/o11y_service_settings), where it is enforced admin-only by Admin::ApplicationController. This tool is only ever used by admins, so gating it behind /admin is the right home for it.
Changes
- New admin controller
Admin::O11yServiceSettingsController(inheritsAdmin::ApplicationController) with the same index/new/create/edit/update/destroy actions. - New admin views/helper/JS under
admin/o11y_service_settings(reusing the sharedgroups/observability/o11y_service_settings/_form_fieldspartial, which is left in place). - New top-level "Observability" admin sidebar menu (
lib/sidebars/admin/menus/observability_menu.rb). Monitoring is for GitLab’s own health, so this gets its own top-level item. - Removed the
experimentalroute namespace, theExperimental::O11yServiceSettingsController+ views/helper/JS, and theexperimental_group_o11y_settings_accessfeature flag — admin access is now the gate, so the flag is no longer needed. - Specs moved/adapted to the admin equivalents (request, helper, frontend, sidebar menu).
SSRF hardening (included)
While moving the write path, this also hardens Observability::GroupO11ySettingsUpdateService:
- Validate
o11y_service_nameagainst a strict allowlist (\A[a-z0-9]+(?:-[a-z0-9]+)*\z) before interpolating it into the service URL, returning a graceful error otherwise. - Reject any
o11y_service_url/o11y_otel_url/o11y_mcp_urlvalue containing a URI fragment (#) or userinfo (@) component, which could otherwise make the parsed host differ from the visible host.
Access
The page is admin-only via Admin::ApplicationController (admin + admin mode), matching other admin tools such as Deploy keys and Spam logs. No feature flag.
HTTP Router sync (pipeline:skip-router-sync)
This MR moves the o11y service settings routes from /-/experimental to /admin, so the cells-routes:router-in-sync job reports drift against the HTTP Router snapshot. Applying pipeline:skip-router-sync because the HTTP Router snapshot on main can only match one GitLab ref at a time and there are paired route-changing MRs in flight; the router will be resynced from master after these merge. This is an admin-only, low-traffic tool.