/claim #2281
This PR implements a Jira Service Management (JSM) connector that indexes tickets, requests, and comments from JSM projects, with full EE permission sync support.
Rather than copying the 1,066-line Jira connector (as attempted in prior PRs), this implementation inherits from JiraConnector and overrides a single method — _load_from_checkpoint — to re-tag yielded Document objects with DocumentSource.JIRA_SERVICE_MANAGEMENT.
The result is a 45-line connector with zero duplicated logic. All JQL search, ADF parsing, checkpoint pagination, hierarchy node generation, permission sync, and validation are inherited from the battle-tested Jira connector.
Why this works:
process_jira_issue() is the only place that sets source=DocumentSource.JIRA — our override intercepts and re-tags it.load_from_checkpoint() and load_from_checkpoint_with_perm_sync() delegate to _load_from_checkpoint, so a single override covers both paths.SlimDocument has no source field, so retrieve_all_slim_docs_perm_sync requires no override.Document is a mutable Pydantic model (not frozen), so item.source = ... is safe.This follows the codebase’s own best practices: “No duplicate logic: Don’t copy/paste into branches when shared logic can live above the conditional.”
Backend — Connector (4 files)
| File | Action | Purpose |
|---|---|---|
backend/onyx/configs/constants.py |
Modified | Added JIRA_SERVICE_MANAGEMENT to DocumentSource enum and DocumentSourceDescription |
backend/onyx/connectors/registry.py |
Modified | Registered JiraServiceManagementConnector in CONNECTOR_CLASS_MAP |
backend/onyx/connectors/jira_service_management/__init__.py |
New | Package init |
backend/onyx/connectors/jira_service_management/connector.py |
New | 45-line connector inheriting JiraConnector |
Backend — EE Permission Sync (3 files)
| File | Action | Purpose |
|---|---|---|
backend/ee/onyx/external_permissions/jira_service_management/__init__.py |
New | Package init |
backend/ee/onyx/external_permissions/jira_service_management/doc_sync.py |
New | JSM-specific doc sync using JiraServiceManagementConnector and DocumentSource.JIRA_SERVICE_MANAGEMENT |
backend/ee/onyx/external_permissions/sync_params.py |
Modified | Registered JSM in _SOURCE_TO_SYNC_CONFIG with dedicated doc sync and reused Jira group sync |
Frontend (4 files)
| File | Action | Purpose |
|---|---|---|
web/src/lib/types.ts |
Modified | Added JiraServiceManagement to ValidSources and validAutoSyncSources |
web/src/lib/sources.ts |
Modified | Added source metadata (icon, display name, category) |
web/src/lib/connectors/connectors.tsx |
Modified | Added connector config UI (base URL, scoped token, indexing scope tabs, email blacklist) |
web/src/lib/connectors/credentials.ts |
Modified | Added credential interface and default values |
A dedicated jira_service_management_doc_sync function was required because jira_doc_sync hardcodes DocumentSource.JIRA and JiraConnector. Without a separate function, the DB lookup during permission sync would search for documents with source JIRA instead of JIRA_SERVICE_MANAGEMENT, resulting in zero matches.
jira_group_sync is safely reused for JSM because it only enumerates Jira groups and does not reference a specific DocumentSource. Both JSM and Jira share the same Atlassian group model.
Resolved (confirmed by Greptile 4/5 + Cubic):
access.py dead code — Removed entirely; permissions inherited from parentJiraServiceManagementConfig field mismatch — Fixed to jira_base_url + added scoped_tokensync_params.py misplaced — Moved JSM entry into the canonical sync_params.py_SOURCE_TO_SYNC_CONFIG missing JSM — Added with dedicated jira_service_management_doc_syncNon-blocking notes from reviewers (no action required):
StopIteration pattern — Greptile confirmed “existing code is already doing this correctly”| PR | Lines | Core issue | This PR |
|---|---|---|---|
| #9121 (+1,484) | Near-verbatim copy | None project_key bug, dead code |
✅ Zero duplication |
| #8557 (+211) | Wrong return type | access.py returns list[str] |
✅ Correct ExternalAccess | None |
| #7877 (+6,256) | Non-production files | .coverage, placeholder assert True tests |
✅ Zero non-production files |
| #7008 (+854/-1,470) | Empty files | Confidence score: 0/5 | ✅ All files populated |
| #3087 (+413) | Stale | Closed after 90 days | ✅ Clean, review-ready |
The connector inherits all indexing logic from JiraConnector, which is already covered by the existing Jira test suite. The JSM connector only re-tags the document source.
ast.parse() on all modified .py filessync_params.py (verified by Greptile 4/5)starmovie12
@starmovie12
Onyx (YC W24)
@onyx-dot-app