feat: Jira Cloud integration (connection, inbound webhook, pull-sync + settings UI)#5919
Open
zerox9dev wants to merge 15 commits into
Open
feat: Jira Cloud integration (connection, inbound webhook, pull-sync + settings UI)#5919zerox9dev wants to merge 15 commits into
zerox9dev wants to merge 15 commits into
Conversation
Tables for workspace-scoped Jira connections (API-token auth, secrets stored as secretbox ciphertext) and Jira->Multica issue links. No FKs or cascades per migration rules; cleanup happens in application code. Concurrent secondary indexes live in single-statement migrations 225-227.
CRUD/upsert queries for jira_connection and jira_issue_link mirroring vcs.sql, plus a narrow SyncIssueFromJira title/description update used by the inbound webhook. Generated with sqlc v1.31.1.
Webhook secret verification (constant-time shared secret via header or query param, since Jira webhooks carry no native signature), normalized jira:issue_created / jira:issue_updated parsing with assignee-change detection and ADF description flattening, and a minimal REST client (myself + issue fetch) behind a Client seam handlers can mock.
Extends the issue_origin_type_check constraint (pattern of migrations 060/111/131/149) so the inbound Jira webhook can stamp mirrored issues with origin_type='jira' + origin_id=<jira_connection.id>.
Mirrors the VCS integration shape:
- handler/jira.go: workspace-scoped connection list/connect/get/delete;
credentials validated live via the jira.Client seam, API token and
minted webhook secret stored as MULTICA_JIRA_SECRET_KEY secretbox
ciphertext, one-time plaintext webhook secret returned at connect.
- handler/jira_webhook.go: POST /api/webhooks/jira/{connectionId} with
10MiB body cap, refuse-if-unconfigured, constant-time per-connection
secret verification, and create-or-sync of the mirrored Multica issue
(IssueService.Create on first delivery, narrow title/description sync
after; thin payloads enriched via the REST client).
- router.go: public webhook route, member-visible reads, admin-gated
connect/disconnect, and the MULTICA_JIRA_SECRET_KEY secretbox wiring.
- DB-backed webhook tests with a mocked Jira client (no real network).
SearchIssues pages GET /rest/api/2/search until the caller's maxResults (hard-capped at 100) and returns the same minimal Issue shape the webhook enrichment path uses, plus the assignee identity. 400 responses map to a new ErrBadRequest so a bad JQL surfaces as a user-fixable error. Powers the pull-based sync for accounts that cannot register Jira webhooks.
Migration 229 adds a nullable jql column to jira_connection (no FK, no index). UpsertJiraConnection persists it, the connect endpoint accepts an optional jql field, and connection responses expose it so the settings UI can show what a sync will pull. Empty means the pull path's default 'assignee = currentUser()'.
…sync path
syncJiraIssue now returns a created/updated/skipped outcome so it serves
as the single per-issue mirror path for both the webhook and the new
POST /workspaces/{id}/jira/connections/{connectionId}/sync endpoint. The
endpoint searches the site with the connection's stored JQL (default
'assignee = currentUser()'), mirrors up to 100 results, and returns a
{created, updated, total} summary. Admin-gated like the other Jira
mutations; lets users without Jira admin rights import their issues
without registering a webhook.
Each connection card gets a Sync now button that hits the pull-based sync
endpoint, spins while in flight, toasts the {created, updated} summary and
invalidates the workspace issue queries so pulled issues appear at once.
The connect form gains an optional JQL field (default shown as the
placeholder). Strings added to en, zh-Hans, ko and ja.
… Cloud) Jira Cloud removed the offset-based /rest/api/2/search endpoint; switch SearchIssues to the enhanced JQL endpoint /rest/api/3/search/jql with nextPageToken cursor pagination. Fixes 502 on manual sync against real Jira Cloud sites.
|
@zerox9dev is attempting to deploy a commit to the IndexLabs Team on Vercel. A member of the Team first needs to authorize it. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #1634.
Summary
Adds Jira Cloud integration so issues assigned in Jira surface as Multica issues. Built on the existing VCS-integration pattern (per-workspace, API-token auth, secretbox-encrypted secrets — no Atlassian OAuth app required, works for self-hosters out of the box).
Two ingest paths, so it works whether or not you have Jira admin rights:
assignee = currentUser()) fetches issues via the Jira REST API and creates/syncs them. No webhook, no tunnel, no site-admin.POST /api/webhooks/jira/{connectionId}verified by a per-connection secret (Jira Cloud doesn't sign webhooks) creates/syncs onjira:issue_created/jira:issue_updated.What's included
CREATE INDEX CONCURRENTLYone-per-file):jira_connection(incl. optionaljql) +jira_issue_link.POST .../jira/connections/{id}/sync→{created, updated, total}), Jira REST client using the enhanced/rest/api/3/search/jql(the offset-based/rest/api/2/searchwas removed on Cloud). Webhook and pull share one create-or-sync function.jirastrings inen,zh-Hans,ko,ja.Auth model — steer welcome
v1 uses a per-workspace Jira Cloud API token (email + API token + base URL, encrypted). Atlassian Connect / OAuth (3LO) would be cleaner but needs a hosted Atlassian app; I'd add it later rather than block this. Happy to adjust.
Not in this PR (follow-ups)
Verification
go build/vetclean; Jira client + handler tests pass (DB-backed).pnpm typecheck6/6; locale parity + Jira tab tests pass.