Draft: Pin Jira API requests to the configured host and context path

What does this MR do and why?

Gitlab::Jira::HttpClient forwarded whatever absolute URL jira-ruby derived from the self field of Jira API responses. Jira builds that field from its own base URL, so when the Jira API URL setting points at a different host than the Web URL, sub-resource calls such as remote link creation were addressed to the wrong host.

HTTParty 0.24 added strict base_uri host validation (CVE-2025-68696), so those requests now raise HTTParty::UnsafeURIError instead of being sent. Integrations::Jira#jira_request rescues StandardError, so the cross-reference fails silently — no comment and no remote link are created.

The defect predates the httparty patch. Before it, the mismatched absolute URL was followed, which sent the configured Jira credentials to a host the admin never configured for API traffic.

Why it surfaced when it did

Two changes combine, which is worth knowing when dating the regression:

  1. httparty 0.23.1 → 0.24.2 reached production on 2026-01-23. issue.remotelink.all started raising, but find_remote_link wrapped it in its own inner jira_request, so the error was swallowed locally and the lookup just returned nil. The flow continued and both the comment and the remote link still posted over relative paths — only the duplicate-link guard went inert.

  2. The fix for the duplicate-comment bug unwrapped that call on purpose, so a failed lookup fails closed rather than reading as "no link exists" and duplicating:

     def find_remote_link(issue, url)
    -  path = API_ENDPOINTS[:link_remote_issue] % issue.id
    -  links = jira_request(path) { issue.remotelink.all }
    +  links = issue.remotelink.all
       return unless links

    HTTParty::UnsafeURIError descends from StandardError, so that inner jira_request had been rescuing it. The error now reaches the outer jira_request in send_message and aborts the whole operation. This reached production on 2026-07-28.

Step 2 is correct behaviour and is not what needs changing — it converted a latent bug into a visible one. This MR removes the cause so the lookup succeeds.

normalize_path now discards everything before the /rest/ prefix and re-anchors the path on the configured context_path. Every request, and the credentials on it, therefore stays on the host and context path the admin configured. The httparty host check stays fully enabled; it is simply no longer handed a mismatched URL.

Jira reports its own context path in self as well, which is not necessarily the context path of the configured API URL. Re-anchoring on the configured value also keeps all calls for one resource consistent — previously the remote link GET and POST could resolve to two different paths for the same resource.

Verification

Both new specs fail on master with the reported HTTParty::UnsafeURIError and pass here:

  • spec/lib/gitlab/jira/http_client_spec.rb covers path normalisation directly: differing host, differing context path, matching context path, a context path that itself contains /rest (both guarding against a repeated prefix), query string preservation, and paths with no REST prefix.
  • spec/models/integrations/jira_spec.rb adds an end-to-end regression case driving #create_cross_reference_note with Jira reporting the Web URL host in self.

Also run green: the full Jira model and client specs with FOSS_ONLY=1, plus the Jira request, import, and vulnerability external link specs.

References

Edited by Jorge Tomás

Merge request reports

Loading
Loading