From 593f8c60b82c43bbb31672eb073b3e57abc26f63 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:47:38 -0400 Subject: [PATCH] fix(security-review): resolve Confluence cloudId via accessible-resources, not /_edge/tenant_info (#41) The public /_edge/tenant_info endpoint returns an HTML 'Page Unavailable' on the seahavenind site, so cloudId auto-resolution failed. Fetch the token first, then resolve cloudId from the OAuth-native https://api.atlassian.com/oauth/token/ accessible-resources (Bearer), preferring the resource whose url matches the configured site, else the first. CONFLUENCE_CLOUD_ID override still honored. Canary 3/3 (offline), shellcheck clean. --- security-review/checkers/confluence-doc.sh | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/security-review/checkers/confluence-doc.sh b/security-review/checkers/confluence-doc.sh index 35107dc..ca945dc 100755 --- a/security-review/checkers/confluence-doc.sh +++ b/security-review/checkers/confluence-doc.sh @@ -221,15 +221,8 @@ _CONF_MODE=""; _CONF_BASE=""; _CONF_BEARER="" conf_api_init() { if [ -n "$CONFLUENCE_OAUTH_CLIENT_ID" ] && [ -n "$CONFLUENCE_OAUTH_CLIENT_SECRET" ]; then - local cid="$CONFLUENCE_CLOUD_ID" - if [ -z "$cid" ] && [ -n "$CONFLUENCE_BASE_URL" ]; then - cid="$(curl -sS -H 'Accept: application/json' \ - "$CONFLUENCE_BASE_URL/_edge/tenant_info" 2>>"$REPORT_DIR/confluence-api.log" \ - | jq -r '.cloudId // empty' 2>/dev/null)" - fi - [ -n "$cid" ] || { log "OAuth: could not resolve cloudId — skipping API"; return 1; } - # 2LO client-credentials token. The secret goes in the request BODY via - # --data-urlencode and is never echoed/logged (matches the existing -u risk class). + # 2LO client-credentials token FIRST (the secret goes in the request BODY via + # --data-urlencode and is never echoed/logged — matches the existing -u risk class). local tok tok="$(curl -sS -X POST "$CONFLUENCE_OAUTH_TOKEN_URL" \ -H 'Content-Type: application/x-www-form-urlencoded' \ @@ -238,6 +231,18 @@ conf_api_init() { --data-urlencode 'grant_type=client_credentials' \ 2>>"$REPORT_DIR/confluence-api.log" | jq -r '.access_token // empty' 2>/dev/null)" [ -n "$tok" ] || { log "OAuth: token request failed — skipping API (no false alarm)"; return 1; } + # Resolve the cloudId: use CONFLUENCE_CLOUD_ID if given, else the OAuth-native + # accessible-resources endpoint (the public /_edge/tenant_info is not reliable). + # Prefer the resource whose url matches the configured site; else the first. + local cid="$CONFLUENCE_CLOUD_ID" + if [ -z "$cid" ]; then + cid="$(curl -sS -H "Authorization: Bearer $tok" -H 'Accept: application/json' \ + 'https://api.atlassian.com/oauth/token/accessible-resources' \ + 2>>"$REPORT_DIR/confluence-api.log" \ + | jq -r --arg url "$CONFLUENCE_BASE_URL" \ + '(map(select(.url==$url)) | .[0].id) // .[0].id // empty' 2>/dev/null)" + fi + [ -n "$cid" ] || { log "OAuth: could not resolve cloudId (set CONFLUENCE_CLOUD_ID) — skipping API"; return 1; } _CONF_MODE="oauth"; _CONF_BEARER="$tok" _CONF_BASE="https://api.atlassian.com/ex/confluence/$cid" return 0