Skip to content

Commit 27460f8

Browse files
authored
fix(atlassian): harden cloud ID resolution for Confluence and Jira (#3853)
1 parent c764319 commit 27460f8

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

apps/sim/tools/confluence/utils.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import type { RetryOptions } from '@/lib/knowledge/documents/utils'
22
import { fetchWithRetry } from '@/lib/knowledge/documents/utils'
33

4+
function normalizeDomain(domain: string): string {
5+
return `https://${domain
6+
.trim()
7+
.replace(/^https?:\/\//i, '')
8+
.replace(/\/+$/, '')}`.toLowerCase()
9+
}
10+
411
export async function getConfluenceCloudId(
512
domain: string,
613
accessToken: string,
@@ -20,20 +27,27 @@ export async function getConfluenceCloudId(
2027

2128
const resources = await response.json()
2229

23-
if (Array.isArray(resources) && resources.length > 0) {
24-
const normalizedInput = `https://${domain}`.toLowerCase()
25-
const matchedResource = resources.find((r) => r.url.toLowerCase() === normalizedInput)
30+
if (!Array.isArray(resources) || resources.length === 0) {
31+
throw new Error('No Confluence resources found')
32+
}
33+
34+
const normalized = normalizeDomain(domain)
35+
const match = resources.find(
36+
(r: { url: string }) => r.url.toLowerCase().replace(/\/+$/, '') === normalized
37+
)
2638

27-
if (matchedResource) {
28-
return matchedResource.id
29-
}
39+
if (match) {
40+
return match.id
3041
}
3142

32-
if (Array.isArray(resources) && resources.length > 0) {
43+
if (resources.length === 1) {
3344
return resources[0].id
3445
}
3546

36-
throw new Error('No Confluence resources found')
47+
throw new Error(
48+
`Could not match Confluence domain "${domain}" to any accessible resource. ` +
49+
`Available sites: ${resources.map((r: { url: string }) => r.url).join(', ')}`
50+
)
3751
}
3852

3953
function decodeHtmlEntities(text: string): string {

apps/sim/tools/jira/utils.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ export async function downloadJiraAttachments(
9797
return downloaded
9898
}
9999

100+
function normalizeDomain(domain: string): string {
101+
return `https://${domain
102+
.trim()
103+
.replace(/^https?:\/\//i, '')
104+
.replace(/\/+$/, '')}`.toLowerCase()
105+
}
106+
100107
export async function getJiraCloudId(domain: string, accessToken: string): Promise<string> {
101108
const response = await fetchWithRetry(
102109
'https://api.atlassian.com/oauth/token/accessible-resources',
@@ -116,18 +123,25 @@ export async function getJiraCloudId(domain: string, accessToken: string): Promi
116123

117124
const resources = await response.json()
118125

119-
if (Array.isArray(resources) && resources.length > 0) {
120-
const normalizedInput = `https://${domain}`.toLowerCase()
121-
const matchedResource = resources.find((r) => r.url.toLowerCase() === normalizedInput)
126+
if (!Array.isArray(resources) || resources.length === 0) {
127+
throw new Error('No Jira resources found')
128+
}
122129

123-
if (matchedResource) {
124-
return matchedResource.id
125-
}
130+
const normalized = normalizeDomain(domain)
131+
const match = resources.find(
132+
(r: { url: string }) => r.url.toLowerCase().replace(/\/+$/, '') === normalized
133+
)
134+
135+
if (match) {
136+
return match.id
126137
}
127138

128-
if (Array.isArray(resources) && resources.length > 0) {
139+
if (resources.length === 1) {
129140
return resources[0].id
130141
}
131142

132-
throw new Error('No Jira resources found')
143+
throw new Error(
144+
`Could not match Jira domain "${domain}" to any accessible resource. ` +
145+
`Available sites: ${resources.map((r: { url: string }) => r.url).join(', ')}`
146+
)
133147
}

0 commit comments

Comments
 (0)