From 1caded98e9236d8c4b4bced1b9dd6b7c42a3f7e1 Mon Sep 17 00:00:00 2001 From: thanhnv Date: Mon, 7 Sep 2026 00:53:26 +0900 Subject: [PATCH] fix(jira): support Jira Server/Data Center Bearer auth alongside Cloud Basic auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jira Server self-hosted instances (e.g. insight.fsoft.com.vn) reject Basic Auth with email+API token (403). Auto-detect by hostname: - *.atlassian.net → Basic Auth (email + API token) - everything else → Bearer header with Personal Access Token User pastes PAT into the same 'API token' field in UI Connectors. --- core/jira_tool.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/core/jira_tool.py b/core/jira_tool.py index ef5db00..285ecfb 100644 --- a/core/jira_tool.py +++ b/core/jira_tool.py @@ -83,18 +83,40 @@ def get_issue_by_url(config: Dict[str, Any] | None, url: str) -> str: return get_issue(config, key) +def _is_cloud(base_url: str) -> bool: + """True when the base URL points at Atlassian Cloud (*.atlassian.net).""" + try: + host = (urlparse(base_url).hostname or "").lower() + except ValueError: + return False + return host.endswith(".atlassian.net") + + def _get(config: Dict[str, Any], path: str, params: dict = None): - """Gọi Jira REST API bằng xác thực cơ bản, qua lớp TLS có ghim chứng chỉ nội bộ.""" + """Gọi Jira REST API, tự chọn mode xác thực theo loại server. + + Jira Cloud (*.atlassian.net) → Basic Auth (email + API token). + Jira Server / Data Center → Bearer token (Personal Access Token). + Cả hai đều đi qua lớp TLS có ghim chứng chỉ nội bộ (tls_trust). + """ from . import tls_trust c = _conf(config) url = c["base_url"].rstrip("/") + path - # Same TLS auto-recovery the LLM provider calls get (core/tls_trust.py) — - # a corporate gateway that terminates TLS with its own certificate used to - # break this outright with SSLCertVerificationError. - resp = tls_trust.request("get", url, params=params or {}, timeout=_TIMEOUT, - auth=(c["email"], c["api_token"]), - headers={"Accept": "application/json"}) + headers = {"Accept": "application/json"} + + if _is_cloud(c["base_url"]): + # Cloud: Basic Auth với email + API token từ id.atlassian.com + resp = tls_trust.request("get", url, params=params or {}, timeout=_TIMEOUT, + auth=(c["email"], c["api_token"]), + headers=headers) + else: + # Server / Data Center: Personal Access Token qua Bearer header. + # Người dùng dán PAT vào trường "API token" trong UI Connectors. + headers["Authorization"] = f"Bearer {c['api_token']}" + resp = tls_trust.request("get", url, params=params or {}, timeout=_TIMEOUT, + headers=headers) + resp.raise_for_status() return resp.json()