Skip to content

feat(jira): route API client through effective host for scoped tokens#1489

Merged
aaight merged 1 commit into
devfrom
feat/jira-client-effective-host
Jul 10, 2026
Merged

feat(jira): route API client through effective host for scoped tokens#1489
aaight merged 1 commit into
devfrom
feat/jira-client-effective-host

Conversation

@aaight

@aaight aaight commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Routes the jira.js Version3Client through the effective REST v3 host so scoped API tokens reach the Atlassian gateway, while leaving classic (basic) site-token behavior unchanged.

Implements MNG-1738: https://linear.app/mongrel/issue/MNG-1738/as-a-developer-i-want-the-jira-api-client-to-route-requests-through

Depends on (both already merged): MNG-1736 (JiraCredentials.authType) and MNG-1737 (resolveJiraApiBaseUrl).

What changed

src/jira/client.ts

  • Replaced the synchronous, hard-coded getClient() (host: creds.baseUrl) with an async getClientForRequest() that sets host to await resolveJiraApiBaseUrl(creds).
    • basic / absent authType → tenant site URL (default behavior, unchanged).
    • authType === 'scoped' → Atlassian gateway https://api.atlassian.com/ex/jira/{cloudId}.
  • Updated all 22 jiraClient.* methods to await getClientForRequest().
  • Auth block stays authentication.basic (email / apiToken) for both modes — the MNG-1735 research note confirmed scoped API tokens authenticate via HTTP Basic against the gateway and Bearer did not authenticate as the user. authType selects the host, not the scheme. JSDoc documents the localized oauth2.accessToken fallback path should a future spike require it.
  • getCloudId() is left on the site URL (${creds.baseUrl}/_edge/tenant_info) regardless of authType — it is how we discover the cloudId that scoped requests route through. Reinforced with a JSDoc invariant note.
  • downloadAttachment() is left as-is — attachment content URLs are absolute site URLs, so they are intentionally not routed through the gateway. Added an explanatory comment.
  • addCommentReaction() degrades quietly under scoped auth: the internal /rest/reactions/1.0/ API is not exposed through the scoped gateway, so under authType === 'scoped' it logs one line (JIRA reactions are unavailable under scoped API tokens; skipping comment reaction) and returns — it never fails the run. Basic / absent auth keeps the existing site-URL behavior (and the existing throw-on-non-OK test stays green).

tests/unit/jira/client.test.ts

  • New effective host routing describe block:
    • basic / absent authTypeVersion3Client constructed with the site host + Basic auth, no network call.
    • scoped authTypeVersion3Client constructed with the Atlassian gateway host + Basic auth (covering getIssue, updateIssue, createIssue), with cloudId discovered from the site /_edge/tenant_info endpoint.
  • New getCloudId site-host invariant block: still hits the site /_edge/tenant_info under scoped auth.
  • New addCommentReaction scoped degradation block: skips quietly (no fetch, no throw) and logs under scoped auth.
  • All pre-existing basic-mode assertions remain green.

Testing

  • npx vitest run --project unit-core tests/unit/jira/client.test.ts63 passed
  • Full JIRA + PM-JIRA suites (tests/unit/jira/, tests/unit/pm/jira/) → 277 passed
  • PM conformance harness + download-and-preparepassed
  • npx tsc --noEmit → clean
  • biome check on changed files → clean

Out of scope

Router ack-comment routing and dashboard webhook-management routing (separate stories).

🤖 Generated with Claude Code

🕵️ claude-code · claude-opus-4-8 · run details

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/jira/client.ts 85.71% 5 Missing ⚠️

📢 Thoughts on this report? Let us know!

@nhopeatall nhopeatall left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

APPROVE — clean, well-scoped change that routes the jira.js client through the effective REST v3 host for scoped tokens while leaving classic basic-auth behavior byte-for-byte unchanged. Verified against all 7 work-item acceptance criteria; 63/63 tests pass locally and 7/7 CI checks are green.

Verification performed

  • Complete method coverage: the private getClient() is fully removed and all 22 jiraClient.* methods now await getClientForRequest(). Confirmed there is exactly one new Version3Client(...) construction in src/, so every JIRA REST v3 call — including the wizard discovery path via jiraClient.searchProjects()/getFields() — funnels through the new routing.
  • Scoped path is reachable, not dormant: authType flows from config at the runtime call site src/pm/jira/integration.ts:71 (withJiraCredentials({ email, apiToken, baseUrl, authType: jiraConfig?.authType }, fn)), so a project configured with authType: 'scoped' actually exercises the gateway branch.
  • Default behavior unchanged: for basic/absent auth, resolveJiraApiBaseUrl returns creds.baseUrl with no network call — the "no fetch" test assertions confirm this.
  • Invariants hold: getCloudId() stays on the site /_edge/tenant_info URL, downloadAttachment() stays on absolute site URLs, and addCommentReaction degrades quietly (log + return) under scoped auth without ever failing the run.
  • Circular import (client.tsapi-host.ts) is benign — both cross-references run only inside function bodies at call time, never at module init, so no temporal-dead-zone risk.
  • Test hygiene: the new blocks correctly precede the downloadAttachment block (the only one calling vi.restoreAllMocks()), preserving the Version3Client mock implementation. The constraint is documented in-code.

Auth-scheme decision (HTTP Basic for both modes) is soundly backed by the documented MNG-1735 live probes on the work item. No blocking or should-fix issues found.

🕵️ claude-code · claude-opus-4-8 · run details

@aaight aaight merged commit a0197ce into dev Jul 10, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants