Skip to content

Commit f0df859

Browse files
Fix analytics-review on workflow_dispatch: pass resolved PR context to the agent (#152)
* Fix analytics-review on workflow_dispatch: pass resolved PR context to the agent Dry-run 32015295640 (PR #146) went green end-to-end after the v0.86.2 recompile, but the agent posted nothing: the resolve pre-step's AW_PR_NUMBER/AW_HEAD_REF land in step env only, which never reaches the agent sandbox, and on workflow_dispatch the event payload has no PR object. The agent concluded "no associated pull request ... nothing to review" and noop'd. Fix 1: the resolve step (now id: resolve_pr) also writes step outputs and /tmp/gh-aw/context/run-context.md — the context dir is the one channel proven to reach the agent (it read jira-ticket.md in the same run). The prompt body names run-context.md as the source of truth for PR identity, treats a dispatch run with a resolved PR as a normal review, and reserves noop for runs where no PR resolves at all. (${{ steps.* }} interpolation into the body cannot work: the prompt is rendered in the activation job, the steps run in the agent job.) Fix 2: the same run showed "JIRA returned HTTP 404 for ENG-909" — ambiguous, since JIRA answers 404 for missing ticket, missing project permission, AND bad credentials. On any non-200 the step now probes /rest/api/3/myself and writes an auth diagnosis into the marker (credentials rejected vs authenticated-but-cannot-see vs unreachable), reporting HTTP codes only, never credential values. Still never fails the job. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * JIRA step: support scoped Atlassian tokens (accessible-resources probe + auto-recovery) Root cause of the ENG-909 404: JIRA_API_TOKEN is a scoped Atlassian API token, and scoped tokens must target https://api.atlassian.com/ex/jira/<cloudId> instead of https://<site>.atlassian.net. Atlassian answers 404 (not 403) when a scoped token hits the site-host form, which mimics a missing issue. - Replace the /rest/api/3/myself probe (not callable with granular read:issue scopes -> would false-report valid credentials as broken) with GET https://api.atlassian.com/oauth/token/accessible-resources, which works for both token types and returns each site's cloudId. - Auto-recovery: when the issue fetch fails and the probe can resolve a cloudId (configured URL matches a site, cloudId embedded in an ex/jira URL, or single-site token), retry via the scoped-token endpoint - so either token type works with either JIRA_BASE_URL form. - Self-diagnosing markers on hard failure: credentials rejected (401/403, mentions <=365-day scoped-token expiry), base URL matches none of the token's sites (lists reachable site URLs + cloudIds and the exact value to set), ticket not visible/nonexistent (tried both endpoints), or api.atlassian.com unreachable. HTTP codes, site URLs and cloudIds only; never credential values. - Comments fetch now uses the possibly-recovered base URL. - README: JIRA_BASE_URL form guidance per token type. - New helper .github/scripts/jira_sites.py (cloud-id resolution + site summary; always exits 0). All six failure/recovery branches exercised locally against a mock Atlassian server using the step script extracted verbatim from the workflow; every path exits 0 and writes the marker. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 8ce12f2 commit f0df859

4 files changed

Lines changed: 180 additions & 15 deletions

File tree

.github/scripts/jira_sites.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env python3
2+
"""Helpers for diagnosing JIRA API access in the analytics-review workflow.
3+
4+
Parses the JSON that `GET https://api.atlassian.com/oauth/token/accessible-resources`
5+
returns (the list of Atlassian sites a credential can reach) and answers two
6+
questions for the workflow's JIRA pre-step:
7+
8+
jira_sites.py cloud-id <resources.json> <configured-base-url>
9+
Print the cloudId to use with the scoped-token endpoint
10+
(https://api.atlassian.com/ex/jira/<cloudId>), chosen as: the site
11+
whose `url` equals the configured base URL, else the cloudId already
12+
embedded in an .../ex/jira/<id> base, else the only site when exactly
13+
one is accessible. Prints nothing when no confident answer exists.
14+
15+
jira_sites.py summary <resources.json>
16+
Print a one-line "url (cloudId ...)" list for diagnostics.
17+
18+
Site URLs and cloudIds are not credentials (cloudIds appear in every browser
19+
request to a JIRA site); nothing secret is ever read or printed here. Exit
20+
code is always 0 — this feeds a diagnostics path that must never fail the job.
21+
"""
22+
23+
import json
24+
import sys
25+
26+
27+
def load_sites(path):
28+
try:
29+
with open(path) as fh:
30+
data = json.load(fh)
31+
except Exception:
32+
return []
33+
return [s for s in data if isinstance(s, dict)] if isinstance(data, list) else []
34+
35+
36+
def main():
37+
if len(sys.argv) < 3:
38+
return
39+
mode, path = sys.argv[1], sys.argv[2]
40+
sites = load_sites(path)
41+
if mode == "summary":
42+
line = "; ".join(
43+
"%s (cloudId %s)" % (s.get("url", "?"), s.get("id", "?")) for s in sites
44+
)
45+
print(line or "no sites accessible to this token")
46+
elif mode == "cloud-id":
47+
base = (sys.argv[3] if len(sys.argv) > 3 else "").rstrip("/")
48+
match = [s for s in sites if str(s.get("url", "")).rstrip("/") == base]
49+
if not match and "/ex/jira/" in base:
50+
cid = base.split("/ex/jira/", 1)[1].split("/")[0]
51+
match = [s for s in sites if s.get("id") == cid]
52+
if not match and len(sites) == 1:
53+
match = sites
54+
if match:
55+
print(match[0].get("id", ""))
56+
57+
58+
if __name__ == "__main__":
59+
main()

.github/workflows/analytics-review.lock.yml

Lines changed: 5 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)